原理
很多网站都有文件上传的功能,如果有些网站对上传的文件不做严格的限制,用户上传了一些特殊文件,后台就会将上传文件的内容当做代码执行,这样一来,用户就可以通过上传一些木马文件,获取到网站的WebShell(网页后门),用一些WebShell管理工具,实现对网站的控制
检测后缀:如果一个后缀能骗过检测机制,又能成功被Windows识别,那么就可以成功绕过上传
检测文件内容:通常需要上传一个图片马
简单的一句话木马
<?php @eval($_POST[a]); ?>
有时候<?= @eval($_POST[a]); ?>
这样也可以(没有php)
eval()
函数,eval函数的作用是将括号里的字符串都当做php语句执行@
是错误控制运算符,可以将产生的错误忽略$_POST[]
是超全局变量,用于获取post请求的值a
是可以修改的,使用中国蚁剑连接时,a为密码- 有
<?
的木马容易被识别,来个不一样的GIF89a? <script language="php">eval($_REQUEST[1])</script>
密码是1
JavaScript(简称JS)前端验证
一般的前端验证的错误提示是弹窗,前端验证是指在客户端就对文件进行合法性检查,但显而易见,所有的前端验证都是不安全的,因为前端都是用户可控的
- F12找到检验文件的代码,删除后再上传
- 可以用一些浏览器插件来关掉JS的功能,使检测失效
- 先将文件的后缀改成允许上传的格式,再用抓包软件拦截后上传,在抓包软件中再将后缀改回原本想要上传的格式,这样就可以绕过前端直接发往后端
Content-Type验证
MediaType即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。也就是说,每种类型的文件上传时,都会给他一个Content-Type值作为标识,但是这个也是用户可修改的
- 常见类型:
text/html HTML格式
text/plain 纯文本格式
text/xml XML格式
image/gif gif图片格式
image/jpeg jpg图片格式
image/png png图片格式 - 绕过方法
- 用抓包软件拦截,再将content-type类型修改为允许上传的类型,注意有两个content-type,注意不要改错
- 实际上只要我们上传的是允许上传的类型,就会自动为我们生成一个正确的content-type,只要参考前端验证3的方法即可
黑名单绕过
如果明确说明了不允许某类文件的上传,即为把这类文件设置为黑名单
等价扩展名绕过
原理
等价扩展名就是在更改后缀名的同时不改变文件性质,如果,没有对等价扩展名加以限制,可以绕过黑名单php的等价扩展名
php2 php3 php4 phps phtml php5 phptasp的等价扩展名
asa, cer, cdxaspx的等价扩展名
ashx, asmx, ascxjsp的等价扩展名
jspx jspf
.htaccess绕过
.htaccess
文件是分布式配置文件,可以实现改变文件扩展名等功能,只在当前目录和子目录生效.htaccess
文件是用来修改Apache的配置的文件,如果和主配置文件有冲突的话,优先.htaccess配置
.htaccess
文件代码这段代码的功能是如果发现shell.jpg文件,就将它当做php代码来解析1
2
3<FilesMatch "shell.jpg">
SetHandler application/x-httpd-php
</FilesMatch>- 流程
先将.htaccess
文件上传,再将.jpg
文件上传,然后找到.jpg
的上传地址用蚁剑连接即可 - 前提
有些题目会把MIME类型做限制,但没有限制.htaccess
后缀,这时候可以通过修改Content-Type成功上传
如果.htaccess
后缀也被加入黑名单,或是中间件不是Apache
,这个方法失效
.user.ini绕过
.user.ini
文件是用来声明 PHP 设置更改的文件,可以支持在每个目录进行不同的配置,比php.ini
有更高的优先级,和.htaccess
文件类似,但是.htaccess
只能在Apache中间件中使用,而.user.ini
有更广的使用面
.user.ini
文件代码1
auto_prepend_file=shell.jpg
这段代码表示在执行PHP脚本之前,会自动包含名为shell.jpg的文件。这意味着,如果
shell.jpg
文件中包含了有效的PHP代码,那么这些代码将在执行PHP脚本之前被执行流程
先将.user.ini
文件上传,再将shell.jpg
文件上传,需要注意的是,这里需要找到.user.ini
的同级目录(必须是php文件),因为.user.ini
文件是它同级php文件的配置文件,这个文件会自动包含shell
文件
大小写绕过
大小写绕过和sql注入原理的差不多,Windows对大小写不敏感,但如果源代码里有这个函数strtolower()
(把接收到的都转为小写),则大小写绕过失效
空格绕过
- 原理:
windos在存储时会自动去处空格,在后缀的首或尾部加入一个空格,如果网站没有过滤空格的话,可以成功上传 - 注意:
浏览器有可能会自动过滤上传文件的空格,建议使用抓包软件在数据包中加入空格 trim()
函数的作用是首尾去除空格,有这个函数空格绕过失效
.点绕过
在Windows中,系统会自动忽略删除末尾的.
,所以我们上传类似于.php.
这样的文件也是可以生效的,但如果检测机制没有去删除这个.
,那么就会把最后一个.
后面当成后缀名,文件就可以成功上传(用抓包软件)
复写.点绕过
- 原理
原理和点绕过类似,但是源代码中加入了deldot()
函数用来删除文件名末尾的点,这时候如果我们直接在.
后面加上空格,他是会被忽略的,.
还是会被删除 - 方法
如果我们写入两个点,中间加上空格. .
这样一来,最后一个点会被删除,中间的空格不会被忽略,于是不认为前面一个点是末尾的点,实现点绕过.(用抓包软件)
::$DATA绕过
- 原理
php在Windows环境的时候,如果文件的后缀名后面有::$DATA
,则会把后面的数据当做文件流处理,不会检测后缀名 - 注意
::$DATA
要想生效必须要在php+Windows环境,Windows保存文件时会去除后面::$DATA
,所以在连接时找到的地址不含::$DATA
复写后缀绕过
- 原理
和SQL注入里的复写绕过类似,源代码中有str_ireplace(参1,参2,参3)
函数,可以将关键后缀替换为空,如果是替换为空,且只进行一次的话,则可以复写pphphp
绕过
白名单绕过
如果明确说明了只允许某类文件的上传,其他类型的文件都不允许上传,即为把这类文件设置为白名单,显然,白名单是要比黑名单安全性更高
00截断绕过
使用条件:
- php版本要小于5.3.4。
- 文件路径(sava_path)可控。
- magic_quotes_gpc需要为关闭状态。
原理
所谓的00截断
指的就是%00
和0x00
%00
适用于GET传参,URL解码后是空字符NULL,解码成16进制也为0x000x00
适用于POST传参,解析后也是空字符NULL,0x代表16进制
当一个字符串中存在空字符的时候,再被解析的时候会导致空字符后面的字符被丢弃(类似于SQL语句中的注释符)流程
上传文件时,把木马文件改成可以上传的类型,然后用抓包软件修改数据包
GET传参:在 sava_path的地方加上想要的文件名和后缀,最后加上%00
POST传参:在sava_path的地方加上想要的文件名和后缀,最后加上一个字符,在用Hxe(16进制1)找到最后这个字符将它修改为00
图片马
在upload-labs pass 14关开始,检测程序不仅仅是根据后缀来判断文件是否合法了,会根据文件内容来检测上传文件是否为一个真实的文件,这时候,我们可以试着上传一个图片马
- 概念
图片马,即是携带了一句话木马的图片,外表是一个正常的图片,但是图片的编码中写入了一句话木马 - 图片马的制作
将图片文件和一句话木马php文件保存在同一文件夹下,在此文件夹的命令提示符下输入a.jpg是一个正常的图片,shell.php是一句话木马,c.jpg是合成以后的图片马1
copy a.jpg/b+ shell.php/a c.jpg
- 使用条件
并非所有的情况下都可以使用图片马,在正常情况下,图片不会被解析为可执行文件,需要网站存在文件包含漏洞或文件解析漏洞才行,在upload-labs pass 14里并没有这个环境,可以在/upload/目录下创建一个include.php文件,里面写入1
2
3
4
$file = $_GET[ 'file' ] ;
include ($file); - webshell的获取
需要访问的地址并非图片保存的地址,而是include.php(文件包含漏洞)的地址,并用GET传参将图片的地址传入?file=图片地址
,再用蚁剑连接 - 解释一下文件包含漏洞的原理
在php文件中include包含其他文件时,他本来想引用一个php文件,但是漏洞就是,他不会去识别是什么php文件,引用的文件都当做php来解析,解决了图片马不当做php解析的问题
getimagesize()-图片马
getimagesize()函数将测定任何GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM或WBMP图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通HTML文件中标记中的 height/width 文本字符串。
如果无法读取图片信息,则会被认定为非真实图像,要绕过这个函数检测实际上和利用图片马上传即可
exif_imagetype()-图片马
exif_imagetype()读取一个图像的第一个字节并检查其后缀名。
返回值与getimage()函数返回的索引2相同,但是速度比getimage快得多。需要开启php_exif模块
如果无法读取图片信息,则会被认定为非真实图像,要绕过这个函数检测实际上和利用图片马上传即可
二次渲染绕过
- 二次渲染原理
二次渲染就是根据用户上传的图片,重新生成一个新的图片,保存新的图片,删除原来上传的图片,比如根据用户上传的不同大小的图片,渲染成符合条件的大小固定的图片 - 绕过原理
在二次渲染中,图片有增加部分,有减少部分,有不变部分,有可能我们在图片中写入的木马会被渲染掉,所有我们先上传一张图片,再将上传后渲染过的图片保存下来,对比渲染前后的编码变化,将木马写在不变部分,再次上传图片,利用文件包含漏洞,即可获得WebShell - 注意
这种方式适用于git格式,其他方式过于复杂,暂时不做了解,同时,也需要一个可以将木马以二进制形式写入图片的软件
条件竞争绕过
原理
有些网站的服务器会先将上传的文件保存下来,再进行后缀或文件内容的对比,如果符合条件,则对文件进行重命名,如果不符合,则会删除文件.
但文件的保存和删除还是有间隔的,如果我们能在删除之前访问网页,就可以成功执行上传代码
ps:php中unlike()
是用于删除函数的,如果服务器是先重命名再判断,就无法找到提交的路径了保存一句话木马
由原理可知,非法的文件在上传后会被删除,哪怕我们在用一句话木马在间隔中访问到了WebShell,之后还是会被删除,所以我们必须想办法使木马保存在服务器里
所以我们将一句话木马改为<?php fputs(fopen('shell2.php','w'),'<?php @eval($_POST["aa"])?>'); ?>
解释:fputs(参1,参2,参3)
函数的作用是将参2('<?php @eval($_POST["aa"])?>'
)的内容写进参1(fopen('shell2.php','w')
)。参3可选,规定要了写入的最大字节数。fopen(参1,参2)
这是一个之前学过的函数,不过多解释,这里的作用是用来创建新文件,保存一句话木马
注意
我们上传的文件会被删除,但只要我们访问到了网站,就会自动保存shell2.php
,所以我们实际最终获取WebShell的地址是在shell2.php
,这里注意上传文件名(shell,php
)和文件内创建的文件(shell2.php
)不能重名,不然无法创建Burp重放
文件的保存和删除的间隔太短了,所以我们使用Burp抓包软件进行不停放包- 先上传文件,再将抓到的包发到intruder(攻击器)
- payload set中设置null payloads
- payload选项选择无限重发(continue indefinitely)
脚本访问
手动刷新浏览器太慢了,写个python脚本来访问,输出访问成功,代表代码成功执行,再用蚁剑连接1
2
3
4
5
6
7import requests
url = "上传文件的地址"
while True:
html = requests.get(url)
if html.status_code == 200:
print("访问成功")
break
条件竞争-图片马
- 文件解析漏洞
中间件Apache(阿帕奇)解析漏洞主要是因为低版本Apache默认一个文件可以有多个用.分割得后缀,当最右边的后缀无法识别则继续向左看,直到碰到合法后缀才进行解析.图片中,.7z
是无法被浏览器解析的,如shell.php.7z
如果存在文件解析漏洞,则会被当成php文件解析 - 原理
如果文件是先进行了后缀或文件内容的审查,合法的文件才进行保存,最后进行重命名.这样一来就无法上传.php
文件了,这时可以试着上传图片马,但是由前面可知,图片马需要用到文件包含或是文件解析漏洞,那么我们就要利用文件保存和重命名之间的时间差,访问还未被重命名的文件,这时因为文件解析漏洞的存在,就会把文件当成php来解析 - 流程
流程和前面的条件竞争没有什么区别,只是将上面的一句话木马写入图片,在用Burp重放,用python脚本访问
数组拼接漏洞
- explode()函数
会以一个字符串去分割另一个字符串,并将字符串分割后的结果存储成一个数组 - 原理
示例upload-labs pass 21,这关采用的是白名单后缀验证,将上传的文件根据.
作为分隔符,切割的内容以数组的形式保存,然后将数组的第一项与第n-1项拼接(n为数组总元素个数),成为最后的文件名,如果我们上传时,指定第一项为shell.php
,第二项为空,第三项为jpg,这样一来,进行检测时,会因为最后一项为jpg而绕过,最后拼接时,拼接的是第一项与第二项(3-1=2),即为shell.php+空
,为php文件