weblogic“伪随机”目录生成算法探究

0x01 背景说明

我们在渗透测试过程中,可以很容易发现weblogic的 server name一旦被修改,其web应用有一个目录就会发生改变,导致我们在部署war拿shell时受阻。

比如bea_wls_internal这个weblogic自带web应用的web目录物理路径为:

weblogic10.3.6.0\user_projects\domains\base_domain\servers\AdminServer\tmp_WL_internal\bea_wls_internal\9j4dqk\war

PS:为了后面的讨论,这里统一下概念,域名为base_domain,server nameAdminServer,web应用名为bea_wls_internal,伪随机目录为9j4dqk

这时如果server name修改为c0ny1的话,经过测试其伪随机目录会变成qn64ct,即该web应用物理路径变为:

weblogic10.3.6.0\user_projects\domains\base_domain\servers\c0ny1\tmp_WL_internal\bea_wls_internal\qn64ct\war

0x02 真随机 or 伪随机?

在此前我一直以为改目录是随机的无法。直到我做了下面的测试,将两个域的server name都改为c0ny1

bea_wls_internal随机目录变化

bea_wls9_async_reponses随机目录变化

发现两个域下相同web应用的随机目录名相同,这说明随机数目录其实是伪随机,它是有算法来生成的。而通过结果我们很容易就判断出该随机数和域名无关,和server nameapplication name有关!

0x03 探究生成算法

于是我打算跟踪下weblogic源码,扒出负责生产伪随机数的算法函数。由于其生成伪随机目录在weblogic未启动完全情况下,故通过weblogic配置的调试比较难。这种情况下更好的思路是插桩,但要插哪个函数的桩呢?

我在翻阅weblogic的源码(weblogic.jar)时,着重关注文件操作和部署接口的代码,发现了一个相关性很大的方法。该函数就在weblogic的路径工具类(weblogic.application.utils.PathUtils)中。

相关方法

在判断不失误的情况下,我们只要知道其传入的参数值就知道改函数如何使用了。为此我编写了如下代码,使用javassist将打印函数参数值的代码注入到该函数中。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class Test {
public static void changeMethode() {
try {
ClassPool.getDefault().insertClassPath("/Users/c0ny1/IdeaProjects/weblogic-path-test/lib/weblogic.jar");

// 获取需要修改的类
CtClass cls = ClassPool.getDefault().getCtClass("weblogic.application.utils.PathUtils");
// 获取类中的printTest方法
CtMethod m = cls.getDeclaredMethod("generateTempPath");
// 在方法中插入新的代码
//m.insertBefore("System.out.println($1 + File.separator + Long.toString((long)Math.abs(var3.toString().hashCode()), 36));") ;
// 修改该方法的内容
m.setBody("{StringBuffer var3 = new StringBuffer();\n" +
" if ($1 != null) {\n" +
" var3.append($1);\n" +
" }\n" +
"\n" +
" if ($2 != null) {\n" +
" var3.append(\"_\").append($2);\n" +
" }\n" +
"\n" +
" if ($3 != null) {\n" +
" var3.append(\"_\").append($3);\n" +
" }\n" +
"\n" +
" String str = $2 + java.io.File.separator + Long.toString((long)Math.abs(var3.toString().hashCode()), 36);\n" +
" System.out.println(\"[+] p1:\" + $1);\n" +
" System.out.println(\"[+] p2:\" + $2);\n" +
" System.out.println(\"[+] p3:\" + $3);\n" +
" System.out.println(\"[+] \" + str);\n" +
" return str;}");

// 解除代码锁定,恢复可编辑状态
cls.defrost();
// 写出到外存中
cls.writeFile("./PathUtils.class");
// testJarClass.writeFile(other path);

} catch (Exception e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
changeMethode();
}
}

被注入代码后的PathUtils类

将插桩后的PathUtils类通过Winrar软件覆盖weblogic.jar原来的类,然后重新启动weblogic,即可从控制台查看到如下:

weblogic重启运行结果

由此我们知道web应用bea_wls9_async_response的随机目录被生成时,该函数被调用并传入server nameapplication name,这也验证我们之前的猜想。

1
generateTempPath("c0ny1","bea_wls9_async_response","bea_wls9_async_response.war")

0x04 伪随机目录生成代码编写

到这里写计算伪随机目录生成程序就是很简单的事了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class WeblogicPathBuilder {
public static String generateTempPath(String paramString1, String paramString2, String paramString3) {
StringBuffer stringBuffer = new StringBuffer();

if (paramString1 != null) stringBuffer.append(paramString1);

if (paramString2 != null) {
stringBuffer.append("_").append(paramString2);
}

if (paramString3 != null) {
stringBuffer.append("_").append(paramString3);
}
return Long.toString(Math.abs(stringBuffer.toString().hashCode()), 36);
}

public static void main(String[] args) {
String ServerName = args[0];
String AppName = args[1];
String AppWarName = AppName + ".war";
System.out.println(generateTempPath(ServerName,AppName,AppWarName));
}
}

计算结果和weblogic实际生成完全吻合!!!

计算结果

之后的几天逛Github时,发现早就有人发现其规律。

https://github.com/dr0op/WeblogicScan/blob/master/app/plugins/CVE-2019-2618.py