File upload vulnerability (1) upload-labs shooting range practice

The goal of the file upload vulnerability is to upload some malicious files to the server that the server can parse. Such files can establish a connection with the attacker and execute malicious commands (also known as webshell). Its harm is so great that it has already attracted the attention of the industry.

This article will reproduce some bypass methods through the practice of upload-labs. Of course, it is also a systematic summary of the basic part of file upload vulnerabilities.

1. Environment construction

Here you can directly visit the author's github to download:

https://github.com/c0ny1/upload-labs

After finishing the installation, just follow the instructions in the documentation. I have to say, I sincerely thank the author for providing us with such an excellent platform for practice and learning. Here is the author's mind map posted cheekily:

Please add a picture description
The picture above shows a general bypass idea. It doesn’t matter if you don’t understand it now. Let’s do it together and you will understand.

2. Level Analysis

2.1 less-1 - detection based on front-end JS

The earliest detection, of course, is also the weakest. Let's first look at the filter statement in the page:

function checkFile() {
    
    
    var file = document.getElementsByName('upload_file')[0].value;
    if (file == null || file == "") {
    
    
        alert("请选择要上传的文件!");
        return false;
    }
    //定义允许上传的文件类型
    var allow_ext = ".jpg|.png|.gif";
    //提取上传文件的类型
    var ext_name = file.substring(file.lastIndexOf("."));
    //判断上传文件类型是否允许上传
    if (allow_ext.indexOf(ext_name + "|") == -1) {
    
    
        var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
        alert(errMsg);
        return false;
    }
}

insert image description here

Solution 1: Directly disable the browser's JS for uploading

1. Enter about:config inside the URL address bar
2. Search for the existing JavaScript.enable option
3. Set disabled
insert image description here

Try uploading ours ”webshell“. Both here are usedwebshell instead:phpinfo

<?php phpinfo();?>

insert image description here

Solution 2: The burp agent modifies the data type

After we upload a JPG suffix to bypass the restriction, we modify our suffix to .php in burp to bypass again

insert image description here

Capture packets and modify the file suffix:

insert image description here

Test results:

insert image description here

At this point, we found that front-end constraints are not only brain-consuming, but useless.

2.2 less-2 - MIME header authentication

Let's analyze the source code first:

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    
    
    if (file_exists(UPLOAD_PATH)) {
    
    
        if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
    
    
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']            
            if (move_uploaded_file($temp_file, $img_path)) {
    
    
                $is_upload = true;
            } else {
    
    
                $msg = '上传出错!';
            }
        } else {
    
    
            $msg = '文件类型不正确,请重新上传!';
        }
    } else {
    
    
        $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
    }
}

In order to see it more clearly, we print out the FILE variable:

insert image description here
You can see the file data structure:

insert image description here

array(1) {
    
     ["upload_file"]=> array(5) 
	{
    
     	
		["name"]=> string(7) "web.php" 
		["type"]=> string(24) "application/octet-stream" 
		["tmp_name"]=> string(14) "/tmp/phpPYzq7W" 
		["error"]=> int(0) 
		["size"]=> int(18) 
	} 
} 

At this point, you can roughly sort out the running process of the above source code. After our file arrives at the server, it will judge the MIME type of the request packet. If the type is wrong, it will directly refuse to upload. At this point we need to use the burp proxy to modify the MIME type of the file to upload:

insert image description here

test:

insert image description here

2.3 less-3 php3,4,5 extension analysis

This question is quite special. We can try to expand the analysis solution when the server filter is not strict and the extended php analysis function is enabled.

insert image description here

Execution effect view:

insert image description here
We can see that there is no parsing, which is actually because we have not configured the corresponding danger inside apache. We need to configure and parse files with corresponding suffixes in the apache configuration file to trigger such a file upload bypass.

2.4 less-4 .htaccess file bypass

Looking at the source code, it is found that many suffixes are filtered, but no .htaccessfiles are filtered.

.htaccessThe role of the file:
The htaccess file is a configuration file in the Apache service, which is responsible for the configuration of the web pages in the relevant directory. Through the htaccess file, it can help us realize: webpage 301 redirection, custom 404 error page, change file extension, allow/block access to specific users or directories, prohibit directory listing, configure default documents, etc. Of course, the most commonly

