去年冬天,漏洞我在一个电商后台的注入优惠券模块里发现了一个参数,叫 couponId。漏洞前端传的注入是加密后的字符串,看着挺唬人。漏洞但抓包改了一下,注入把加密串换成纯数字 1001,漏洞服务器居然原样返回了另一张优惠券的注入详细信息。那一刻我就知道,漏洞这地方能捅出大篓子。注入
漏洞注入点这东西,漏洞说白了就是注入系统里那些“你以为它做了检查、其实它没做”的漏洞位置。它不一定是注入 SQL 注入那种老掉牙的东西,更多时候藏在接口参数、漏洞HTTP 头、甚至文件名的某个字符里。我见过一个文件上传功能,前端限制只能传 .jpg,后端也检查了扩展名。但如果你把文件名改成 test.jpg.php,中间件解析时按 php 执行——那个点号后面的 php 就是注入点。开发觉得“我检查了后缀”,可解析器不这么想。
找注入点跟拆炸弹差不多。你得先摸清楚数据从哪来、到哪去、中间经过谁的手。比如一个搜索框,用户输入 苹果,后端拼成 SELECT * FROM goods WHERE name LIKE '%苹果%'。那个单引号就是入口。但现在的系统没那么蠢,很多用了预编译。那注入点就转移了——转移到 ORDER BY 后面的字段名,或者 LIMIT 后面的数字。预编译管不了这些地方,因为表名、列名、排序方向没法参数化。我试过一个招聘网站,排序参数传 salary desc 正常,传 salary desc, (select sleep(5)) 直接卡了五秒。时间盲注,就藏在排序里。
还有一种注入点更隐蔽:HTTP 头。有些应用会把 User-Agent 或者 X-Forwarded-For 存进数据库做日志。你往 User-Agent 里塞个单引号,日志表插入时就可能出错。如果错误信息回显到页面上,那就能一步步把数据拖出来。我见过一个后台,登录失败时会记录 X-Forwarded-For 到审计表,而那个插入语句没过滤。改个头,直接报 SQL 语法错误。开发当时就傻了,说“这头也能注入?”
别只盯着输入框。JSON 里的嵌套字段、数组里的每个元素、甚至 cookie 里 base64 解码后的内容,都可能是入口。有个 API 接收 { "ids":[1,2,3]},后端把数组拼成 IN (1,2,3)。你把第三个元素改成 3) UNION SELECT password FROM users--,如果没做类型强制,整个查询就被改写了。数组里的每个元素都是独立注入点,很多人只测第一个。
我的习惯是:拿到一个请求,先把所有参数列出来,然后逐个替换成特殊字符——单引号、双引号、反斜杠、括号、分号、注释符。看响应有没有变化。没变化不代表安全,可能是盲注。这时候用时间函数或者布尔条件去猜。比如 id=1 and 1=1 和 id=1 and 1=2,页面返回内容一样?那就试 id=1 and sleep(3)。响应慢了,说明注入点存在。
找到注入点只是第一步。真正麻烦的是判断它能不能利用、能利用到什么程度。有的点只能读不能写,有的被 WAF 挡了关键字,有的权限低到只能查当前库。但只要有那么一个点没堵上,整个系统的数据就像放在漏水的桶里。你永远不知道下一个被拖库的会是谁。