SQL注入
1、通读技巧:
SQL注入经常出现在登录页面、获取HTTP头(user-agent/client-ip等)、订单处理,登录页面的注入现在来说大多是发生在HTTP头里面的client-ip和xforward-for,一般用来记录登录的IP地址,另外在订单系统里面,由于订单涉及购物车等多个交互,所以经常会发生二次注入。在通读代码挖掘漏洞的时候可以着重关注这几个地方。
2、搜索关键词:
select from、mysql_connect、mysql_query、mysql_fetch_row、update、insert、delete
3、场景:
(1)数据库查询功能
<?php$hostName = "127.0.0.1";$usrName = "root";$passWord = "123456";$dbname = "test";$Id = $_GET['id'];$content = mysql_connect($hostName,$usrName,$passWord);mysql_select_db("test",$content);$sql = "SELECT * FROM user WHERE id = $Id";$result = mysql_query($sql) or die(mysql_error());while($row = mysql_fetch_array($result)){echo "ID:".$row['id']."<br>";echo "Username:".$row['usename']."<br>";echo "Passwd:".$row['passwd']."<br>";echo "email:".$row['Email']."<br>";}mysql_close($content);echo "<hr>";echo $sql;//查询数据;读写文件;执行命令
(2)用户登入功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="./login.php" method="post">
账号:<input type="text" name="username"><br >
密码:<input type="password" name="passwd"> <br >
<input type="submit" value="提交" name="login">
</form>
</body>
</html>
<?php
if (!isset($_POST['login'])){
echo "false";
}else{
$username = $_POST['username'];
$passwd = $_POST['passwd'];
$connect = mysql_connect("127.0.0.1","root","123456");
mysql_select_db("test",$connect);
$sql = "SELECT * FROM user WHERE username = '$username'";
$result = mysql_query($sql) or die ('执行MySQL语句失败!');
while($row = mysql_fetch_array($result)){
$db_username = $row['username'];
$db_passwd = $row['passwd'];
}
if($db_passwd == $passwd && $db_username == $username){
echo "success!";
}else{
echo "fale!";
}
}
(3)宽字节问题
a、描述:
在使用PHP连接MySQL的时候,当设置“setcharacter_set_client=gbk”时会导致一个编码转换的注入问题,也就是我们所熟悉的宽字节注入,当存在宽字节注入漏洞时,注入参数里带入%df%27,即可把程序中过滤的\(%5c)吃掉,造成绕过。
b、搜索关键词:
character_set_client=gbk,SET NAMES’gbk’,mysql_set_charsetmysql_set_charset,urldecode,rawurldecode
c、漏洞的解决方法推荐如下几种方法:
1)在执行查询之前先执行SET NAMES’gbk’,character_set_client=binary设置character_set_client为binary。
2)使用mysql_set_charset(’gbk’)设置编码,然后使用mysql_real_escape_string()函数被参数过滤。
3)使用pdo方式,在PHP5.3.6及以下版本需要设置setAttribute(PDO::ATTR_EMULATE_PREPARES,false);来禁用prepared statements的仿真效果。
如上几种方法更推荐第一和第三种。
场景:
<?php
if (!isset($_POST['login'])){
echo "false";
}else{
$username = $_POST['username'];
$passwd = $_POST['passwd'];
$connect = mysql_connect("127.0.0.1","root","123456");
mysql_select_db("test",$connect);
mysql_query("SET NAMES 'GBK'");//此命令使数据库以GBK形式解码;
$sql = "SELECT * FROM user WHERE username = '$username'";
$result = mysql_query($sql) or die ('执行MySQL语句失败!');
while($row = mysql_fetch_array($result)){
$db_username = $row['username'];
$db_passwd = $row['passwd'];
}
if($db_passwd == $passwd && $db_username == $username){
echo "success!";
}else{
echo "fale!";
}
}
d、拓展
只要字符被进行转换就有可能产生漏洞,如果某处使用了urldecode或者rawurldecode函数,则会导致二次解码生成单引号而引发注入。原理是我们提交参数到WebServer时,WebServer会自动解码一次,假设目标程序开启了GPC,我们提交/1.php?id=1%2527,因为我们提交的参数里面没有单引号,所以第一次解码后的结果是id=1%27,%25解码的结果是%,如果程序里面使用了urldecode或者rawurldecode函数来解码id参数,则解码后的结果是id=1’单引号成功出现引发注入。
(4)二次注入
a、函数介绍
addslashes ( string $str ) : string
• 返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(‘)、双引号(“)、反斜线(\)与 NUL(NULL 字符)。
注册功能
<?php
header("content-type:text/html;charset=utf-8");
if(!empty($_POST['submit'])){
$id = addslashes($_POST['id']);
$username = addslashes($_POST['username']);
$passwd = addslashes($_POST['passwd']);
$email = addslashes($_POST['Email']);
$connect = mysql_connect("127.0.0.1","root","123456");
mysql_select_db("test",$connect);
$sql = "INSERT INTO user (id,username,passwd,email) VALUE ('$id','$username','$passwd','$email');";
$result = mysql_query($sql) or die("执行命令失败".mysql_error());
if($result){
echo "regist success!";
}else{
echo "regist fail!";
}
}else{
echo "not POST!";
}
?>
<form action="reg.php" method="POST">
ID: <input type="text" name="id"><br>
username: <input type="text" name="username"><br>
passwd: <input type="password" name="passwd"><br>
Email: <input type="text" name="Email"><br>
<input type="submit" name="submit" value="提交">
</form>
查询功能
<?php
header("content-type:text/html;charset=utf-8");
if(!empty($_POST['submit'])){
$id = $_POST['id'];
$connect = mysql_connect("127.0.0.1","root","123456");
mysql_select_db("test",$connect);
$sql1 = "SELECT * FROM user WHERE id = '$id'";
$result1 = mysql_query($sql1);
while($row1 = mysql_fetch_array($result1)){
$username = $row1['username'];
$sql2 = "SELECT * FROM user WHERE username = '$username';";//此处为二次注入利用语句
$result2 = mysql_query($sql2) or die(mysql_error());
while ($row2 = mysql_fetch_array($result2)){
echo "ID:".$row2['id']."<br>";
echo "Username:".$row2['username']."<br>";
echo "Passwd:".$row2['passwd']."<br>";
echo "email:".$row2['Email']."<br>";
}
}
}
?>
<form action="search.php" method="POST">
search ID :<input type="text" name="id">
<input type="submit" name="submit" value="提交">
</form>
