本文使用的版本

image-20230920125230345

Pass-01

这一关只在前端对文件进行检查

上传前先将木马文件更改后缀为jpg,然后使用burp拦截

image-20230906145315039

然后将1.jpg改名为1.php后上传

image-20230906145428980

使用蚁剑连接

image-20230906145549715

Pass-02

先清除上传文件

这一关是MIME类型绕过,只要将Content-Type的参数改为image/jpeg绕过

image-20230906150227360

使用蚁剑连接成功

Pass-03

先清除上传文件

先上传1.php,发现被拦截了

image-20230906150726144

可以被php解析的文件后缀

php3,php5,pht,phtml,phps

把文件后缀改为php3后上传,需要注意的是,这一关把上传的文件重命名了,我们再burp拦截请求即可看到新的文件名。

image-20230906152033143

最后使用蚁剑连接成功

image-20230906151837254

Pass-04

测试了很多后缀都不行,最后在后缀后再加一个解释器无法识别的后缀,成功上传

image-20230906154346478

使用蚁剑连接成功

image-20230906154429830

这一关真正的源码与源码提示不一致!

Pass-05

成功上传a.txt,说明这一关并没有对文件头和文件类型做检查,这样就要再后缀名上下手了

image-20230906160037654

上传a.php.j

image-20230906160159573

可以看到文件被重命名了,php后缀被删除

image-20230906160254750

分析源码,发现没有将后缀转换为小写,随即上传1.PHP

image-20230916110556922

拦截到访问该图片的请求,直接用蚁剑连接成功。

image-20230916110715856

Pass-06

观察源码,发现没有对空格过滤,随即上传成功

image-20230916112415911

Pass-07

观察源码,发现源码没有对文件进行重命名,随即使用多重后缀上传

image-20230916114216844

Pass-08

观察源码发现没有过滤::DATA,随即上传

image-20230916115318935

Pass-09

deldot() 函数从末尾向前检测,检测到第一个点后,会继续向前检测,但遇到空格或字符会停下来

image-20230918152032038

程序去掉点后的文件名为1.php. ,保存后文件名变为1.php

Pass-10

上传1.php测试,上传成功

image-20230918155317916

但是php后缀被替换为空值

image-20230918155249876

随即双写绕过

image-20230918155523050

文件也正常保存了

image-20230918155554681

Pass-11

观察源代码

image-20230918160321712

注意到:

strrpos函数计算.最后一次出现的位置,substr截取.之后的字符串

再通过in_array函数判断.后的字符串是否在白名单里,只有在白名单里的文件后缀才能通过,程序最后还会对文件进行重命名

注意到get传参save_path,可使用%00隔断,意思就是直接使用get去传文件名,因为文件的最终名称拼接而成的,改变save_path参数加上%00即可控制文件名称,

image-20230918164336123

%00的作用是阻止函数继续读取

Pass-12

这题和上一题一样,不过GET传值变成了POST传值

image-20230918170831165

需要注意的是,需要将该路径进行url解码后才能发出,不然会上传失败

image-20230918171141208

Pass-13

JPG

该pass检查文件头,用copy命令整合的jpg图片马可以轻松上传,

image-20230918172958343

结合靶场提供的文件包含测试,可以看到恶意代码被执行了

GIF

image-20230918182207420

Pass-14

同上即可

Pass-15

同上即可

Pass-16

这一关对图片进行了二次渲染,前面pass的图片马中的恶意代码会被覆盖掉,所以必须将恶意代码放在不会被覆盖的位置

先上传原图,然后将二次渲染的图保存下来,使用010与原图比较,在蓝色的匹配区域插入恶意代码

image-20230918190749268

上传更改后的文件

image-20230918190947760

上传后尝试包含

image-20230918190838273

Pass-17

对该pass进行源码审计,发现不论文件名是什么都会在upload目录下存在过,这是典型的条件竞争

新建一个测试器上传1.php,内容是保存一个新的脚本文件,因为旧的文件只会存在很短的时间。

然后随便添加一个get传参,名称无所谓,参数也无所谓,只要次数足够。

image-20230920101615338

再新建一个测试访问1.php,目的是执行1.php

然后随便添加一个get传参,名称无所谓,参数也无所谓,只要次数足够。当这个返回值出现200时,说明执行成功,届时就可以访问phpinfo.php

image-20230920102427863

将载荷都设置成下图所示

image-20230920102622843

依次开启测试,查看访问1.php的测试,我们发现已经返回200,说明phpinfo.php已经成功创建。

image-20230920102819204

访问测试

image-20230920102900994

Pass-18

上传图片马包含可以过关

同样的,也可以通过条件竞争

和上一个pass一样的方法,但是源码对文件名和文件头都做了检查,我们取一个无法解析的文件名phpinfo.php.7z

image-20230920124307328

需要注意的是,本pass上传的文件并不在upload目录下,而是在网站根目录

image-20230920124524925

查看网站根目录,发现phpinfo.php被创建

image-20230920124714389

Pass-19

需要Linux环境,懒得配🤤

Pass-20

审计代码,发现可以利用数组绕过

image-20230920133710856

如果传入数组,$file = explode('.', strtolower($file));会失去作用,同时$ext = end($file);的作用是返回数组的最后一位也可以随意绕过,同时可将$file[count($file) - 1]为空

image-20230920134126963

如上图上传后,因为$file[count($file) - 1]为空,所以$file_name会等于phpinfo.php.,但move_uploaded_file()在保存时会忽略.,所以最后的文件名称为phpinfo.php

image-20230920134543570

THE END