闲来无聊,把upload-labs所有的关卡都刷一遍,就当复习一下文件上传漏洞的各种绕过技巧吧,做完一关再看看源代码提高一下审计能力挺好的
一个前端检测,可以禁用js,也可以直接抓包就可以绕过上传
访问成功
Content-Type绕过,直接把Content-Type改为图片类型即可
上传成功
这一关是另类的文件名的绕过,可以尝试phtml,php3,php4, php5, pht后缀名都可以绕过,但是前提是要在配置文件里面有这样的一句话
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
成功回显
源码里面直接用的黑名单。。
$deny_ext = array('.asp','.aspx','.php','.jsp');
当然还有第二种方法
就是上传.htaccess
,实现重写文件解析,同样这样的前提也是得在配置文件里面有这样的一句话
AllowOverride All
LoadModule rewrite_module modules/mod_rewrite.so
上面的方法已经不行了,可以看一下他过滤的名单
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".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
还是没有过滤,可以重写文件解析规则绕过,上传一个.htaccess
,文件内容如下,就是在upload目录下匹配gg.jpg的文件并以php文件执行
SetHandler application/x-httpd-php
然后再上传一个名字为gg.jpg的脚本
然后访问成功执行
这一题里面多过滤了.htaccess
,如何绕过呢?
对比一下代码可以知道,可以使用大小写绕过,因为这里把原来转换成小写的那一部分给删掉了
这一关比第五关少了这样的一句代码
$file_ext = trim($file_ext); //首尾去空
所以可以后缀名+空格的形式去绕过
对比第6题的代码可以发现少了下面一句代码
$file_name = deldot($file_name);//删除文件名末尾的点
既然没有对文件最后的点做过滤,可以尝试以后缀名加上点的形式去绕过
这一题的代码比上一次少了下面这一段代码
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
这个是关于windows下文件的流特性,可以参考一下这篇文章
https://www.owasp.org/index.php/Windows_::DATA_alternate_data_stream
这样一来就是说这东西应该只能在Windows下运行了
这一关像是前几关的组合拳,虽然把最后的点给删掉,但是仍然可以绕过,因为这里的过滤并没有递归下去,只是一步,这样就相当于SQL注入里面用str_replace只过滤一次关键字一样
$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); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
可以遵循着他的步骤去实现自己的payload,可以这样设置
4.php. .
这样一来检测到最后的文件名是4.php.
这样就相当于第七关了
关键过滤的代码就这两句
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
跟我上一关讲的SQL注入的类型差不多,就是双写绕过
4.pphphp
关键的代码在于这里的’save_path’是一个可控的变量,但是后面还拼接上一个后缀名,也需要绕过
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
这个时候可以使用%00截断,但这东西有点过气了,因为需要两个条件
如果要完成这一个题目就必须要实现上面的两个条件,但是现在都PHP7了,这东西也就很少见了,满足上面的条件的时候php就是把它当成结束符,后面的数据直接忽略,这也导致了很多的问题,文件包含也可以利用这一点
所以如果要绕过,我们可以这样去实现,另save_path等于下面的值
../upload/4.php%00
这里的源代码就改了一点点,就是把get改为post类型,一样的方式绕过,只不过这里需要在二进制里面修改%00,因为post不会像get对%00进行自动解码。
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
从这一关开始要求上传图片马,但是没有办法直接执行图片马,需要另外的方法去实现一般是加上php伪协议去getshell,常见的有phar,zip等等
如果想要看到详细的效果可以写一下简单的脚本放在upload目录下即可,
@include $_GET[file];
?>
最最最简单的图片马直接一条命令即可生成
copy normal.jpg /b + shell.php /a webshell.jpg
上传一个图片马,内容如下,可以看到里面有脚本语言
把该图片上传上去,尝试文件包含,成功回显
这里可以发现源代码只是用了unpack这一个函数去实现对于php前两个字节的检测,也就是只是对文件头做检测。。。
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack("C2chars", $bin);
类似上一个题目,获取了图片的相关的大小及类型,并验证是否时刻上传的图片,同样可以使用文件头的方式绕过
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
说明info[2]是一个文件的类型,同样的方法也是可以绕过的
换了一个获取图片信息的函数
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
跟pass-13一样的绕过方法
这一关对后缀名和文件类型啥的都进行了很严格的控制,而且在后面还对图片进行了二次编译
//使用上传的图片生成新的图片
$im = imagecreatefromjpeg($target_path);
这一个题目跟上次校赛的题目思路一致,寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传,下载下来后发现这一部分插入代码的没变但是其他部分都变了
尝试文件包含,后面怎么利用就不多说了
这一关是条件竞争的问题,查看源代码就会发现你需要在缓存文件转移到别的目录的时候,赶紧访问它,这里可以使用burp去发包,可以把文件内容改成下面这样
$c=fopen('./cmd.php','w');fwrite($c,'');?>
或者这样,反正就是为了写文件进去就对了
fputs(fopen('shell.php','w'),'');?>
两个burp跑一跑,就会在该文件夹下面产生新的文件了
访问成功
同样的也是一个条件竞争的问题,看一下源代码可以发现这里使用类去实现相关方法,包括查看文件后缀名,大小等等
这里面的问题存在于代码将上传文件更改名字的时候给了个时间差,让我们可以去实现这个竞争效果,同样的方法,不都说
这一关正常做法应该是CVE-2015-2348 move_uploaded_file() 00截断,上传webshell,同时自定义保存名称
上传的文件名用0x00绕过。改成xx.php【二进制00】.x.jpg
但是发现了一种更有意思的解法
http://pupiles.com/%E7%94%B1%E4%B8%80%E9%81%93ctf%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83.html
简单来说就是move_uploaded_file
底层会调用tsrm_realpath
函数导致,递归删除文件名最后的/.
导致绕过了后缀名检测,同样类似的函数还有file_put_content()
,反正打开文件流都会有类似的操作
所以可以这样子去绕过6.php/.
这个题目用了数组+/.的方式去绕过,因为源代码里面含有这样的两句代码,成了关键得绕过的地方
if (!is_array($file)) {
$file = explode('.', strtolower($file));
}
$file_name = reset($file) . '.' . $file[count($file) - 1];
这同样我们就需要满足两个条件,第一个是先得保证另外修改的名字需要满足是数组的条件,所以我们可以抓包构造数组,第二点由于后面filename构成的过程中由于$file[count($file) - 1]
的作用,导致$file[1] = NULL
,所以构造文件名后相当于直接就是xx.php/.
,根据上面一题的知识,可以直接在move_uploaded_file
函数的作用下可以将/.
忽略,因此还是可以上传成功的。
因此save_name变量的两个值分别是xx.php/
,另外一个值是jpg
,其实从代码审计的角度上看,还是可控变量导致这样的后果
upload-labs里面的关卡个人感觉只是针对文件上传这个漏洞去弄的,可以梳理一下,可以根据上面的绕过写一个fuzz字典XD
还有其他的中间件问题导致的解析漏洞没有展现出来,可能环境配置比较麻烦,想了很久,我怕自己忘了,还是自己总结一下,以后可以拿出来看一下
IIS 6.0
解析利用方法有三种:
1.目录解析
建立xx.asp为名称的文件夹
,将asp文件放入,访问/xx.asp/xx.jpg,其中xx.jpg可以为任意文件后缀,即可解析
2.文件解析
后缀解析:/xx.asp;.jpg /xx.asp:.jpg(此处需抓包修改文件名)
3.默认解析
IIS6.0 默认的可执行文件除了asp还包含这三种
/xxx.asa
/xxx.cer
/xxx.cdx
/xxx.apsx
在正常图片URL后添加 /.php,可以解析为php
一般都在2.3.x以下版本,但是有时候配置文件的不同也会导致不安全
后缀解析:test.php.x1.x2.x3
Apache将从右至左开始判断后缀,若x3非可识别后缀,再判断x2,直到找到可识别后缀为止,然后将该可识别后缀进解析
test.php.x1.x2.x3则会被解析为php
最近在出题的时候在apache 2.1.x的版本就可以用test.php.jpg直接就可以getshell了,真尴尬。
Nginx <8.03
畸形解析漏洞
直接在正常图片URL后添加/.php
Nginx <=0.8.37
在Fast-CGI关闭
的情况下,Nginx <=0.8.37 依然存在解析漏洞
在一个文件路径(/xx.jpg)后面加上%00.php会将 /xx.jpg%00.php 解析为 php 文件。