test

【代码审计】常见WEB漏洞代码层原理分析及利用方式——SQL注入篇

Sw1t0range:

1.SQL注入




1.1 普通注入


  普通注入分为int型和string型,在string型注入中需要使用单或双引号闭合。




1.1.1 整型注入


  测试代码:


<?php
header("Content-type:text/html;charset=utf-8"); 
$uid = $_GET['id']; 
$sql = "select * from test where id=".$uid; 
$conn = mysql_connect('localhost', 'root', '123456'); 
mysql_select_db("sw1t0", $conn); 
$result = mysql_query($sql, $conn); 
print_r ('执行SQL语句:'.$sql.'<br />结果:'); 
print_r (mysql_fetch_row($result)); 
?> 


  测试代码中GET id参数中存在SQL注入漏洞(整型注入),测试如下



  原本的SQL注入语句已通过查询出错的方式结合union联合查询到了当前数据库的相关信息。需要注意的是查询出错和语法出错是两回事,加单引号和双引号是用来闭合语句重新构造的,像这个例子如果是通过加引号的方式,那样得到的报错是语法错误,数据库根本不会解析执行,同样后半句的联合查询也不会执行。在此一定要把sql注入的原理理解清楚。


  数据库操作存在一些关键字,php代码审计的时候可以通过查找这些关键字来定向挖掘SQL注入漏洞:select from、mysql_connect、mysql_query、mysql_fetch_row等。




1.2 编码注入


  编码处理的函数也是存在问题的,通过输入转码函数不兼容的特殊字符,可以导致输出的字符变成有害数据。SQL注入里最常见的编码注入是MYSQL宽字节以及urldecode/rawurldecode函数导致的。




1.2.1 宽字节注入


  当设置“set character_set_client=gbk”时会导致一个编码转换的注入问题,这就是宽字节注入:注入参数里带入%df%27,即可把程序中过滤出的\(%5c)吃掉。


  假设


/1.php?id=1


  里面的id参数存在宽字节注入漏洞,当按照普通字符型注入提交


/1.php?id=-1' and  1=1%23


  时,MYSQL实际运行的SQL语句是


select * from user where id='-1\' and 1=1#' 


  因为提交的单引号被转义导致没有闭合前面的单引号,因此是没有注入成功的。但是如果提交


/1.php?id=-1%df' and 1=1%23


  时,这时候MYSQL实际执行的SQL语句是


select * from user where id='-1運' and 1=1#' 


  这是由于单引号被自动转义成\'后,前面的%df和转义字符\反斜杠(%5c)组合成了%df%5c,也就是“運”字,这时候后面的单引号还在,成功闭合了前面的单引号。


  出现这个漏洞的原因是在PHP连接MySQL的时候执行了“set character_set_client=gbk”的设置,告诉MySQL服务器:客户端来源数据编码是GBK,然后MySQL服务器对查询语句进行GBK转码导致反斜杠\被%df吃掉,而一般都不直接这么设置。通常的设置方法是 SET NAMES 'gbk' ,等同于如下代码:


SET 
character_set_connection = 'gbk', 
character_set_results='gbk', 
character_set_client=gbk


  这同样也是存在漏洞的,官方建议使用mysql_set_charset方式来设置编码,然而它也只是调用了SET NAMES,所以效果也是一样的。不过mysql_set_charset调用SET NAMES之后还记录了当前的编码,留着给后面mysql_real_escape_string处理字符串时使用,所以在后面使用mysql_real_escape_string()函数来参数过滤可以解决这个漏洞。


  测试代码:


<?php
//header("Content-type:text/html;charset=utf-8"); 
$conn = mysql_connect('localhost', 'root', '123456'); 
mysql_select_db('sw1t0', $conn); 
mysql_query("SET NAMES 'gbk'", $conn); 
$uid = addslashes($_GET['id']); 
$sql = "select * from test where id='".$uid."'"; 
$result = mysql_query($sql, $conn); 
print_r ('执行SQL语句:'.$sql.'<br/>结果:'); 
print_r (mysql_fetch_row($result)); 
mysql_close(); 
?> 


  测试效果:



  因为编码问题所以存在汉字显示乱码的问题,但是可以看到SQL语句是正常执行了的,注入成功。


  对宽字符注入的挖掘只需搜索如下几个关键字即可:SET NAMES、character_set_client=gbk、mysql_set_charset('gbk') 




1.2.2 二次urldecode注入


  现在的web程序大多都会进行参数过滤,通常使用addslashes()、mysql_real_escape_string()、mysql_escape_string()函数或者开启GPC的方式来防止注入,也就是给单引号(')、(")、反斜杠(\)和NULL加上反斜杠转义。如果某次使用了urldecode或者rawurldecode函数,则会导致二次解码生成单引号而引发注入。


  原理是当提交参数到WebSever时,WebSever会自动解码一次,假设目标开启了GPC,提交


/test.php?id=1%2527 


  因为提交的参数里没有单引号,所以第一次解码后的结果是id=1%27,%25的解码结果是%,如果程序里使用了urldecode或者rawurldecode函数来解码id参数,则解码后的结果是id=1',单引号成功拼接近字符串,可能引发注入。


  测试代码:


<?php
header("Content-type:text/html;charset=utf-8"); 
$conn = mysql_connect('localhost', 'root', '123456'); 
mysql_select_db('sw1t0', $conn); 
$uid = addslashes($_GET['id']); 
$uid = urldecode($uid); 
$sql = "select * from test where id='".$uid."'"; 
$result = mysql_query($sql, $conn); 
print_r ('执行SQL语句:'.$sql.'<br/>结果:'); 
print_r (mysql_fetch_row($result)); 
mysql_close(); 
?> 


 测试效果:



  这种注入漏洞主要是由于urldecode使用不当导致的,因此可以通过搜索urldecode和rawurldecode函数来挖掘二次urldecode注入漏洞。




注:


  此笔记为代码审计一书的学习笔记,将我认为必须要了解和掌握的原理性的知识记录下来便于复习和巩固。同时本书中出现的错误着实不少,不论是文字叙述还是代码段都有,因此我建议大家去自己手动把这些例子都挨着敲一遍,根据报错就可以发现同时也加深对这些漏洞出现的原理的理解。这样以后自己做代码审计的时候举一反三,自己独立挖掘分析,而不是照葫芦画瓢。



评论

热度(2)