继续来学习owasp top10之一的文件上传,使用的靶场是upload-labs
pass-01(前端js绕过)
直接右键查看源码:
发现前端有js拦截,只允许上传.jpg,.png和.gif
文件,不确定后端有没有校验,先尝试抓包绕过:
把文件后缀改成png,点击上传:
修改后缀为php,然后放包
在后台可以看到一句话木马成功上传
但如果我们作为攻击者,我们是看不到后台的,我们需要在前端找到上传的路径:
发现上传的文件在上一级目录下upload下,然后蚁剑连接:
pass-02(MIME绕过)
常见MIME类型:
text/plain
(纯文本)
text/html
(HTML文档)
text/javascript
(js代码)
application/xhtml+xml
(XHTML文档)
image/gif
(GIF图像)
image/jpeg
(JPEG图像)
image/png
(PNG图像)
video/mpeg
(MPEG动画)
application/octet-stream
(二进制数据)
application/pdf
(PDF文档)
绕过方法:
修改Content-Type头:
- 将恶意文件(如PHP)的Content-Type改为无害类型(如image/jpeg)
- 示例:
Content-Type: image/jpeg
(实际是PHP文件)
双扩展名绕过:
- 例如:
malicious.php.jpg
Content-Type: image/jpeg
,但删掉.jpg,就又变成了php文件
这里直接上传php木马文件,会上传失败,观察前端源码并没有过滤,也就是后端进行了校验,那依旧是上传jpg后缀的木马,然后抓包把文件后缀名改成php;也可以上传muma.php.jpg,抓包的结果Content-Type: image/jpeg
,所以只需要把.jpg给删掉即可,两个方法对应上面的修改Content-Type头和双扩展名绕过,但本质没什么区别
看下后端源码:
getshell的方法同第一关
pass-03(黑名单绕过)
先尝试上传muma.php,提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!原来有黑名单,我们如果继续按照前两关的方式,抓包修改文件后缀为php,Content-Type: image/jpeg依旧不行,因为后端专门检验你的文件后缀是不是php
虽然php被禁,但我们还可以尝试php3
, .php4
, .php5
, .php7
, .php8
(旧版 PHP 遗留支持),.phtml
(PHP + HTML 混合文件),.phps
(PHP 源代码显示,但某些配置仍可执行)
根据返回信息可见这些都被上传成功了(除了php后缀,不是看状态码),但是其中存在未被解析的文件,我们只能根据响应数据包里的上传路径一个一个测试:如果说显示空白页面,那么就是被解析了,如果显示一句话木马,那就是没被解析,前提是我们需要在Apache的httpd.conf配置文件中设置AddType application/x-httpd-php
,才可以解析php3
, .php4
, .php5
, .php7
, .php8
,.phtml
,.phps
因为我是高版本phpstudy,于是想手动添加该字段,但即便添加后,在web中访问该文件会将该文件下载(这挺让人懵逼的,按道理不应该是这样啊),未添加前,在web中访问该文件只是空白(但并未解析),两种共同点都是未被解析(因为我上传phpinfo内容依旧是空白),我看别的博主说要将php的版本改为ts(参考:https://blog.csdn.net/mooyuan/article/details/147541272),但我的phpstudy里面没有ts版本,遂放弃。
不过本关的重点在于知道当php被后端校验时应该如何绕过:尝试上传php3
, .php4
, .php5
, .php7
, .php8
,.phtml
,.phps
pass-04(黑名单,.htaccess绕过)
源码:
1 | $msg = null; |
这里将pass-03能上传的文件也校验了,所以pass-03的方法也行不通
但是这里没有禁止上传.htaccess
文件,介绍下该文件:.htaccess(Hypertext Access)是 Apache Web 服务器的一个配置文件,主要用于目录级配置,允许在不修改主服务器配置(httpd.conf
)的情况下,对特定目录进行权限、重定向、URL 重写等设置。
而且其可以修改 PHP 解析规则,攻击者可上传 .htaccess
文件,使 .jpg
等文件被当作 PHP 执行:
1 | AddType application/x-httpd-php .jpg |
使用htaccess文件前提:
- 黑名单中未过滤 .htaccess
- apache配置文件httpd.conf中启用了AllowOverride All
- 服务端未处理文件名(否则上传到htaccess到目录下成为其它文件名则不奏效)
上传.htaccess文件成功:
然后上传phpinfo.php文件,抓包将文件后缀改成jpg(htaccess中可以将jpg文件解析成php文件)
访问时又出错了,又变成下载了,和pass-03遇到的情况一样,这里还是php的版本问题,不过知道原理就可以了
有个师傅把版本改成ts后做得:https://blog.csdn.net/mooyuan/article/details/147542111
pass-05(黑名单,.user.ini绕过)
提示说:上传目录存在php文件(readme.php),本次使用配置文件.uer.ini,该配置文件的效果是在.user.ini相同的目录下,所有的php文件都包含pass5.jpg这个文件。如果我们上传.uer.ini,而且该目录下存在readme.php,我们再上传一个修改为jpg后缀的phpinfo,虽然jpg不能解析为php,但该文件被写入readme.php,这样就可以解析了
.user.ini重要配置项:auto_prepend_file=文件名
:在页面头部加载的文件,auto_append_file=文件名
:在页面尾部加载的文件,写入一个就行
1 | auto_prepend_file=phpinfo.jpg |
依次上传文件,然后访问readme.php
看下后台上传的文件:
注:本次上传禁止了.htaccess
pass-06(黑名单,大小写绕过)
通过源码可知,这里把.htaccess和.user.ini都给禁用了,但不同的是这里并没有转换成小写再校验:
我们只需要把后缀改成没有校验的大写即可,但如果你使用的是高版本的phpstudy,还用的是apach服务器,那么当访问文件的上传路径时,大概率会遇到500的报错,这里使用nginx即可:
pass-07(黑名单,后空格绕过)
依旧是把所有后缀都给禁用了,与pass 05不同的是,校验的代码又少了一行:
这里少了首尾去空这个过滤,我们通过抓包在文件尾处添加一个空格:
如果在.
后面加空格呢???
可见能上传,回显空白页面说明存在该文件,但不能被解析
pass-08(黑名单,加点绕过)
与上面相比,过滤少了删除文件名末尾的点,既然如此,那我们主动构造一个点
访问该文件时,最后加不加点都可以成功
原理:在 Windows 系统 中,文件名末尾的点(
.
)会被自动忽略,导致phpinfo.php.
实际保存为phpinfo.php
,从而绕过某些文件上传检查。
pass-09(黑名单,::$DATA绕过)
过滤又少了$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
,我们继续再文件尾处加上::$DATA
:
访问时不用加::$DATA
:
原理:在 Windows 系统 中,
文件名::$DATA
是一种特殊写法,用来直接访问文件的原始数据流,常用于绕过文件上传限制或隐藏恶意代码。
- NTFS 文件系统特性:
Windows 的 NTFS 格式允许文件附带“数据流”(Alternate Data Streams, ADS),比如文件可以有隐藏的额外内容。::$DATA
的作用:
加在文件名后,表示直接操作文件的主数据流(默认存储内容的部分)。上传名为
phpinfo.php::$DATA
的文件,Windows 会自动忽略::$DATA
,最终保存为phpinfo.php
。
pass-10(黑名单,点空格点绕过)
查看源码,这次将所有该过滤的都过滤了,我们观察它的逻辑,它是先去除文件名末尾的点,然后转换为小写,去掉::$DATA,然后再去除空格,如何我们在文件名后面加上一个点,再加上空格,再加上一个点,第二个点按照代码的逻辑是不会被过滤的,所以当进行in_array匹配时,可以成功绕过
抓包修改文件后缀为. .
顺便提一嘴,我们上面所有的绕过,都可以采用这种点空格点的方式
pass-11(黑名单,双写绕过)
直接看源码,与上面都不一样,这里的str_ireplace的第一个参数设置为黑名单,str_ireplace不区分大小写,所以无法通过大写绕过,如何我们后缀设置为pphphp,str_ireplace会匹配到php并将其删除,然后左边剩下的p和右边的hp可以合并再次生成php后缀,因为该函数是通过递归进行匹配,所以就绕过了前面的p,当执行到最后一个p,结束匹配,成功绕过;
这里文件名phpinfo中的php也被删掉了
pass-12(白名单,前提:上传路径可控,get,%00截断绕过)
我们先上传一个符合要求的图片:
发现上面有save_path的参数,我们再看下源码:
1 | $is_upload = false; |
只允许上传'jpg','png','gif'
,上传.jpg.php
这样是不行的,看下最终的图片保存路径,文件名是save_path加上一个rand随机数和一个date日期,和默认的文件后缀,我们刚才上传正常图片时观察到图片的save_path是/upload/
,也就是我们最终上传的文件路径是/upload/rand+date.jpg,但如果我们能主动在/upload/后面加上个文件名,再使用%00截断后面的rand+date.jpg,即/upload/自定义文件名+%00+rand+date.jpg,当我们自定义的文件名是phpinfo.php,那我们上传的phpinfo.jpg,最终在服务中生成的名字是不是变成了/upload/phpinfo.php???
还有两个前置条件:
配置文件php.ini中的magic_quotes_gpc = off
php的版本要求是5.2.x
因为我是8.1.1.3的phpstudy,上面最低的php版本是5.2.17,可死活下载不下来,下载高版本的就可以,也是离了个大谱,不过还是重在知道方法
最终也是上传失败,只要我在upload/后面拼接任何路径,上传都是失败的,大概率是因为php版本过高的问题
pass-13(白名单,post,%00截断绕过)
与上一关设计方法一样,区别就是这里是post控制上传路径,遇到的问题也一样
pass-14(图片马+文件包含,文件头检验)
根据源码可知:后端会校验我们上传文件二进制的前两个字节,意味着我们上传不了木马文件,只能上传jpg,png和gif,但这里有一个文件包含的功能,提示我们使用文件包含漏洞]能运行图片马中的恶意代码。我们看下include的运行规则:当 include
一个 JPG 文件时,PHP 会尝试解析文件内容。如果 JPG 文件中没有有效的 PHP 代码(比如 <?php ... ?>
标签),PHP 会直接输出文件的原始二进制内容(包括 JPG 的头部信息、图像数据等)。
那如果我们向jpg的图片中加入木马文件呢,也就是将正常jpg图片和木马php文件合成一个带木马的jpg图片即图片马,听起来可能比较懵,我们给出下面的命令生成图片马
我们用记事本打开该图片马即shell.jpg
,在最后发现了我们的木马代码,如果我们把图片马当成php文件解析,按照上面include的规则,那么php代码就可以执行了
在记事本上显示的是??php phpinfo(); ?>
,这个不影响,用vscode打开就是正常的,接着我们上传图片马
然后打开该文件包含的文件,加入参数file,令其等于我们上传的文件路径,不难发现upload是和Pass-14同一目录,include.php和Pass-14也是同一目录,所以upload和include.php也是同一目录,令file=upload/文件名
本以为这样就万事大吉了,结果又又又报错了,查阅数位博主发现是因为在报错的那行有字符<?
,然后被误以为从这里解析,但后面并没有php代码,故而报错,而参考文章解决的办法是删除掉报错行的字符,我也尝试这样修改:
我顺便把所有含<?
的地方都删掉了,图片肯定是不能正常显示了,再次上传被修改的图片,结果又又又又又报错了:显示不能识别文件类型,肯定是因为修改导致文件头被更改或破坏了,从而后端无法识别
其实有更好的解决办法,上传一张比较单调(元素内容比较少)的图片,这样里面产生<?
字符的可能就会极大减小,最后也是终于成功了,png和gif原理相同,就不尝试了
pass-15(图片马+文件包含,getimagesize整个文件检验)
做到这题我发现我上面那道题做错了,也不是做错了,而是没按出题人的目的方向来做,下面的pass-14的做法,上面就当是pass-15的解法了。
pass-14源码是只校验前两个字节,我们用010editor来修改:
我这里使用的前三个字节是FFD80F,表示jpg文件
(多一个字节不影响),这里把文件扩展名(后缀)设为jpg或者php的都无所谓,都可以上传,但最后还是被服务器把后缀设为jpg,依旧需要文件包含来解析
14和15区别
检测方式 | 第一段代码(getReailFileType ) |
第二段代码(isImage ) |
---|---|---|
检测目标 | 文件前 2 字节(Magic Number) | 完整文件结构(getimagesize() ) |
严格性 | 低(易绕过) | 高(需构造复杂图片马) |
简言之:14是仅检查文件头,不验证文件完整性,更容易绕过,15是严格检测文件内容,必须是完整图片才能通过。
第二种绕过方法可以绕过第一种,反之不行,即15的解法可用于14,反正不行
pass-16(图片马+文件包含,exif_imagetype整个文件检验)
自己感觉和pass-15的检测没什么区别,就是检验函数不同,相同点就是会校验整个文件是否是完整图片,所以只改文件头是不行的,这里和pass-15的解法就一样了,还有一个前提是需要开启php_exif
模块
在php.ini配置文件中修改也可以
我一开用的是php 5.3.29nts
版本,但是每当点击上传的时候就会白屏,后台也没有显示上传成功,切换成高版本7.3.4nts
,可以上传,但无法解析,总之总会产生各种各样的问题,最终尝试5.5.9nts
版本,终于成功了
高版本7.3.4nts
:
后来又尝试了一下5.3.29nts
版本,结果成功了,也是无语了(但是上传的时候会报个错误,显示找不到exif模块)
反正做起来挺难受的😭😭😭
pass-17(图片马+二次渲染)
这里可以看到使用imagecreatefromgif()和imagegif()对图像进行二次渲染,这种方法能有效消除gif文件中可能隐藏的恶意代码,生成全新的图像文件,不保留原始文件的元数据,我们先随便上传一个gif文件,然后将其下载下来,与我们原先的图片进行对比:
在两种图片未被修改的地方加上我们的shell脚本代码
修改后的代码上传:
这里如果png和jpg文件也这样修改,可能会失败,下面是我修改jpg的错误做法:
但这样修改后,jpg图片就被破坏掉了,打开就会显示图片已经损坏,就会导致无法上传:
同理如果是png,png会有crc校验,如果随便修改其中的二进制,就会导致crc对不上,从而也无法上传成功,这里使用gif文件修改并上传是最简单的
可以参考该文章:https://xz.aliyun.com/news/2337#toc-13
pass-18
从这到21关就先不写了,以后有空再给补上
参考文章:
https://blog.csdn.net/aaron_miller/article/details/106143006