首发!PowerJob 全版本 RCE(另附检测脚本)

渗透技巧 10个月前 admin
195 0 0

免责声明:

本公众号致力于安全研究和红队攻防技术分享等内容,本文中所有涉及的内容均不针对任何厂商或个人,同时由于传播、利用本公众号所发布的技术或工具造成的任何直接或者间接的后果及损失,均由使用者本人承担。请遵守中华人民共和国相关法律法规,切勿利用本公众号发布的技术或工具从事违法犯罪活动。最后,文中提及的图文若无意间导致了侵权问题,请在公众号后台私信联系作者,进行删除操作。




0x01 代码分析

为了能更直观的看到是怎么造成的命令/代码执行,所以先看下流程  

JobController的runImmediately方法负责执行任务,

调度的处理过程有点复杂,详情看

https://blog.csdn.net/qq_42985872/article/details/128500740

定位到类:WorkerActor

onReceiveServerScheduleJobReq方法负责处理runjob节点的请求。此时空属性的ServerScheduleJobReq对象会传递进入下一级onReceiveServerScheduleJobReq方法

         首发!PowerJob 全版本 RCE(另附检测脚本)

onReceiveServerScheduleJobReq方法会根据任务类型进入不同的处理,轻量级任务进入LightTaskTracker

首发!PowerJob 全版本 RCE(另附检测脚本)

而重量级任务则会进入HeavyTaskTracker

首发!PowerJob 全版本 RCE(另附检测脚本)

跟进isLightweightTask方法查看如何判断的级别

首发!PowerJob 全版本 RCE(另附检测脚本)

从isLightweightTask方法得知,单机、固定频率、固定延迟模式都属于轻量,其他则是重量

先跟进轻量,LightTaskTracker#create

首发!PowerJob 全版本 RCE(另附检测脚本)

请求传进LightTaskTracker对象:

首发!PowerJob 全版本 RCE(另附检测脚本)

在构造方法中做了大量的初始化设定,具体为:会使用父类对请求先做一次参数初始化

首发!PowerJob 全版本 RCE(另附检测脚本)

此时的req是包含有控制台传来的各项参数,继续往下走,constructTaskContext方法会将各项参数封装到taskContext对象

首发!PowerJob 全版本 RCE(另附检测脚本) 首发!PowerJob 全版本 RCE(另附检测脚本)

随后进入到load方法加载控制台传来的ProcessorInfo

首发!PowerJob 全版本 RCE(另附检测脚本)

在PowerJobProcessorLoader#load方法中,ProcessorInfo信息又被传进pf.build方法

首发!PowerJob 全版本 RCE(另附检测脚本)


pf是包含BuiltInDefaultProcessorFactory、JarContainerProcessorFactory的对象

首发!PowerJob 全版本 RCE(另附检测脚本)

在load流程里,会根据传进的处理器类型进入不同的Factory

首发!PowerJob 全版本 RCE(另附检测脚本)

得到处理器参数:BUILT_IN、EXTERNAL

首发!PowerJob 全版本 RCE(另附检测脚本)

分别查看两个Factory

JarContainerProcessorFactory:

根据注释得知该类是从容器加载class,从传进的参数中获取容器id以及容器里的全限定类名,格式大概是这样id#xx.xxx.xxx,当processorType是EXTERNAL时就会用到这个Factory

首发!PowerJob 全版本 RCE(另附检测脚本)

BuiltInDefaultProcessorFactory:

BuiltInDefaultProcessorFactory是内建的默认处理器工厂,可以通过全限定类名加载处理器,在build方法中,会根据传进的ProcessorInfo信息来实例化对象,即ProcessorInfo参数就是全限定类名。当processorType是BUILT_IN时就会用到这个Factory

首发!PowerJob 全版本 RCE(另附检测脚本)

load方法走完了,回到构造方法LightTaskTracker中,实例化后的ProcessorInfo信息被封装到processorBean对象

首发!PowerJob 全版本 RCE(另附检测脚本) 首发!PowerJob 全版本 RCE(另附检测脚本)

在初始化完所有信息后,进入到processTask方法,其会在线程池中完成被调用

首发!PowerJob 全版本 RCE(另附检测脚本)

跟进processTask方法,参数传进process

首发!PowerJob 全版本 RCE(另附检测脚本)

因为在此之前设置了当前线程上下文加载器

首发!PowerJob 全版本 RCE(另附检测脚本)

所以此时被实例化的processorBean会使用到前面实例化时设置的classloader加载

首发!PowerJob 全版本 RCE(另附检测脚本)

进入到

CommonBasicProcessor#process

该类是一个通用处理器类

首发!PowerJob 全版本 RCE(另附检测脚本)

