D^3CTF2023 (新的getter+高版本JNDI不出网+Hessian异常toString)
附件👉Click Me
这道题模拟了真实世界当中动态配置中心的架构——注册端存储相关配置,而服务端定期同步相关配置。而在这道题中的配置是Java原生反序列化的黑名单
Registry Hessian Deser Vul
注册端存在Hessian反序列化漏洞,这里它用的不是原生的Hessian,而是蚂蚁金服魔改后的Sofa Hessian
SOFA-Hessian 基于原生 Hessian v4.0.51 进行改进,支持导入Hessian黑名单来防止常见的Hessian利用链。
import com.alipay.hessian.ClassNameResolver;
import com.alipay.hessian.NameBlackListFilter;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.example.registry.data.Blacklist;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class HessianSerializer {
public HessianSerializer() {
}
public static byte[] serialize(Object obj) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(bos);
output.writeObject(obj);
output.close();
return bos.toByteArray();
}
public static Object deserialize(byte[] obj) throws Exception {
ByteArrayInputStream is = new ByteArrayInputStream(obj);
Hessian2Input input = new Hessian2Input(is);
ClassNameResolver resolver = new ClassNameResolver();
resolver.addFilter(new AntInternalNameBlackListFilter());
input.getSerializerFactory().setClassNameResolver(resolver);
return input.readObject();
}
static class AntInternalNameBlackListFilter extends NameBlackListFilter {
public AntInternalNameBlackListFilter() {
super(Blacklist.hessianBlackList);
}
}
}ClassNameResolver可以添加过滤器,过滤器继承自NameBlackListFilter,黑名单为resources/security/hessian_blacklist.txt
(这两个类都是com.alipay.hessian下的)
题目存在fastjson2.0.24的依赖,刚好黑名单中没有过滤fastjson
考虑fastjson原生反序列化,现在的问题变成
怎么触发fastjson的
toString寻找Hessian黑名单之外的可利用的getter
Getter without accessing the network
ysomap中存在这么一个利用类javax.naming.spi.ContinuationContext#getTargetContext
NamingManager.getContext进去就是JNDI了
JNDI的8u191绕过提到了本地Class的利用
目前公开常用的利用方法是通过 Tomcat 的 org.apache.naming.factory.BeanFactory 工厂类去调用 javax.el.ELProcessor#eval 方法或 groovy.lang.GroovyShell#evaluate 方法
org.apache.naming.factory.BeanFactory在getObjectInstance()中会通过反射的方式实例化Reference所指向的Bean Class,并且能调用一些指定的方法如何理解?
Reference类是我们可控的,这个类指定了JNDI要加载的类名(resourceClass)和用于加载这个类的工厂类(factory),在这里欲加载的类就是
ELProcessor,工厂类为BeanFactory。之所以用这个工程类,
跟进NamingManager#getContext,进到了NamingManager#getObjectInstance
首先判断refInfo是否为Reference或Referenceable类型
接着根据ref获取工厂类,这里传进去的factoryName为org.apache.naming.factory.BeanFactory,getObjectFactoryFromReference会去加载并实例化这个类
接着调用返回的factory的getObjectInstance

首先判断当前ref是否为ResourceRef,接着获取beanClass,并用当前线程的类加载去加载,后面实例化这个类

Introspector.getBeanInfo获取类的基本信息,包括类标识符、属性(貌似只有对应getter、setter的属性才会获取)、方法
从ref中获取addrType为forceString的RefAddr,并创建了一个键为字符串,值为方法的HashMap

接着获取了StringRefAddr的内容,以逗号为分隔符分开为每一项,若该项中含有等于号=,则左边作为值,右边作为getter方法名,获取到对应Method后作为值,放入forced这个HashMap中
源代码的注释也写得很清楚了,每一项可能是name=method的形式,也可以只是一个属性名,这里会对属性名进行setter标准化。显然这里如果是前者,并没有检查method是否为形为getXxx的方法,比如这里为eval

获取ref的所有RefAddr并遍历,跳过addrType为factory、scope、auth、forceString、singleton的RefAddr
对于其他RefAdrr,获取其内容,并放入一个Object数组,只有一个元素且为String
到这里应该可以猜到了这个值会作为上面获取的setter方法的参数,接着就是激动人心的方法调用了

所以实际上这里可以调用任意对象的方法,方法需要满足参数只有一个且为String类型
不过由于无法修改对象的属性,挺难找到ElProcessor之外的利用类
Hessian Exception triggering toString
和Dubbo中的类似,参考见这

Server Java Native Deser Vul
flag在服务端,我们只能通过注册中心打服务端
同样服务端设置了一大堆黑名单,会同步注册中心的黑名单
访问注册中心的/client/status,其会请求服务端的/status,调用update更新黑名单,若返回的是List则直接更新denyClasses,若为字符串,则先进行反序列化后再更新


DefaultSerializer#deserialize还会判断传入的denyClasses是否为空,若为空则读取原始的黑名单。
因此我们通过注入filter内存马来改写注册中心返回的黑名单为一些没用的数据,先清除服务端黑名单,然后再改写一次,让其返回恶意的序列化数据,让服务端对请求/blacklist/jdk/get返回的数据进行反序列化,打原生fastjson或jackson。
为了回显,同样需要改写服务端的返回包,注入filter来改写/status的返回数据为读取的flag
好吧,Filter内存马不好使,要打两次才行(或许是lastServicedResponse的原因?),得加载两次字节码,类名还得不同,麻烦。
网上找了其他师傅写的Spring内存马,太好用了!orz
生成无效黑名单👇
fastjson打Server👇
RegistryInterceptor👇
ServerInterceptor👇
访问三次/client/status即可得到flag
Summary
Registry存在Hessian反序列化漏洞,没有禁fastjson,通过构造畸形数据触发toString,最后调用
ContinuationContext#getTargetContext触发JNDI加载本地Class,打EL表达式Registry植入内存马,修改返回体的数据,让Server请求到无效的黑名单
再次修改Registry返回包数据为恶意序列化数据,fastjson原生反序列化打Server
Server植入内存马,修改返回体为flag数据
优雅~优雅!
Reference
https://github.com/wh1t3p1g/ysomap
https://pupil857.github.io/2023/05/03/d3ctf-ezjava/
Last updated
Was this helpful?