<?phpini_set('display_errors','Off');$target_dir ="tmp/";$filename =explode('.', basename($_FILES['fileToUpload']['name']));$target_file = $target_dir .md5($filename[0] . time()).'.'.$filename[1];if ($_FILES["fileToUpload"]["size"] >800000){header("/index.php");exit();}#cleanup$filecount =count(glob('tmp/'."*"));if ($filecount >=19 ) {exec('rm -rf tmp/*');}move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);#Método novo para verificação de arquivos maliciososexec('exiftool --ext php '. $target_file, $output, $retval);if ($retval ==1) {unlink($target_file);print_r("Tentativa de invasão detectada!!");} else {exec('mv '. $target_file .' tmp');print_r("Sua foto foi devidamente armazenada no nosso servidor!");}?>
Vulnerable point
We can view below that verification of malicious file upload is made using ExifTool to check file extension. But the raw variable target_file is concatenated with a string in exec() function, resulting in a blind command injection.
$filename =explode('.', basename($_FILES['fileToUpload']['name']));$target_file = $target_dir .md5($filename[0] . time()).'.'.$filename[1];[...]#Método novo para verificação de arquivos maliciososexec('exiftool --ext php '. $target_file, $output, $retval);
As you can see in the code snippet, to understand the injection point and the payload were be used is generated in 4 steps:
$target_dir: constant variable with the value /tmp
$filename: array of strings generated using explode function, that split the name of the file uploaded by dot. So, position
$filename[0]: filename, (string before the dot)
$filename[1]: extension (string after the dot)
md5($filename[0] + timestamp): md5 hash of the name of file + timestamp
$target_file: concatenation of two variables explained plus $filename[1], that is the injection point.
The exec() is a built-in function in PHP to execute OS commands, manipulating the extension of the file we can inject a command before the ExifTool command.
Exploitation
To execute another command at the same function call we can put a || to start a payload. This operator acts like a or condition in bash, so if the first command returns a 0 (False) the second command will be executed.
PoC
Injecting the payload before we can confirm that the POC is working because the server is wait 5 seconds to respond.
||sleep 5
The result in the code is the following:
exiftool --ext php ||sleep 5
To retrieve the flag we can get the content /flag and put it in the server directory, to simply GET the file using the website. To do that I used this final payload: