SQL注入漏洞的分类
sqlmap中的注入类型说明
使用sqlmap
的-hh
可以查看到具体的操作说明
Techniques
:
这些选项可用于调整特定SQL注入技术的测试。
--technique=TECH..
用于选择要使用的SQL注入技术(默认为"BEUSTQ")。
--time-sec=TIMESEC
用于设置延迟数据库管理系统(DBMS)响应的时间(默认为5秒)。
--union-cols=UCOLS
用于指定要测试的联合查询SQL注入的列范围。
--union-char=UCHAR
用于指定用于列数枚举的字符。
--union-from=UFROM
用于指定联合查询SQL注入中FROM部分要使用的表。
--dns-domain=DNS..
用于域名用于DNS渗透攻击。
--second-url=SEC..
用于搜索第二次响应的结果页面的URL。
--second-req=SEC..
用于从文件中加载第二次HTTP请求。
这些选项能够让用户配置SQL
注入测试的各种参数和注入类型,以便更准确的测试SQL
注入漏洞。
使用sqlmap进行sql注入测试
下面sqlmap
自动测试的类型有在图中标注说明:
通过请求类型区分
-
GET
注入
注入的payload
直接放在请求的url
里,通常是有长度限制的,中文需要URL
编码; -
POST
注入
payload
是放在body
里面,没有长度限制; -
COOKIE
注入
放在请求头信息里面,提交payload
的时候服务端会从请求头信息读取; -
Referrer
注入
也是放在请求头信息里面,在payload
里添加SQL语句向服务端发送请求,再通过返回判断是否存在注入点; -
XFF
注入
在请求头信息里面,全称为X-Forwarded-For
简称XFF
头,也是直接将payload
放在请求头信息里,服务端会从客户端提交的信息来读取。
通常可以使用下面的payload进行尝试:
X-Forwarded-for: 127.0.0.1' and 1=1#
通过注入参数数据类型区分
int
整型
SELECT * FROM sys_users WHERE id = 1
string
字符串型
SELECT * FROM sys_users WHERE name = "admin"
like
搜索型(模糊匹配)
SELECT * FROM sys_users WHERE email LIKE "%@qq.com%"
SQL常规的漏洞利用思路
- 第一步肯定是寻找注入点,可使用批量测试扫描工具进行,如上面的
sqlmap
; - 获取到注入点之后,开始尝试进一步获得数据库用户名、数据库名称、当前数据库用户权限、服务器操作系统信息、数据库版本等信息;
- 猜解关键数据库表和它的重要字段跟内容,如存放管理员账号的表名、字段名等信息,再进一步获取到数据库管理员账号密码;
- 获取到用户信息,寻找后台登陆测试,再进一步利用。
手工注入思路
- 也是和常规思路差不多,第一步首先判断是否存在注入点,存在注入点的话继续确认是字符型还是数字型的注入参数;
- 猜解查询语句中的字段数,使用
order by N
; - 确定显示的字段顺序;
- 获取当前数据库;
- 获取数据库中的表;
- 继续获取表中的字段名;
- 查询到账户的数据。
这里根据上面的sqlmap
使用说明的类型来逐个介绍sql
注入的类型
关于dvwa
靶场的php
源码中的sql
注入漏洞,可以先了解一下php
中调用mysql
的函数,以下是参考链接: php连接和操作mysql数据库超全详解!!!
布尔型盲注
dvwa
对应的布尔型盲注的前端页面是这样的:
布尔型盲注漏洞的dvwa
参考代码如下,当然这是low级别的:
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// 获取Submit提交输入框的内容
$id = $_GET[ 'id' ];//结合下图抓取的数据包,这里的id是用户的输入
// 与数据库交互,把上面的id获取到再拼接到sql语句中来
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // mysqli_query通常使用这个函数来执行sql语句
// 获取结果条数使用mysqli_num_rows函数
$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// 如果返回的条数大于零,则打印结果信息
echo '<pre>User ID exists in the database.</pre>';
}
else {
// 否则表示失败
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// 返回这个消息给用户
echo '<pre>User ID is MISSING from the database.</pre>';
}
//这下面的代码则是php连接数据库的常规流程,关闭数据库连接的操作
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
结合抓包工具分析这个页面里头的细节操作
通过上面的分析可以指导id
这个变量的值是用户输入的,如果在数据库里存在则打印存在的信息给用户,否则打印不存在的信息给用户。这种只返回指定信息的,不显示任何数据库内容的场景,如果这里存在sql
注入,则称为盲注,其中又细分成布尔型盲注和延时注入(盲注的一种)。
测试盲注
一种,使用1' and '1'='1
和1' and '1'='2
判断两者返回的页面是否一样,来检测此处是否存在注入点;
第二种,使用sleep
函数来测试是否存在注入点
盲注经验技巧
在测试或者已经发现存在sql
盲注点的时候,可以结合php
的另外几个函数进一步渗透测试,如下:
if(1,2,3)
函数,如函数声明,它有三个参数,第一个是表达式、第二个是若表达式为真则显示,第三个参数是表达式不成立则显示;
-substring(1,2,3)
函数,第一个参数是字符串、第二个是开始截取的位置、第三个参数是截取该字符串的长度;database()
函数,直接使用
上面的三个函数既可以单独使用,也能结合一起使用。
报错型注入
当web
程序在执行数据库语句遇到语法不对的场景时,会给客户回显报错的信息,比如
1064 - 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 ''' at line 1
数据库报错信息存在的意义是为了让开发人员在调试程序的时候可以快速定位问题。
在php
执行sql
语句的时候一般会采用异常处理函数来捕获错误信息。
例如:
mysqli_error()
函数mysqli_connect_error()
函数
调用方式如下图,下面贴一下dvwa
中关于sql
注入的源码:
报错注入攻击方法
比较常见的是在web
测试点输入一个“ ‘ ”
单引号字符来测试站点是否存在报错注入。
下面举一个简单的例子,查看当前数据库名:
SELECT first_name, last_name FROM users WHERE user_id = '1' and info()--
//这里会报错,如下图,说当前库不存在info这个函数,以这种方式可以推断出当前数据库名
报错注入攻击深入
通过下面的链接,我是本地测试环境,来进一步对报错注入漏洞站点进行深入
http://www.dvwa.com/vulnerabilities/sqli/?id=1%27%20and%20(updatexml(1,concat(0x7e,(select%20user()),0x7e),1))--+&Submit=Submit#
使用updatexml()
函数,通过函数名可以猜到,它的作用是update
修改xml
数据,它有三个参数,分别是文件对象名称、文件路径以及修改的值。函数声明如下:
updatexml(XML_document,XPath_string,new_value)
如上面的测试图所示,当路径出现语法错误的时候mysql
就会报错,这里的0x7e
表示" ~ "
字符,在xpath
语法中是错误的,所以导致报错。
除了上面的updatexml()
函数之外,还有以下函数可以在sql
报错注入的时候利用:
floor()
extractvalue()
geometrycollection()
multipoint()
polygon()
multipolygon()
linestring()
multilinestring()
exp()
报错型注入攻击的一般流程
- 获取到报错注入点,通过该注入点得到库名;
- 接下来获取mysql的账号密码;
- 通过mysql的内置库进一步获取表名;
- 基于上面的步骤继续获取字段名;
- 然后再继续获取值,也就是内容信息;
堆叠注入
堆叠注入攻击是利用了mysql
堆叠查询可查询多条sql
语句的特点来构造payload
对注入点进行攻击。
在mysql
中通常是通过mysqli_multi_query()
以及mysql_multi_query()
这两个函数来执行一个或多个针对数据库的查询。
堆叠注入的危害是很大的,可以任意使用增删改查的语句,例如删除数据库、修改数据库、添加数据库等高危操作。
时间注入攻击
时间注入属于盲注的一种。在mysql
中可以利用sleep()
函数来进行时间注入。它的参数值是整型,sleep(20)
就表示数据库延时20秒再返回内容。在注入点测试的时候可以使用
' and sleep(20)
来观察网页响应时间,由此来判断是否存在sql
注入。
一般实际渗透场景中,通过一条简单的if
判断语句来判断是否存在时间注入
select if(2>1,sleep(10),0) 2>1
#通常都是这么使用,用来判断数据库名的长度或者关键字段的长度等等
UNION 联合注入攻击
SQL
联合查询的操作符是UNION
,它既可以单张表联合查询,也支持多表联合查询,在SQL
注入里面通常的应用场景是多表联合查询,多表联合查询的关键字是UNION SELECT
,操作符上下两个结果集的列数必须相等,否则会报错。
举一个例子(是在搭载了dvwa
靶场的phpadmin
里面操作的),查询guestbook
表和users
表的字段信息,其中guestbook
表有三个字段,而users的字段数是八个,如果直接SELECT *
,它会因为字段数不等导致报错,如下:
SELECT * FROM `guestbook` WHERE comment_id = 1 UNION SELECT * FROM `users`;
正确的写法是:
SELECT * FROM `guestbook` WHERE comment_id = 1 UNION SELECT 1,2,3 FROM `users`;
在SQL注入攻击的应用场景下,上面的这些1,2,3
字段换成具体的字段名称或者换成SQL自带的函数,可以获取到想要的数据,如下:
SELECT * FROM `guestbook` WHERE comment_id = 1 UNION SELECT database(),user(),version() FROM `users`;