漏洞精粹 | 复盘利用 codeql '神器'挖掘 Ognl 漏洞
lipiwang 2024-11-21 17:40 4 浏览 0 评论
1 Ognl漏洞简单回顾
's2-032'、's2-033' 和 's2-057' 都是因为将恶意 的Ognl 的表达式直接存入了 'ActionMapping' 实例中,从而造成了 'Ognl' 命令注入。下面将介绍这三个漏洞中未经处理的参数:
1.1 s2-032
第139行代码为漏洞的起因,未对传入 'method' 变量进行过滤而直接存入了 'ActionMapping' 实例中。虽然在 'struts2' 整个参数的传递过程中使用了 'escapeHtml4' 会对参数进行处理,但是这种处理也是存在绕过方式,具体绕过就不在这里过多分析。
1.2 s2-033
's2-033' 是将 'actionMethod' 变量的值直接存进了 'ActionMapping' 实例中。
1.3 s2-037
037未经过处理的参数如上图所示。
恶意的 'Ognl' 表达式存入了 'ActionMapping' 实例中,在后续的执行流程中,'ActionProxy'实例取出'ActionMapping'中的值('getName()/getNameSpace()/getActionMethod()'),传给 'OgnlUtil' 实例执行 'Ognl' 表达式 ('compileAndExecute()') 。
2 Ognl漏洞挖掘通用模式
通过上文的分析,挖掘 'Ognl' 的相关漏洞可以分为两个步骤:
1. 找到一条路径,使得恶意构造的数据能够被当作 'Ognl' 表达式被解析;
2. 绕过 'Ognl' 沙箱(本文不会涉及 'Ognl' 的绕过,想要了解的可以查看参考链接)。
而对于步骤1,有两种方法可以快速定位到可能的漏洞点:
A:根据功能特性进行分析,比如 's2-032' 所涉及到的功能点为动态方法调用, 's2-033' 和 's2-037' 涉及到的功能点为 'REST' 插件,这两个功能都能直接使用'Ognl'表达式。
B:根据数据流进行分析,本方法是上一种方法的抽象表示,如果存在某个功能使用了 Ognl 表达式,那么必然会调用获取 Ognl 表达式的函数和执行 Ognl 表达式的函数。
第二种定位漏洞的方式刚好就是 codeql 数据流分析的使用场景,获取 Ognl 表达式的函数为 Source 点,而执行 Ognl 表达式的函数为 Sink 点。
3 codeql实战
'codeql' 是基于静态分析的,这也就是说 'codeql' 只从语义上分析了数据流的可达性,但至于是否可达并没有保证。同时,由于 'Java' 语言的某些运行时特性,也使得 'codeql' 在查找数据流的时候会存在遗漏的情况。笔者将解决这两类问题的办法称之为辅助截断数据流向和辅助建立数据流向,分别对应着 'DataFlow::Configuration' 类的 'isBarrier' 和 'isAdditionalFlowStep'。
3.1 建立数据流向
在建立数据流向的时候,包括但不仅限于如下的几类情况:
1. 使用继承 'DataFlow::Configuration' 的类来做污点追踪的时候,使用的是全局数据流分析,全局数据流分析指的是函数和函数之间的数据流分析。但并不是所有的代码都只存在全局数据流分析,可能还涉及到本地数据流,所以此时需要额外的建立本地数据流分析。
2. 在 'codeql' 进行污点标记的时候,只是标记了一定会被污染的情况,但有一些污点会因为函数调用的不确定性而具有不同的状态,例如下面的情况:
public void foo(String taint) {
this.field = taint;
}
public void bar() {
String x = this.field;
}
在这种情况下,如果 'foo()' 在 'bar()' 之前被调用,那么变量 'x' 就被污染了,反之则没有被污染。
除了以上两种情况外,还存在一些需要辅助建立数据流向的情况:
1. 'Java' 的需要运行时才能知道的数据流向,例如 'Java' 中的消息传递,包括但不限于 'wait/notify' 和 'rpc',对于这类情况需要具体的情况具体分析。
2. 在异常处理的时候,有些的Sink点只有在抛出异常的时候才会触发。
3.2 截断数据流向
强制建立数据流向的过程具有一定通用性的,但是对于截断数据流向的解决办法,则需要根据不同额代码做具体分析。接下来,以通过 'codeql' 查找出来的 'ScopeInterceptor.java'->'OgnlUtil.java' 这条路径为例进行分析,路径详情如下所示:
数据流向为:'ScopeInterceptor.java'-->'ValueStackShadowMap.java'-->'OgnlValueStack.java' --> 'OgnlUtil.java'。虽然 'codeql' 查找到了这条能够从 'Source' 到 'Sink' 的路径,但如本章开头提到的, 'codeql' 只是从语义上分析了代码,并不保证其可达。所以,在每个跨类调用的地方都需要人为的进行分析。笔者将调用关系简单画成了下图:
注:这个图表明在 'ScopeInterceptor' 类中的 'before' 方法会调用 'ValueStackShadowMap' 类中的方法;'ValueStackShadowMap' 类中的 'findValue' 方法会调用 'OgnlValueStack' 类中的方法;'OgnlValueStack' 类中的 'getValue' 方法会调用 'OgnlUtil' 类中的方法。
下面将分别分析 'before()'、'findValue()' 和 'getValue()' ,来判断这个路径是否可达。
1. 'before()'
上图红框中的代码为 'codeql' 提示的调用 'ValueStackShadowMap' 类中方法的代码。因为 'ValueStackShadowMap()' 继承于 'Map' 接口,所以这里 'Map' 类型的变量 'app' 调用 'get' 方法时 'codeql' 认为可能会调用到 'ValueStackShadowMap' 对象。但在实际的 'Struts2' 框架中,'ValueStackShadowMap'类是'jasperreports'插件中使用的数据类型,不存在在此调用的可能性。综上分析,这条数据流是不存在的,所以 'isBarrier' 如下所示:
override predicate isBarrier(DataFlow::Node node) {
exists(Method m | (m.hasName("get") or m.hasName("containsKey")) and
m.getDeclaringType().hasName("ValueStackShadowMap") and
node.getEnclosingCallable() = m
)
}
剩下的分析和 before 函数分析一致,这里就不再叙述了。
4 总结
早在2018年,Github 安全实验室就发布了如何通过 codeql 对已有的漏洞做 variant analysis 的文章。在今年的 Blackhat 上,360 Alpha Lab 也介绍了他们是如何将 codeql 利用到 chrome 漏洞挖掘上。虽然 codeql 是个功能十分强大的工具,但经过一段时间的使用,笔者认为如果使用者对漏洞原理和目标都有着比较深入的理解,那么'codeql' 将会是一款十分好用的神器。但是 'codeql' 本身的学习曲线还是比较陡峭的,首先它重新定义了一套查询语法,其次可能是因为它支持的语言过多,导致它的文档极其分散且简单,对新手十分不友好。最后,欢迎对 codeql 在漏洞挖掘场景使用感兴趣的朋友加入我们,一同探讨进步。
相关推荐
- linux实例之设置时区的方式有哪些
-
linux系统下的时间管理是一个复杂但精细的功能,而时区又是时间管理非常重要的一个辅助功能。时区解决了本地时间和UTC时间的差异,从而确保了linux系统下时间戳和时间的准确性和一致性。比如文件的时间...
- Linux set命令用法(linux cp命令的用法)
-
Linux中的set命令用于设置或显示系统环境变量。1.设置环境变量:-setVAR=value:设置环境变量VAR的值为value。-exportVAR:将已设置的环境变量VAR导出,使其...
- python环境怎么搭建?小白看完就会!简简单单
-
很多小伙伴安装了python不会搭建环境,看完这个你就会了Python可应用于多平台包括Linux和MacOSX。你可以通过终端窗口输入"python"命令来查看本地是否...
- Linux环境下如何设置多个交叉编译工具链?
-
常见的Linux操作系统都可以通过包管理器安装交叉编译工具链,比如Ubuntu环境下使用如下命令安装gcc交叉编译器:sudoapt-getinstallgcc-arm-linux-gnueab...
- JMeter环境变量配置技巧与注意事项
-
通过给JMeter配置环境变量,可以快捷的打开JMeter:打开终端。执行jmeter。配置环境变量的方法如下。Mac和Linux系统在~/.bashrc中加如下内容:export...
- C/C++|头文件、源文件分开写的源起及作用
-
1C/C++编译模式通常,在一个C++程序中,只包含两类文件——.cpp文件和.h文件。其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码;而.h文件则被称...
- linux中内部变量,环境变量,用户变量的区别
-
unixshell的变量分类在Shell中有三种变量:内部变量,环境变量,用户变量。内部变量:系统提供,不用定义,不能修改环境变量:系统提供,不用定义,可以修改,可以利用export将用户变量转为环...
- 在Linux中输入一行命令后究竟发生了什么?
-
Linux,这个开源的操作系统巨人,以其强大的命令行界面而闻名。无论你是初学者还是经验丰富的系统管理员,理解在Linux终端输入一条命令并按下回车后发生的事情,都是掌握Linux核心的关键。从表面上看...
- Nodejs安装、配置与快速入门(node. js安装)
-
Nodejs是现代JavaScript语言产生革命性变化的一个主要框架,它使得JavaScript从一门浏览器语言成为可以在服务器端运行、开发各种各样应用的通用语言。在不同的平台下,Nodejs的安装...
- Ollama使用指南【超全版】(olaplex使用方法图解)
-
一、Ollama快速入门Ollama是一个用于在本地运行大型语言模型的工具,下面将介绍如何在不同操作系统上安装和使用Ollama。官网:https://ollama.comGithub:http...
- linux移植(linux移植lvgl)
-
1uboot移植l移植linux之前需要先移植一个bootlader代码,主要用于启动linux内核,lLinux系统包括u-boot、内核、根文件系统(rootfs)l引导程序的主要作用将...
- Linux日常小技巧参数优化(linux参数调优)
-
Linux系统参数优化可以让系统更加稳定、高效、安全,提高系统的性能和使用体验。下面列出一些常见的Linux系统参数优化示例,包括修改默认配置、网络等多方面。1.修改默认配置1.1修改默认编辑器默...
- Linux系统编程—条件变量(linux 条件变量开销)
-
条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等...
- 面试题-Linux系统优化进阶学习(linux系统的优化)
-
一.基础必备优化:1.关闭SElinux2.FirewalldCenetOS7Iptables(C6)安全组(阿里云)3.网络管理服务||NetworkManager|network...
- 嵌入式Linux开发教程:Linux Shell
-
本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)