22: WEB vulnerability - file upload content logical array bypass and parsing vulnerability

Knowledge points

  • File header detection
  • Image file information judgment
  • Logical security - Secondary rendering
  • Logical security - conditional competition
  • Directory naming - x.php /
  • Script function vulnerability-CVE-2015-2348
  • Array acceptance + directory naming

Key points of this lesson:

  • Uploadlabs-pass13-20 level test
    • Case 1: Pass-13 header detection image
    • Case 2: Pass-14 getimagesize() image file information judgment
    • Case 3: Pass-15 exif_imagetype() image file information judgment image
    • Case 4: Pass-16 secondary rendering bypass
    • Case 5: Pass-17 conditional competition: upload first and then verify
    • Case 6: Pass-18 conditional competition: upload first and then verify
    • Case 7: Pass-19 00 truncation (CVE-2015-2348) directory naming - x.php /
    • Case 8: Pass-20 array acceptance + directory naming
  • CVE-2017=12615 upload tomcat
    • Case 9: Tomcat PUT method arbitrary file writing vulnerability (CVE-2017-12615)
  • Middleware parsing vulnerability + cooperate with file upload test
    • Case 10: IIS upload parse - (penfei806)
    • Case 11: Nginx upload parse vulhub
    • Case 12: Apache upload parse vulhub

Case 1: Pass-13 picture horse bypass

Source code

function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //Read only 2 bytes
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    
    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
    $fileType = '';    
    switch($typeCode){      
        case 255216:            
            $fileType = 'jpg';
            break;
        case 13780:            
            $fileType = 'png';
            break;        
        case 7173:            
            $fileType = 'gif';
            break;
        default:            
            $fileType = 'unknown';
        }    
        return $fileType;
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $file_type = getReailFileType($temp_file);

    if($file_type == 'unknown'){
        $msg = "Unknown file, upload failed!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "Upload error!";
        }
    }
}

Judge the file type by reading the first two bytes of the file, so you can upload the picture directly.

Make picture horse:

copy 1.png /b + shell.php /a webshell.png

You can also add a sentence directly after the picture:

Direct access to images cannot be parsed as PHP, so File Inclusion vulnerabilities need to be exploited

##include.php
<?php
/*
This page contains a file vulnerability, which is used to test whether the picture horse can run normally!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
    include $file;
}else{
    show_source(__file__);
}
?>

Trojan successfully executed

Case 2: Pass-14 getimagesize() picture horse

Source code

function isImage($filename){
    $types = '.jpeg|.png|.gif';
    if(file_exists($filename)){
        $info = getimagesize($filename);
        $ext = image_type_to_extension($info[2]);
        if(stripos($types,$ext)>=0){
            return $ext;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "Unknown file, upload failed!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "Upload error!";
        }
    }
}

Here, use the getimagesize function to read the file header to determine the file type, or you can bypass the image horse. The method is the same as pass-13. Upload the picture horse, the cooperation file contains vulnerabilities, and successfully execute the Trojan horse.

Case 3: Pass-15 exif_imagetype() picture horse

Source code

function isImage($filename){
    //PHP needs to be turned on_ EXIF module
    $image_type = exif_imagetype($filename);
    switch ($image_type) {
        case IMAGETYPE_GIF:
            return "gif";
            break;
        case IMAGETYPE_JPEG:
            return "jpg";
            break;
        case IMAGETYPE_PNG:
            return "png";
            break;    
        default:
            return false;
            break;
    }
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "Unknown file, upload failed!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "Upload error!";
        }
    }
}

Use EXIF here_ The imagetype function reads the first byte of an image and checks its signature, or it can be bypassed. The method is the same as pass-13. Upload the picture horse, the cooperation file contains vulnerabilities, and successfully execute the Trojan horse.

Case 4: Pass-16 secondary rendering bypass

Source code

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // Get the basic information of the uploaded file, file name, type, size and temporary file path
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=UPLOAD_PATH.'/'.basename($filename);

    // Gets the extension of the uploaded file
    $fileext= substr(strrchr($filename,"."),1);

    //Judge the file suffix and type, and upload only if it is legal
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){
        if(move_uploaded_file($tmpname,$target_path)){
            //Use the uploaded image to generate a new image
            $im = imagecreatefromjpeg($target_path);

            if($im == false){
                $msg = "The file is not jpg Format picture!";
                @unlink($target_path);
            }else{
                //Assign a file name to the new picture
                srand(time());
                $newfilename = strval(rand()).".jpg";
                //Display the image after secondary rendering (new image generated using the image uploaded by the user)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);
                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "Upload error!";
        }

    }else if(($fileext == "png") && ($filetype=="image/png")){
        if(move_uploaded_file($tmpname,$target_path)){
            //Use the uploaded image to generate a new image
            $im = imagecreatefrompng($target_path);

            if($im == false){
                $msg = "The file is not png Format picture!";
                @unlink($target_path);
            }else{
                 //Assign a file name to the new picture
                srand(time());
                $newfilename = strval(rand()).".png";
                //Display the image after secondary rendering (new image generated using the image uploaded by the user)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagepng($im,$img_path);

                @unlink($target_path);
                $is_upload = true;               
            }
        } else {
            $msg = "Upload error!";
        }

    }else if(($fileext == "gif") && ($filetype=="image/gif")){
        if(move_uploaded_file($tmpname,$target_path)){
            //Use the uploaded image to generate a new image
            $im = imagecreatefromgif($target_path);
            if($im == false){
                $msg = "The file is not gif Format picture!";
                @unlink($target_path);
            }else{
                //Assign a file name to the new picture
                srand(time());
                $newfilename = strval(rand()).".gif";
                //Display the image after secondary rendering (new image generated using the image uploaded by the user)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "Upload error!";
        }
    }else{
        $msg = "Only upload with suffix.jpg|.png|.gif My picture file!";
    }
}

Here, according to different file types, the functions magecreatefromjpeg(), imagecreatefrompng(), imagecreatefromgif() are used to render the picture twice.

Since the picture is divided into different data blocks, we only need to find a way to write the Trojan horse into the data block that will not change during secondary rendering, and then we can successfully upload the picture horse. After uploading successfully, we need to cooperate with the file to contain vulnerabilities in order to successfully execute the Trojan horse.

For specific methods, refer to: https://xz.aliyun.com/t/2657

In fact, Pass-14, Pass-15 and Pass-16 ensure that all uploaded image files are picture files. Under normal circumstances, there is no upload vulnerability. Here, the Trojan horse will be executed only if the file contains vulnerabilities.

Case 5: Pass-17 conditional competition

Source code

$is_upload = false;
$msg = null;

if(isset($_POST['submit'])){
    $ext_arr = array('jpg','png','gif');
    $file_name = $_FILES['upload_file']['name'];
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $file_ext = substr($file_name,strrpos($file_name,".")+1);
    $upload_file = UPLOAD_PATH . '/' . $file_name;

    if(move_uploaded_file($temp_file, $upload_file)){
        if(in_array($file_ext,$ext_arr)){
             $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
             rename($upload_file, $img_path);
             $is_upload = true;
        }else{
            $msg = "Upload only.jpg|.png|.gif Type file!";
            unlink($upload_file);
        }
    }else{
        $msg = 'Upload error!';
    }
}

Here is conditional competition. First upload the file to the server (move_uploaded_file), and then judge whether the file suffix is in the white list. If so, rename it, otherwise delete it. Therefore, we can upload 1.php. We only need to access it before it is deleted. We can continuously upload it by using burp's introder module, and then we can continuously access and refresh the address.

Case 6: Pass-18 conditional competition

Source code

//index.php
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))
{
    require_once("./myupload.php");
    $imgFileName =time();
    $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
    $status_code = $u->upload(UPLOAD_PATH);
    switch ($status_code) {
        case 1:
            $is_upload = true;
            $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
            break;
        case 2:
            $msg = 'The file has been uploaded but not renamed.';
            break; 
        case -1:
            $msg = 'This file cannot be uploaded to the temporary file storage directory of the server.';
            break; 
        case -2:
            $msg = 'Upload failed. The upload directory is not writable.';
            break; 
        case -3:
            $msg = 'Upload failed. This type of file cannot be uploaded.';
            break; 
        case -4:
            $msg = 'Upload failed. The uploaded file is too large.';
            break; 
        case -5:
            $msg = 'Upload failed. A file with the same name already exists on the server.';
            break; 
        case -6:
            $msg = 'The file cannot be uploaded and cannot be copied to the target directory.';
            break;      
        default:
            $msg = 'Unknown error!';
            break;
    }
}

//myupload.php
class MyUpload{
......
......
...... 
  var $cls_arr_ext_accepted = array(
      ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
      ".html", ".xml", ".tiff", ".jpeg", ".png" );

......
......
......  
  /** upload()
   **
   ** Method to upload the file.
   ** This is the only method to call outside the class.
   ** @para String name of directory we upload to
   ** @returns void
  **/
  function upload( $dir ){
    
    $ret = $this->isUploadedFile();
    
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->setDir( $dir );
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->checkExtension();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->checkSize();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );    
    }
    
    // if flag to check if the file exists is set to 1
    
    if( $this->cls_file_exists == 1 ){
      
      $ret = $this->checkFileExists();
      if( $ret != 1 ){
        return $this->resultUpload( $ret );    
      }
    }

    // if we are here, we are ready to move the file to destination

    $ret = $this->move();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );    
    }

    // check if we need to rename the file

    if( $this->cls_rename_file == 1 ){
      $ret = $this->renameFile();
      if( $ret != 1 ){
        return $this->resultUpload( $ret );    
      }
    }
    
    // if we are here, everything worked as planned :)

    return $this->resultUpload( "SUCCESS" );
  
  }
......
......
...... 
};

Although multiple checks are performed on the file, such as judging the file suffix, checking the file size, whether the file exists, etc., like Pass-17, the file is first uploaded to the server (move_uploaded_file) and then verified. Therefore, there is also a problem of conditional competition. You can upload pictures continuously. Due to competition conditions, you may not have time to rename them, so the upload is successful.

Case 7: Pass-19 00 truncation CVE-2015-2348

Source code

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");

        $file_name = $_POST['save_name'];
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);

        if(!in_array($file_ext,$deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' .$file_name;
            if (move_uploaded_file($temp_file, $img_path)) { 
                $is_upload = true;
            }else{
                $msg = 'Upload error!';
            }
        }else{
            $msg = 'It is forbidden to save as this type of file!';
        }

    } else {
        $msg = UPLOAD_PATH . 'Folder does not exist,Please create it manually!';
    }
}

Move here_ uploaded_ IMG in file() function_ Path is saved by the post parameter_ Name, so you can save_name uses 00 truncation to bypass. The method is the same as pass-12. reference resources: https://www.secpulse.com/archives/5767.html

You can also use another idea, save_ Change the name value to "upload-19.php /.", bypass the blacklist, upload to the server and save it as upload-19.php.

Case 8: Pass-20 array acceptance + directory naming

Source code

if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {

        $is_upload = false;
        $msg = null;
        if(!empty($_FILES['upload_file'])){
            //mime check
            $allow_type = array('image/jpeg','image/png','image/gif');
            if(!in_array($_FILES['upload_file']['type'],$allow_type)){
                $msg = "Prohibit uploading this type of file!";
            }else{
                //check filename
				//Judge save_ Whether name is empty. If not, $file gets save_name value
                $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
                //Judge whether $file is an array. If not, break it up into an array
				if (!is_array($file)) {
                    $file = explode('.', strtolower($file));
                }
				
				//Take the value of the last element in the array as the suffix, and then verify the whitelist
                $ext = end($file);
                $allow_suffix = array('jpg','png','gif');
                if (!in_array($ext, $allow_suffix)) {
                    $msg = "Prohibit uploading this suffix file!";
                }else{
					//Rename the file name: take the value of the first element +. + the value of the last element in the array
                    $file_name = reset($file) . '.' . $file[count($file) - 1];
                    $temp_file = $_FILES['upload_file']['tmp_name'];
                    $img_path = UPLOAD_PATH . '/' .$file_name;
					//Upload file, img_path controllable
                    if (move_uploaded_file($temp_file, $img_path)) {
                        $msg = "File upload succeeded!";
                        $is_upload = true;
                    } else {
                        $msg = "File upload failed!";
                    }
                }
            }
        }else{
            $msg = "Please select the file to upload!";
        }
        
    } else {
        $msg = UPLOAD_PATH . 'Folder does not exist,Please create it manually!';
    }
}