used The function is to realize a pseudo-static page. SetHandler application/x-http-php means to set all files in the current directory to be parsed by php. On the one hand, changing the suffix of our files to html can still be parsed as php. On the other hand, if there is no restriction on the upload directory, any malicious upload of .htaccess files will immediately cause security risks. No matter what file is uploaded, as long as it conforms to the php language code specification, it will be executed as PHP.

To enable this file, you have to add such a rule to the apache configuration file:

AllowOverride All

insert image description here

Upload example:

.htaccessFirst upload the file we wrote

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

insert image description here
Test parsing:
insert image description here

Parse failed, problem is unknown. You can private me after you solve it, hahaha

2.5 less-5 dot empty dot empty bypass

Source code audit:

$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".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);
        //去除字符串::$DATA
        $file_ext = str_ireplace('::$DATA', '', $file_ext);
        //首尾去空
        $file_ext = trim($file_ext); 
        
        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 = '上传出错!';
            }
        } else {
    
    
            $msg = '此文件类型不允许上传!';
        }

Recap the code execution process here: the uploaded file will be processed for legality of the suffix name. After the processing is completed, the obtained suffix string file_ext and the blacklist will be passed to the filter program for comparison. If it matches the blacklist, an error will be reported. Terminate upload. Upload is allowed if it does not match the blacklist.

In other words, if we can make the handler have a surplus when processing our suffix, that is, we can't match the blacklist, then we can bypass it. We can give a payload:

#()为空格,也可以自己编写,只要保证被处理后可以掏出黑名单并且可以被当成PHP进行解析即可
web.php.().()

insert image description here

Here we can see that the file name we modified is sent to the following processing statement for processing, and the upload is successful after removing a dot and a space.

insert image description here

test:

insert image description here

2.6 less-6 case file name confusion

Looking at the source code here, one line is missing, no case conversion is performed, and the lower case is bypassed directly.
insert image description here

Test: successfully bypassed and uploaded the file, but unfortunately, it did not parse it. It is speculated that it is a php version problem, but it is still the same. If you have solved it, please send a private message.

insert image description here

2.7 less-7 space bypass

$file_ext = trim($file_ext); //首尾去空Observe the source code here and find that this processing statement is missing . That is to say, we can add a space after the suffix to try to bypass it.

web.php(此处空格)

insert image description here

test:

insert image description here

Uploaded successfully.

2.8 less-8 dot bypass

Here, there is less filtering of small dots in the source code. The idea is the same as that of the seventh level, and we continue to bypass:

web.php.

insert image description here
Test results:

insert image description here

2.9 less-9 Win file stream feature bypass

After source code analysis, it was found that the str_ireplace() function was not used to replace characters to remove ::$DATA characters. Bypass Windowsthe stream feature, which means that if PHP runs on Windows, it will 文件名+::D A T A "treat ::DATAthe subsequent data as a file stream, and will not detect the suffix name, and keep the ::$DATAprevious file name. The purpose is not to check the suffix name.

web.php::$data

insert image description here
Detection:

insert image description here

2.10 less-10 point short pass

insert image description here

2.11 less-11 file name empty double write bypass

Source code analysis:

 $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","ini");
 
        //首位去除空格
        $file_name = trim($_FILES['upload_file']['name']);
        //直接将黑单内部的字符替换为空
        $file_name = str_ireplace($deny_ext,"", $file_name);

So we directly double-write the file name to bypass:

web.pphphp

insert image description here

test:

insert image description here

2.12 00 truncation in less-12 get parameter passing

Source code analysis:

<?php
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    
    
    //定义白名单
    $ext_arr = array('jpg','png','gif');
    //复合使用strrops获取后缀名定位,截取后缀名
    $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'];
        //get接收参数save_path来确定文件的存储路径,利用随机数加日期来拼接出图片文件的名称
        $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类型文件!";
    }
}
?>

From the source code above, we seem to find that once the whitelist is used to restrict uploading files, there is basically no solution. But here the author still left us a hand, the file upload path here is obtained through the form of get parameter. In other words, can we play tricks on the upload path?

In fact, we can use 00截断such a security hole that appeared before PHP5.3 to bypass, because it \0represents the stop character in C language, and the meaning has not changed in PHP written in C language.

Let's upload a normal .jpgsuffix file first. Capture packets, modify the upload path to the file with .php suffix and add the URL encoding format of %00, that is, \0.

insert image description here

We saw that the upload failed. After data query, the environment we use is 5.3.29, which exceeds the minimum version 5.2 for triggering the vulnerability, so it cannot be reproduced. Students can try to solve it. At the same time, pay attention to closing the php.ini filemagic_quotes_gpc

even if

magic_quotes_gpc = off

2.13 00 truncation in less-13 post parameter passing

Source code analysis shows that the file save path is passed through the method of POST parameter passing. We capture the packet, modify the path to .php%00further decode its URL to pass parameters:

insert image description here

Modify the data package:

insert image description here
Pass parameters after modification:

insert image description here

Of course, because the version is too high, the 00 truncation vulnerability of PHP cannot be used again, but when everyone encounters a similar code structure, such an upload solution is also a way of thinking.

2.14 less-14 file contains combined file upload

Let's take a look at the tips first:

insert image description here
Let's make it clear that we use file inclusion, so we can directly start the production of the picture horse:

#1.将目标文本文件和图片放到同一个目录下,并在此目录运行cmd
#2.输入copy命令生成图片马
copy src.jpg/b + web.txt web.jpg
copy 图片文件/b + 敏感文本文件 web.jpg

After the file horse is created, you can drag it into 010editor to see our Trojan horse information:

insert image description here

To upload:

insert image description here

Tests include:

http://127.0.0.1/upload-labs/include.php?file=http://127.0.0.1/upload-labs/upload/1620230315204119.jpg

insert image description here
This file contains old irons that I don't understand. It can be understood as the data received by the file parameter can be directly executed as a PHP file.

That is because our images contain sensitive PHP statements. So after being included, it is parsed by the server as PHP, and our image itself contains PHP code. Therefore, such potential safety hazards have been caused.

2.15 less 15-16 files contain combined file uploads

Here, the source code of the two is analyzed at the same time:

#15关的过滤语句

//定义过滤函数
function isImage($filename){
    
    
    //定义白名单上的文件后缀
    $types = '.jpeg|.png|.gif';

    if(file_exists($filename)){
    
    
        //使用getimagessize确定任何支持的指定图像文件的大小,并返回尺寸以及文件类型和 height/width 文本字符串,以在标准 HTML IMG 标签和对应的 HTTP 内容类型中使用。
        $info = getimagesize($filename);
        //从info的前两个字节中截取出文件后缀名
        $ext = image_type_to_extension($info[2]);
        //stripos返回types在ext中首次出现的数字位置,这里是在进行白名单匹配
        if(stripos($types,$ext)>=0){
    
    
            return $ext;
        }else{
    
    
            return false;
        }
    }else{
    
    
        return false;
    }
}


#16关的过滤语句
function isImage($filename){
    
    
    //需要开启php_exif模块,exif_imagetype() 读取一个图像的第一个字节并检查其签名。
    $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;
    }
}

It can be seen that it is still a judgment on the type of image. As long as the accurate file contains loopholes, we can easily bypass the above function by making a random image:

less-15

1. Make a picture horse

C:\Users\HP\Desktop\muma>copy tailuo.png/b + web.txt web.png
tailuo.png
web.txt
已复制         1 个文件。

2. File upload

insert image description here

3. The file contains parsing

insert image description here

less-16 Just repeat the trick.

2.16 less-17 file inclusion and secondary rendering bypass

Let's continue with source code analysis:

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

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

The core code above shows us the unique filtering scheme in this official card, even after our pictures are uploaded, the pictures will still be reorganized. We can try the following filter strengths:

Go ahead and upload our previous web.jpg image horse.

insert image description here
Parsing failed, we try to pull down the picture and analyze the difference before and after uploading:

insert image description here

Use 010editor for binary analysis:

insert image description here

We can see that there is already obvious data shuffling behavior, and our previous PHP statement has disappeared. At this point, we can try to insert the statement in the place that has not been changed. In theory, this solution is feasible, but because different images run under the same secondary rendering function, the results are not the same. And the pictures in jpg format that I have tried are obviously out of order, and many attempts have failed.

We try to upload the gif image horse, pull the uploaded image to the local for encoding comparison again, and try to inject php code in the unmodified part:

