Natas Level 12 → Level 13

Once login, we are able to upload a JPEG file. From the source code, we see that there are three functions within the main program and a form.

function genRandomString() { 
 $length = 10; 
 $characters = "0123456789abcdefghijklmnopqrstuvwxyz"; 
 $string = ""; 

 for ($p = 0; $p < $length; $p++) { 
 $string .= $characters[mt_rand(0, strlen($characters)-1)]; 
 return $string; 

function makeRandomPath($dir, $ext) { 
 do { 
 $path = $dir."/".genRandomString().".".$ext; 
 } while(file_exists($path)); 
 return $path; 

function makeRandomPathFromFilename($dir, $fn) { 
 $ext = pathinfo($fn, PATHINFO_EXTENSION); 
 return makeRandomPath($dir, $ext); 

if(array_key_exists("filename", $_POST)) { 
 $target_path = makeRandomPathFromFilename("upload", $_POST["filename"]); 

 if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) { 
 echo "File is too big"; 
 } else { 
 if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) { 
 echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded"; 
 } else{ 
 echo "There was an error uploading the file, please try again!"; 
} else { 

<form enctype="multipart/form-data" action="index.php" method="POST"> 
<input type="hidden" name="MAX_FILE_SIZE" value="1000" /> 
<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" /> 
Choose a JPEG to upload (max 1KB):<br/> 
<input name="uploadedfile" type="file" /><br /> 
<input type="submit" value="Upload File" /> 
<? } ?>

The first function, getRandomString() return a string of 10 random characters from 0-9a-z.

The second function, makeRandomPath() takes a directory, $dir and an extension, $ext to create a $path using getRandomString(). Notice the extension in here is not modified.

The third function, makeRandomPathFromFilename() takes a directory, $dir and a filename $fn, create an extension, $ext and return the result of makeRandomPath() using the same $dir and $ext. The call to pathinfo returns information about a file path, in this case the entension of $fn.

The main program check If the filename exist in the upload, if so, then the $target_path is set to upload/filename.ext. It also check for filesize and make sure the upload is successful.

The form hidden field put constraint on MAX_FILE_SIZE, set the filename to getRandomString() with an .jpg extension. In fact, if we view source, we can see (in this case) the pre-determined filename for my upload will be 3zpebzm4p1.jpg. We can also access this file later.

The goal here is to upload some file that we can execute when we access it later. But because the form changes the filename to take a jpg extension, we also need to intercept the form, change the filename back to other file extension (e.g. php) and then send it to the server. So let code a simple php that will review the password. We can use the passthru() in PHP to execute a command. We’ll use the following as our upload file:

  echo passthru("cat /etc/natas_webpass/natas13");

We will upload our file (natas12.php) but intercept the outgoing message with burp. Notice, the filename extension has changed to .jpg when we intercepted it. We changed it back to .php before forwarding the message to the server.

Content-Disposition: form-data; name="filename"
3zpebzm4p1.jpg php

As expected, the message return contain the correct filename extension. Clicking on the link will execute the php code and the next password is shown as plaintext.


Other php commands that also give similar result: readfile() and file_get_contents().

Additional Resource: