红客解密程序 暗网编程
27.6K subscribers
966 photos
12 videos
1 file
56 links
渗透测试,#删库,数据删除 拿数据库 木马注入 破解,提权,Dns动持
Download Telegram
Java反序列 Jdk7u21 Payload

在分析代码之前,我们先来了解一些相关知识,有助于后续理解


javassist
javassist :Java字节码操作库,提供了在运行时操作Java字节码的方法,如在已有 Class 中动态修改和插入Java代码,示例:在 Cat 类中添加包含恶意代码的 static block

生成的.class,反编译后的源码图2

在Jdk7u21 的payload 中,使用了javassist 来构造包含恶意代码的class


Java static initializer
Java Class 中定义的static 代码块被称为 staticinitializer,在class 初始化(initialized) 时会执行该语句块

这里需要重点关注一下ClassLoader.defineClass()方法运行后,并不会执行 static block,而Class.newInstance()会执行,这两个地方会涉及到Jdk7u21 payload 恶意代码的具体执行点
"f5a5a608"的hashCode为0
Java Object 中定义了hashCode()方法,返回一个hash 值,当两个对象equals 时,hashCode需要相同

String 类重写了该方法

有一个特殊的字符串"f5a5a608",hashCode的值为 0,在构造 Jdk7u21 payload 的过程中利用到了这一点

Dynamic Proxy
在ysoserial 的代码中,大量使用了到动态代理机制来构造payload,我们来简单了解一下

当需要增加或者修改某些已存在class的功能时,会使用动态代理机制,通过创建 proxyobject 来代理实际的对象。主要涉及接口为InvocationHandler

接口中只定义了一个方法invoke(),所有 proxy object 的方法调用都会转换为调用 invoke()方法,调用方法和参数通过method和 args来传递

来看一个代理Map 接口的例子,会在所有方法的执行之前打印start 、执行完成后打印finish
Payload分析 & 构造

TemplatesImpl
在利用payload 中,TemplatesImpl类主要的作用为:

使用_bytecodes成员变量存储恶意字节码( 恶意class=> byte array )

提供加载恶意字节码并触发执行的函数,加载在defineTransletClasses()方法中,方法触发为getOutputProperties()或 newTransformer()

我们来具体看一下,该类位于com.sun.org.apache.xalan.internal.xsltc.trax包中,用于xml document 的处理和转换,定义

TemplatesImpl 类实现了Templates和 Serializable两个接口

其中Templates接口定义如下,包含了两个方法,即之前提到触发恶意代码执行所的方法,在TemplatesImpl类中有一个private 方法 defineTransletClasses()

在方法中,调用了ClassLoader.defineClass()方法,参数为实例变量_bytecodes内的元素,该方法会将字节数组转换为Class,并加载

也就是说,通过设置_bytecodes的内容 ,调用 defineTransletClasses() 方法即可加载指定的 Class。

在代码中,一共有三个地方调用了这个方法

getTransletClasses()

getTransletIndex()

getTransletInstance()

在Java static initializer 部分提到 ClassLoader.defineClass() 并不会执行 static 代码块,所以前两个方法不满足条件,再看一下 getTransletInstance()方法
漏洞利用
根据上一节对漏洞原因的分析,我们利用漏洞绕过eBPF verifier机制后,就可以执行任意eBPF支持的指令,当然最直接的就是读写任意内存。漏洞利用步骤如下:

1.构造eBPF指令,利用ALU指令缺陷,绕过eBPF verifier机制;

2.构造eBPF指令,读取内核栈基址;

3.根据泄漏的SP地址,继续构造eBPF指令,读取task_struct地址,进而得到task_struct->cred地址;

4.构造eBPF指令,覆写cred->uid, cred->gid为0,完成提权。

漏洞利用的核心,在于精心构造的恶意eBPF指令,这段指令在Vitaly Nikolenko的exp中是16机制字符串(char *__prog),并不直观,笔者为了方便,写了个小工具,把这些指令还原成比较友好的形式,当然也可以利用eBPF的调试机制,在内核log中打印出eBPF指令的可读形式。

我们来看下这段eBPF程序,共41条指令(笔者写的小工具的输出):

parsing eBPF prog, size 328, len 41
ins 0: code(b4) alu | = | imm, dst_reg 9, src_reg 0, off 0, imm ffffffff
ins 1: code(55) jmp | != | imm, dst_reg 9, src_reg 0, off 2, imm ffffffff
ins 2: code(b7) alu64 | = | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 3: code(95) jmp | exit | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 4: code(18) ld | BPF_IMM | u64, dst_reg 9, src_reg 1, off 0, imm 3
ins 5: code(00) ld | BPF_IMM | u32, dst_reg 0, src_reg 0, off 0, imm 0
ins 6: code(bf) alu64 | = | src_reg, dst_reg 1, src_reg 9, off 0, imm 0
ins 7: code(bf) alu64 | = | src_reg, dst_reg 2, src_reg a, off 0, imm 0
ins 8: code(07) alu64 | += | imm, dst_reg 2, src_reg 0, off 0, imm fffffffc
ins 9: code(62) st | BPF_MEM | u32, dst_reg a, src_reg 0, off fffffffc, imm 0
ins 10: code(85) jmp | call | imm, dst_reg 0, src_reg 0, off 0, imm 1
ins 11: code(55) jmp | != | imm, dst_reg 0, src_reg 0, off 1, imm 0
ins 12: code(95) jmp | exit | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 13: code(79) ldx | BPF_MEM | u64, dst_reg 6, src_reg 0, off 0, imm 0
ins 14: code(bf) alu64 | = | src_reg, dst_reg 1, src_reg 9, off 0, imm 0
ins 15: code(bf) alu64 | = | src_reg, dst_reg 2, src_reg a, off 0, imm 0
ins 16: code(07) alu64 | += | imm, dst_reg 2, src_reg 0, off 0, imm fffffffc
ins 17: code(62) st | BPF_MEM | u32, dst_reg a, src_reg 0, off fffffffc, imm 1
ins 18: code(85) jmp | call | imm, dst_reg 0, src_reg 0, off 0, imm 1
ins 19: code(55) jmp | != | imm, dst_reg 0, src_reg 0, off 1, imm 0
ins 20: code(95) jmp | exit | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 21: code(79) ldx | BPF_MEM | u64, dst_reg 7, src_reg 0, off 0, imm 0
ins 22: code(bf) alu64 | = | src_reg, dst_reg 1, src_reg 9, off 0, imm 0
ins 23: code(bf) alu64 | = | src_reg, dst_reg 2, src_reg a, off 0, imm 0
ins 24: code(07) alu64 | += | imm, dst_reg 2, src_reg 0, off 0, imm fffffffc
ins 25: code(62) st | BPF_MEM | u32, dst_reg a, src_reg 0, off fffffffc, imm 2
ins 26: code(85) jmp | call | imm, dst_reg 0, src_reg 0, off 0, imm 1
ins 27: code(55) jmp | != | imm, dst_reg 0, src_reg 0, off 1, imm 0
ins 28: code(95) jmp | exit | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 29: code(79) ldx | BPF_MEM | u64, dst_reg 8, src_reg 0, off 0, imm 0
ins 30: code(bf) alu64 | = | src_reg, dst_reg 2, src_reg 0, off 0, imm 0
ins 31: code(b7) alu64 | = | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 32: code(55) jmp | != | imm, dst_reg 6, src_reg 0, off 3, imm 0
ins 33: code(79) ldx | BPF_MEM | u64, dst_reg 3, src_reg 7, off 0, imm 0
ins 34: code(7b) stx | BPF_MEM | u64, dst_reg 2, src_reg 3, off 0, imm 0
ins 35: code(95) jmp | exit | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 36: code(55) jmp | != | imm, dst_reg 6, src_reg 0, off 2, imm 1
ins 37: code(7b) stx | BPF_MEM | u64, dst_reg 2, src_reg a, off 0, imm 0
ins 38: code(95) jmp | exit | imm, dst_reg 0, src_reg 0, off 0, imm 0
ins 39: code(7b) stx | BPF_MEM | u64, dst_reg 7, src_reg 8, off 0, imm 0
ins 40: code(95) jmp | exit | imm, dst_reg 0, src_reg 0, off 0, imm 0
parsed 41 ins, total 41

稍微解释下,ins 0 和 ins 1 一起完成了绕过eBPF verifier机制。ins 0指令后,regs[9] = 0xffffffff,但在verifier中,regs[9].imm = -1,当执行ins 1时,jmp指令判断regs[9] == 0xffffffff,注意regs[9]是64bit integer,因为sign extension,regs[9] == 0xffffffff结果为false,eBPF跳过2(off)条指令,继续往下执行;而在verifier中,jmp指令的regs[9].imm == insn->imm结果为true,程序走另一个分支,会执行ins 3 jmp|exit指令,导致verifier认为程序已结束,不会去检查其余的dead code。

这样因为eBPF的检测逻辑和运行时逻辑不一致,我们就绕过了verifier。后续的指令就是配合用户态exp完成对kernel内存的读写。