1. Make a gif Trojan

C:\Users\HP\Desktop\muma>copy dijia.gif/b + web.txt web.gif
dijia.gif
web.txt
已复制         1 个文件。

2. Upload the file and save it locally again

insert image description here

3.edit Binary comparative analysis

insert image description here
Click on this part for code injection testing:

insert image description here

After n times of testing: Finally, the upload of webshell can be realized in this position

insert image description here

In general, the secondary rendering can't escape some conventional positions without secondary conversion. Through continuous testing, we finally locate the small binary area in the binary file that has not been converted and does not affect the file structure, and complete our php code injection.

Immediately after the picture is uploaded, we need to implement malicious webshell parsing in combination with the vulnerability contained in the file. The whole process requires multiple attempts. In order to achieve the expected effect. However, if you can jpg,png,gifhave a systematic understanding of the encoding format of equivalent pictures, this thing will be done faster. Still need to learn a lot.

2.17 less-18 race vulnerability

Competitive vulnerabilities are a novel concept for most of our beginners. To understand this type of vulnerability, we need to figure out a very important point, who competes with whom. Knowing this, we can be targeted in the follow-up study.

Source code analysis:

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 = "只允许上传.jpg|.png|.gif类型文件!";
            unlink($upload_file);
        }
    }else{
    
    
        $msg = '上传出错!';
    }
}

Let's take a look at the idea here again. The file is uploaded to the folder first, and then the validity of the suffix is ​​checked. Legal renaming is reserved, and illegal deletion is performed directly.

It sounds fine, but when you think about it carefully, it's broken. There is a time window for files to be stored in the directory first, so if we are fast enough, malicious files within the window period can be included. Wouldn't it be enough to just let this malicious file generate a webshell?

Here is our first malicious PHP file:

#webat.php
<?php fputs(fopen('shell.php','w'),'<?php phpinfo();?>')?>

Then we use burp to start two processes, one for fast upload, and one for fast request to upload file address. Eventually our malicious code will be executed to generate our webshell.

Here we capture two data packets and send them to the blasting module with ctrl+i for processing:

insert image description here

Let's grab the request package again and perform the same operation:

insert image description here
Configure the upload module:
insert image description here

Configure the request module:

insert image description here

Result acquisition:

insert image description here
Test webshell:

insert image description here
Uploaded successfully! ! !

To sum up, the competition point in this example is whether the file we uploaded webat.phpis deleted first or requested by us first. We use two processes, one for wireless uploads and one for limited requests. Finally, the upload status is confirmed according to the echo status code, and webshellthe upload is carried out.

3. Summary

Let me first talk about common file upload detection schemes. It can be roughly divided into client-side and server-side restrictions according to the classification scheme given by the author.

The client can mainly perform legality detection at the JS level (preventing gentlemen from villains), while the server can check the suffix of the file and check the content of the file. In the detection of the server side, a classification can be made according to the black and white lists. The black list has a low safety factor, and it is usually bypassed due to problems such as the case filtering is not rigorous, the filter suffix code is not rigorous, and the program version is too low.

The whitelist is much safer. Even if you want to bypass the whitelist detection to upload the webshell, you need to combine the possible file upload vulnerabilities to attack. Greatly increase the attack difficulty of the attacker.

Of course, there is another type of uploading problem that occurs in the running logic of the code. Before the legality of the file is confirmed, it is very dangerous to let the file appear on the server in any form. Especially in the upload directory, the attacker can use the method of multi-process competition request to execute malicious code before we delete the malicious file to realize the generation of webshell. This part requires a code audit to find the corresponding problems.

Please add a picture description

Here is the author's upload idea: generally it is to judge the front-end and back-end filters, and to judge the filter type (content detection, suffix detection, code logic problems)
Please add a picture description

Of course, if someone asks how to defend against file uploads, then I will definitely answer immediately: simultaneous whitelist filtering on the front and back ends, suffix filtering on the front end, file content detection on the back end, and multiple renderings at random times. Make sure to judge the legality of the file first, upload the file to the directory, and rename it.

In this way, the safety factor can be pulled to 99%, completely blocking the "dream of shell insertion" that hackers dream of

Guess you like

Origin blog.csdn.net/qq_55316925/article/details/129532306