Bypass method: array acceptance + directory naming

Case 9: Tomcat PUT method arbitrary file writing vulnerability (CVE-2017-12615)

First of all, the exploitation condition of CVE-2017-12615 vulnerability is Windows+Tomcat 7.0.x + configuration file readonly=false (non default configuration). The content of the configuration file is as follows:

<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>

Tomcat sets readonly to false and also enables the support of PUT request mode. This means that we can upload files. Can we upload any file? No, we first need to know the following two generals of Tomcat:

  • org.apache.jasper.servlet.JspServlet: it handles jsp and jspx file requests by default. There is no PUT upload logic and it cannot handle PUT requests
  • org.apache.catalina.servlets.DefaultServlet: static files (files other than jsp and jspx) are processed by default. PUT upload processing logic exists and PUT requests can be processed.

Therefore, even if we can PUT a file to the server, we can't directly PUT files ending in JSP and jspx, because these suffix files are handled by JspServlet, which can't handle PUT requests.

However, when we upload a file in the following two ways by using Windows features, tomcat does not think it is a jsp file, so it is handled by DefaultServlet to successfully create a jsp file, which is the so-called CVE-2017-12615 vulnerability.

evil.jsp%20
evil.jsp::$DATA

The above contents belong to CVE-2017-12615 vulnerability. In addition, when we upload files of type evil.jsp/ (i.e. ending with backslash), we will also successfully create JSP files, and this way extends the exploitation of PUT vulnerability to the Linux platform and all versions of Tomcat 5.x-9.x, but this is not the content of CVE-2017-12615.

Environment construction: use vulhub to build vulnerability environment( https://vulhub.org/#/environments/tomcat/CVE-2017-12615/)

Exploit:

<1> Upload back door

<2> Command execution using the back door

reference resources: https://www.cnblogs.com/rnss/p/13384127.html

Middleware parsing vulnerability

Case 10: IIS upload parse - (penfei806)

File parsing vulnerability

  • Form: www.xxx.com/xx.asp jpg
  • Principle: the server does not resolve by default; After the number, so XX. asp Jpg is parsed into asp files.

Exploit vulnerability

<1> A case

<2> Login background

<3> There is an upload function to upload pictures. The filepath field value is modified as follows

<4> Access the image address, and the image is executed as asp

Case 11: Nginx upload parse vulhub

nginx parsing vulnerability

  • Form: www.xxxx.com/UploadFiles/image/1.jpg/1.php
  • Usage: when uploading a picture horse and accessing the picture address, add / 1.php after it, and it will be parsed as PHP

Exploit vulnerability

<1> Upload a picture horse

<2> Cooperate with the vulnerability analysis to successfully execute the code

Case 12: Apache upload parse vulhub

Apache HTTPD multi suffix parsing vulnerability

After the environment is running, access http://your-ip/uploadfiles/apache.php.jpeg You can see that phpinfo is executed and the file is parsed into a PHP script.

http://your-ip/index.php Is a whitelist check file suffix upload component, which is not renamed after uploading. We can use Apache parsing vulnerability to get shell by uploading a file named xxx.php.jpg or xxx.php.jpeg.

reference resources:

  • https://blog.csdn.net/weixin_44677409/article/details/92799366
  • https://www.cnblogs.com/shellr00t/p/6426856.html
  • wait

Posted by weevil on Fri, 03 Dec 2021 03:32:25 -0800