去年帮朋友看一个站,渗透登录框输个 ' OR 1=1-- 直接进了后台。绕过他脸都白了,渗透问我是绕过不是数据库被人拖了。我说不是渗透,是绕过前端把 SQL 拼接当字符串处理,压根没过滤。渗透这事让我意识到,绕过前端渗透测试里,渗透绕过手段往往比漏洞本身更值得聊——因为大部分开发者防的绕过是"正常攻击",而不是渗透"绕过去的攻击"。
JS 渗透的绕过第一道墙通常是前端校验。很多表单提交前会跑一段正则,渗透比如邮箱格式、绕过手机号、渗透密码强度。看起来挺唬人,但打开 DevTools 把那段校验函数删掉,或者直接把 disabled 属性摘了,表单照样提交。更隐蔽的做法是改 maxlength,比如密码框限制 20 位,你改成 200,后端如果没做长度校验,超长 payload 就能塞进去。我见过一个上传接口,前端只允许 .jpg,但把 accept 属性删掉后传 .php 照样成功——后端只信了前端传来的 MIME 类型。
XSS 的绕过更依赖对 JS 执行环境的理解。常规的 <script>alert(1)</script> 被过滤了,不代表没戏。试试 <img src=x onerror=alert(1)>,或者用 eval 拼字符串:eval('al'+'ert(1)')。如果连 eval 都被禁,还有 setTimeout('alert(1)',0)。最阴的是利用 HTML 实体编码,比如 alert(1),浏览器解析时自动还原。我实测过一个 CMS,过滤了 alert 关键字,但没过滤 confirm,直接 confirm(1) 就弹窗了。绕过思路就一条:找到过滤规则没覆盖到的等价执行路径。
CSRF 的绕过经常被低估。很多人以为加个 Referer 校验就安全了,但 Referer 可以伪造——用 data: 协议或者 about:blank 页面发请求,Referer 头直接是空的。有些站校验 Origin,那就用 window.open 配合 document.write 构造一个同源页面再发请求。更绝的是 JSONP 劫持:如果接口返回 callback=xxx,你注册一个全局函数 xxx,用 <script src="接口地址"> 就能拿到数据——根本不需要跨域头。
文件上传的绕过花样最多。前端校验后缀?抓包改 filename="shell.php.jpg",有些后端只取第一个点之前的部分。或者用 %00 截断:shell.php%00.jpg,老版本 PHP 会直接当 shell.php 处理。MIME 类型校验?把 Content-Type 改成 image/jpeg 就行。最狠的是竞争条件:上传一个 .htaccess 文件,里面写 AddType application/x-httpd-php .jpg,然后传 .jpg 木马——前提是能覆盖 .htaccess 且服务器允许。我见过一个站,上传目录可执行,但文件名被随机化了,结果通过 .htaccess 把随机名也解析成 PHP,直接 getshell。
绕过 WAF 是另一层博弈。常见手法包括大小写混写(SeLeCt)、内联注释(/*!50000select*/)、URL 编码二次编码(%2527)、参数污染(id=1&id=2)。有次遇到一个 WAF 拦截 union select,但把 union 换成 union%0a 就过了——它只匹配了空格。还有用 + 代替空格、用 /**/ 代替空格。更骚的是分块传输:Transfer-Encoding: chunked 把 payload 拆成多段,WAF 拼不回去就放行了。这些技巧没有固定套路,得看目标 WAF 的规则库版本。
说到底,JS 渗透绕过的核心不是工具,是对解析差异的敏感度。浏览器怎么解析、后端怎么解析、WAF 怎么解析——三者不一致的地方就是突破口。我习惯在测试时开两个窗口:一个正常操作,一个抓包改参数,对比响应差异。有时候一个 %20 换成 + 就能从 403 变 200。这行没有银弹,只有不断试错和观察。