在Jfinal使用redis缓存时存在的反序列化问题
src/main/java/com/jfinal/plugin/redis/serializer/JdkSerializer.java#valueFromBytes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public Object valueFromBytes(byte[] bytes) { if (bytes == null || bytes.length == 0) return null; ObjectInputStream objectInput = null; try { ByteArrayInputStream bytesInput = new ByteArrayInputStream(bytes); objectInput = new ObjectInputStream(bytesInput); return objectInput.readObject(); } catch (Exception e) { throw new RuntimeException(e); } finally { if (objectInput != null) try { objectInput.close(); } catch (Exception e) { LogKit.error(e.getMessage(), e); } } }
|
可以看到调用了readObject,我们看看在哪使用了valueFromBytes方法
发现在src/main/java/com/jfinal/plugin/redis/Cache.java#get
使用了valueFromBytes方法
1 2 3 4 5 6 7 8
| public <T> T get(Object key) { Jedis jedis = getJedis(); try { return (T)valueFromBytes(jedis.get(keyToBytes(key))); } finally { close(jedis); } }
|
又有多个方法调用了valueFromBytes 但是get方法是通过查询redis键所对应的值 比较 常用
1 2 3
| protected Object valueFromBytes(byte[] bytes) { return this.serializer.valueFromBytes(bytes); }
|
返回的是serializer的对象中的方法,默认serializer指定的对象FstSerializer,我们需要在传入RedisPlugin为JdkSerializer才能进入readObject
在配置中需要指定
1 2 3 4 5 6
| @Override public void configPlugin(Plugins me) { RedisPlugin redis = new RedisPlugin("evilRedis","127.0.0.1"); redis.setSerializer(new JdkSerializer()); me.add(redis); }
|
使用缓存时触发
1 2
| Cache userCache = Redis.use("evilRedis"); userCache.get("data");
|
进入redis在data这个键值中修改为Yso生成的目标有的依赖链 将反序列化的字节码存入data键所对应的值中 访问触发缓存即可RCE