胖哈勃归来-WP

看了一些其他人的wp, 没有一个人提到这个特性的根本原因其实是 perl 的数组特性而不是 CGI 或是 param 函数的 bug :-(, 想到了 ph 师傅说的 “不求甚解才是大多数人进步的阻力”, 共勉

在做seccon sqlsrf的时候注意到的一个奇怪的现象, 传入user=1'union select '58474452dda5c2bdc1f6869ace2ae9e3'--+&user=123 会返回 database error, 当时觉得很奇怪, 但是因为可以注出admin密码就没管这么多

后来 rr 说 sqlsrf 有用 Perl 特性的解法, 还粗略看了眼 cgi 的文档, 也没想太多, 直到这道题才算把之前的疑惑解了

回到题目, 这道题的源码就是 sqlsrf 的源码去掉一些不必要的部分, 所以核心的流程也差不多, 简单来说就是读取用户post的 user 带入 sql 查询得到密码, 与用户传入的 pass MD5 加密后的值进行比较, 如果相等则把用户的 user 加入 session 标记为登录

关键点在于把用户输入的 user 当做用户名传入session, 也就是说如果用注入的方法登录: user='union select '21232f297a57a5a743894a0e4a801fc3'--+, 那么session中存储的用户名就是'union select '21232f297a57a5a743894a0e4a801fc3'--+

那么我们要做的事情就是:让 perl 认为第一处拼接 sql 语句中的$q->param('user')是我们构造的注入语句:

让 perl 认为第二处传入session语句中的$q->param('user')admin:

这看上去是不可能的, 因为两次调用的是同样的东西, 不能通过传统的 HPP 来做, 当然这确实是不可能的

这时想到了开头那个奇怪的错误, 虽然 perl 对同名参数只会取前一个, 但是明显后一个的user=123造成了一些微小的变化, 使得最后报错

于是可以确定这里是 perl 在某些场景用 param 取得参数的时候会有问题

google之后得到了答案: 这个

如果 param 函数被用在一个 list 上下文中, 那么他会返回一个包含了所有取得值的数组, 并根据这个数据重新生成哈希数组

例如

如果传入name=John&name=authorized&name=1 就会变成这样

归根结底这是 perl 数组的特性, 回到题目的这里

其实就类似这样一个 list

那么我们传入user=auu&user=autheduser&user=admin后, 会变成这样:

那么这里, 我们调用 %sess_info[“autheuser”], 取得的是哪一个? 来验证一下:

得到admin

so 最后的payload: