前前言
本人的个人博客网址:www.QmSharing.space,所有的文章都可以在里面找到,欢迎各位大佬前来参观并留下宝贵的建议,大家一起学习一起成长 :-)
前言
本系列的初衷和 Pwnable.kr 系列一样, 是为了在最大程度保留游戏乐趣的前提下, 给卡壳的 Player 提供一定的提示, 帮助其完成该题并学习到分析的思路.
难度分析
本题虽然在难度评分上是属于中等偏上的难度, 但如果你之前有做过 PHP 0815 的话, 难度会稍微降低一定(毕竟注入点好找了). 但本题难在考察了一种稍微特殊的 SQL 盲注, 需要 Player 有一定的知识面, 并有较好的 Payload 构造和脚本编写能力(当然, 你想花个几小时手工注入, 我也不拦着你 ;-) ).
分析
本题的目的是通过各种方式得到管理员的密码, 然后提交正确的密码. 通过对于题目名字的分析, 大概可以猜到这应该是个注入题, 但本题只给了部分的核心代码:
# 这个函数可以忽略, 就是连接数据库用的
function addslash2_get_db() { }
function addslash2_sort($orderby, $dir)
{
# 连接数据库用
if (false === ($db = addslash2_get_db())) {
return false;
}
static $whitelist = array(1, 3, 4, 5);
static $names = array(1 => 'Username', 3 => 'Apples', 4 => 'Bananas', 5 => 'Cherries');
# 这个变量指定排序方向, 这个白名单函数被隐藏了
$dir = GDO::getWhitelistedDirS($dir, 'DESC');
# 看起来像是用了白名单噢! 怎么办!
if (!in_array($orderby, $whitelist)) {
return htmlDisplayError('Error 1010101: Not in whitelist.');
}
# 还有 escape, 好像很严格呢...
$orderby = $db->escape($orderby);
# 直接拼接 SQL 语句, 啊哈, 还限制了显示个数
$query = "SELECT * FROM users ORDER BY $orderby $dir LIMIT 10";
# ... 显示结果
}
如果简单地审计一下, 好像输入都被严格过滤过, 而且还是使用了白名单这种安全的方法. 不过, 这题给我的感觉好像是前面的题目的综合(如果你和我一样是按 PHP 分类顺序做下来的话). 如果你做过 PHP 0815, 你会轻易地发现, 这个 in_array 的使用好像没有设置为严格模式, 更要命的是, 它是和 int 类型进行比较(这个问题可以参考我的 PHP 0815 的文章). 这样的话, 我可以判断出这是一个注入点(因为我只要输入任意的白名单数字+一个非数字就能绕过 in_array, 比如 "1 -- "), 你输入后会发现其实这个数据库里有 21 行.
有些人可能做过 PHP 0815, 然后轻易地发现这个漏洞, 但他会说, 这个 $orderby 还被 escape 过, 怎么还存在注入呢? 如果你做过 No Escape 这题, 你会知道 mysqli_real_escape_string 仅过滤个别特殊字符, 但这个函数无法防御数字型注入和类似这种 order by 注入, 因此你只要不用任何引号, 其他的注释符号(-- 和 #)都是能正常使用的.
有人可能已经发行了这个注入点, 并且成功注入了, 但却不知道下一步该怎么做? 这其实也是本题的一个难点, 因为 order by 的特殊性(它基本只能放在语句末尾), 导致无法使用常用的 union select 大法, 而且很多的注入方法也会失效. 但也并不是无法注入的, 既然我们不能 "明注", 我们可以盲注啊. 这里提示一下, order by 能接 if 或 case 语句, 然后你就可以根据不同的结果, 控制显示的结果从而猜解出答案. 再提示下去, 答案就出来了, 如果你还是不懂, 可以在留言提出你的问题, 我看到后会尽快解答.
答案
解答步骤和 Writeup 可以在我的 Github 中找到: JackoQm's Github: order_by_query
注: 本题还有小彩蛋, 还是挺有意思的, 不要过错哦 : )
网友评论