upload-labs range practice
- 1. Environment construction
- 2. Level Analysis
-
- 2.1 less-1 - detection based on front-end JS
- 2.2 less-2 - MIME header authentication
- 2.3 less-3 php3,4,5 extension analysis
- 2.4 less-4 .htaccess file bypass
- 2.5 less-5 dot empty dot empty bypass
- 2.6 less-6 case file name confusion
- 2.7 less-7 space bypass
- 2.8 less-8 dot bypass
- 2.9 less-9 Win file stream feature bypass
- 2.10 less-10 point short pass
- 2.11 less-11 file name empty double write bypass
- 2.12 00 truncation in less-12 get parameter passing
- 2.13 00 truncation in less-13 post parameter passing
- 2.14 less-14 file contains combined file upload
- 2.15 less 15-16 files contain combined file uploads
- 2.16 less-17 file inclusion and secondary rendering bypass
- 2.17 less-18 race vulnerability
- 3. Summary
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:
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;
}
}
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
Try uploading ours ”webshell“
. Both here are usedwebshell
instead:phpinfo
<?php phpinfo();?>
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
Capture packets and modify the file suffix:
Test results:
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:
You can see the file data structure:
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:
test:
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.
Execution effect view:
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 .htaccess
files are filtered.
.htaccess
The 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
Upload example:
.htaccess
First upload the file we wrote
<FilesMatch "/.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
Test parsing:
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.().()
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.
test:
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.
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.
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(此处空格)
test:
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.
Test results:
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 Windows
the stream feature, which means that if PHP runs on Windows, it will 文件名+::D A T A "
treat ::DATA
the subsequent data as a file stream, and will not detect the suffix name, and keep the ::$DATA
previous file name. The purpose is not to check the suffix name.
web.php::$data
Detection:
2.10 less-10 point short pass
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
test:
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 \0
represents the stop character in C language, and the meaning has not changed in PHP written in C language.
Let's upload a normal .jpg
suffix 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.
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%00
further decode its URL to pass parameters:
Modify the data package:
Pass parameters after modification:
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:
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:
To upload:
Tests include:
http://127.0.0.1/upload-labs/include.php?file=http://127.0.0.1/upload-labs/upload/1620230315204119.jpg
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
3. The file contains parsing
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.
Parsing failed, we try to pull down the picture and analyze the difference before and after uploading:
Use 010editor for binary analysis:
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
3.edit Binary comparative analysis
Click on this part for code injection testing:
After n times of testing: Finally, the upload of webshell can be realized in this position
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,gif
have 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:
Let's grab the request package again and perform the same operation:
Configure the upload module:
Configure the request module:
Result acquisition:
Test webshell:
Uploaded successfully! ! !
To sum up, the competition point in this example is whether the file we uploaded webat.php
is 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 webshell
the 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.
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)
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