process方法中,将包含有任务参数、任务instanceId等信息的TaskContext对象传进process0方法

首发!PowerJob 全版本 RCE(另附检测脚本) 首发!PowerJob 全版本 RCE(另附检测脚本)

process0方法属于AbstractScriptProcessor类,该类属于通用脚本处理器类,所有脚本插件都要继承该类。在process0方法中,会使用prepareScriptFile方法来根据控制台传来的内容生成脚本文件,文件名是instanceId

首发!PowerJob 全版本 RCE(另附检测脚本) 首发!PowerJob 全版本 RCE(另附检测脚本)

跟进getScriptName方法发现是一个抽象方法

首发!PowerJob 全版本 RCE(另附检测脚本)

所在的抽象类由多个插件类继承,用于应对不同系统的调用。在powerjob本身中自带有多个脚本处理器(插件)

首发!PowerJob 全版本 RCE(另附检测脚本)

被重写的getScriptName方法大同小异,均返回对应系统的脚本文件名:cmd_instanceId.bat/shell_instanceId.sh

首发!PowerJob 全版本 RCE(另附检测脚本) 首发!PowerJob 全版本 RCE(另附检测脚本)

回到prepareScriptFile方法,最终把参数写入脚本文件

首发!PowerJob 全版本 RCE(另附检测脚本)

回到process0方法,方法里会调用到抽象方法getRunCommand,根据子类重写的方法返回来判断要调用哪个应用来执行脚本。

也就是说,当控制台传进的processorInfo(即封装后的processorBean)是CMDProcessor类时,getRunCommand则是CMDProcessor里重写的getRunCommand方法,返回的是cmd.exe,否则就是剩余的几个Processor(python、sh、powershell)

首发!PowerJob 全版本 RCE(另附检测脚本)

最终由ProcessBuilder完成对getRunCommand方法返回值的调用,scriptPath被当成返回值的参数进行执行

剩下的HeavyTaskTracker.create不看了,可能更复杂,但大同小异

验证: 

根据saveJob方法里jobInfoDO的信息构造参数保存任务,其中jobParams参数是恶意命令,最后使用runImmediately方法执行任务就会触发漏洞

保存任务

首发!PowerJob 全版本 RCE(另附检测脚本)

查看实体类,可以看到有一个处理器选项

SaveJobInfoRequest
首发!PowerJob 全版本 RCE(另附检测脚本)
ProcessorType
首发!PowerJob 全版本 RCE(另附检测脚本)


0x02 V3.X版本

在V3版本中可以直接通过shell处理器的方式执行系统命令,但仅限于linux

首发!PowerJob 全版本 RCE(另附检测脚本) 首发!PowerJob 全版本 RCE(另附检测脚本)

新建任务,designatedWorkers可指定机器,不指定机器默认全部执行

可以查看所有机器地址

首发!PowerJob 全版本 RCE(另附检测脚本)

processorInfo的参数为命令执行参数

首发!PowerJob 全版本 RCE(另附检测脚本)

搜索刚刚创建的任务关键字得出任务id

首发!PowerJob 全版本 RCE(另附检测脚本)

运行任务id得到结果id

首发!PowerJob 全版本 RCE(另附检测脚本)

根据id获取命令执行结果

首发!PowerJob 全版本 RCE(另附检测脚本)
0x03 V4.X版本

v4以后的处理器都是通过插件的方式调用,此时双系统都可以执行命令

  • windows:  

通过内置的全限定类名执行

按照v3的方式添加任务(v4的参数有些许不一样),然后执行查询任务id

首发!PowerJob 全版本 RCE(另附检测脚本)

运行得到的id就会触发

首发!PowerJob 全版本 RCE(另附检测脚本)
  • linux: 

ShellProcessor

可以通过查询执行成功的id来查看命令回显

首发!PowerJob 全版本 RCE(另附检测脚本)
0x04 小Tips

假如通过v3的方式在v4增加了任务,可以尝试通过接口转换执行

首发!PowerJob 全版本 RCE(另附检测脚本)

但需要目标有这个依赖

<dependency>    <groupId>tech.powerjob</groupId>    <artifactId>powerjob-official-processors</artifactId>    <version>4.3.3</version></dependency>

    

检测工具请关注我们的圈子,后台回复“加群”或“小助手”加入我们的群吧

     首发!PowerJob 全版本 RCE(另附检测脚本)

                   

 

首发!PowerJob 全版本 RCE(另附检测脚本)

原文始发于微信公众号(Lambda小队):首发!PowerJob 全版本 RCE(另附检测脚本)

版权声明:admin 发表于 2023年9月5日 上午7:22。
转载请注明:首发!PowerJob 全版本 RCE(另附检测脚本) | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...