这里还需要知道下eBPF的map机制,eBPF为了用户态更高效的与内核态交互,设计了一套map机制,用户态程序和eBPF程序都可以对map区域的内存进行读写,交换数据。利用代码中,就是利用map机制,完成用户态程序与eBPF程序的交互。

ins4-ins5: regs[9] = struct bpf_map *map,得到用户态程序申请的map的地址,注意这2条指令,笔者的静态解析并不准确,获取map指针的指令,在eBPF verifi
漏洞影响范围&修复
因为linux kernel的内核版本众多,对于安全漏洞的影响范围往往并不容易确认,最准确的方式是搞清楚漏洞根因后,从代码层面判断,但这也带来了高成本的问题,快速应急时,我们往往需要尽快确认漏洞影响范围。

从前面的漏洞原理来看,笔者大致给一个全面的linux kernel受影响版本:

3.18-4.4所有版本(包括longterm 3.18,4.1,4.4);

<3.18,因内核eBPF还未引入verifier机制,不受影响。

对于大量用户使用的各个发行版,还需要具体确认,因为该漏洞的触发,还需要2个条件

1.Kernel编译选项CONFIG_BPF_SYSCALL打开,启用了bpf syscall;

2./proc/sys/kernel/unprivileged_bpf_disabled设置为0,允许非特权用户调用bpf syscall

而Ubuntu正好满足以上3个条件。

关于修复,upstream kernel在3月22日发布的4.4.123版已经修复该漏洞[11][12], Ubuntu官方4月5日也正式发布了安全公告和修复版本[13][14],没有修复的同学可以尽快升级了。

但现在距漏洞Exp公开已经过去20多天了,在漏洞应急时,我们显然等不了这么久,回过头看看当初的临时修复方案:

1.设置/proc/sys/kernel/unprivileged_bpf_disabled为1,也是最简单有效的方式,虽然漏洞仍然存在,但会让exp失效;

2.使用Ubuntu的预发布源,更新Ubuntu 4.4的内核版本,因为是非正式版,其稳定性无法确认。
网络安全公司CrowdStrike旗下的猎鹰传感器(Falcon Sensor)的一次软件更新引发了一场全球危机,导致全球安装有Windows系统计算机出现大规模的蓝屏死机(blue screen of death,即BSOD),结果数千架航班被迫停飞、医院陷入混乱、支付系统崩溃,直接影响了数百万用户,成为历史上最大的 IT 故障。初步统计,宕机事件给财富 500 强企业造成高达 54 亿美元的损失。

此次宕机是由于CrowdStrike猎鹰传感器的更新中存在缺陷而引发的,相关更新出现一个逻辑错误进而导致系统崩溃,特别是Windows设备。
Premise 在 2019 年为美国为首的阿富汗联合特种作战特遣部队准备的一项技术宣传中,提出了三种潜在用途,这些用途可以响应指挥官的信息需求:1、衡量美国信息作战的有效性; 2、侦察和绘制关键的社会结构,如清真寺、银行和网吧;3、在 100 平方公里的区域内秘密监控信号塔和 Wi-Fi 信号

从这份材料的介绍显示,阿富汗的接包者上传的数据非常有价值,只可惜美国要撤军阿富汗,可能之后单子会越来越少了

非洲特种作战司令部 (SOCAFRICA) 的美国空军 (USAF) 组成部分与海军特种作战 (NSW) 部队一起,需要下一代情报、监视和侦察 (ISR) 能力,以实现远程和动态重新分配任务地面进入作战环境 (OE) 以支持后果严重的反暴力极端主义组织 (VEO) 任务。使用数据科学和机器学习 (ML),Premise 的目标是通过一个由超过 600,000 名人类数据贡献者组成的呈指数增长的全球网络来满足 SOCAFRICA 的关键要求,从而在整个非洲大陆实现大规模可扩展的虚拟收集(定向观察、相关情感和无线网络映射)。 ”在2020年7 月,Premise 向英国政府提交了一份功能性描述的文件,称它可以从其贡献者的手机中捕获 100 多种类型的元数据,并将其提供给付费客户:包括手机的位置、类型、电池电量和已安装的应用程序。
华尔街日报还报道称,该公司的APP曾对阿富汗的用户发布了几项任务,其中有识别和拍摄喀布尔西部主要由哈扎拉什叶派少数民族成员组成的部分地区的什叶派清真寺。在过去五年中,该地区曾多次遭到XX袭击,被采访的阿富汗用户说他认为这些任务可能涉及间谍活动,因此没有接受