Java xxe oob 读取多行文件失败的原因

一. java xxe oob 支持的协议

根据 src.zip!\java\net\URL.java 中的以下代码

if (protocol.equalsIgnoreCase(GOPHER) &&
    packagePrefix.equals(JDK_PACKAGE_PREFIX) &&
    !enableGopher) {
        continue;
}
try {
    String clsName = packagePrefix + "." + protocol +
      ".Handler";
    Class cls = null;
    try {
        cls = Class.forName(clsName);
    } catch (ClassNotFoundException e) {
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        if (cl != null) {
            cls = cl.loadClass(clsName);
        }
    }
    if (cls != null) {
        handler  =
          (URLStreamHandler)cls.newInstance();
    }
} catch (Exception e) {
    // any number of exceptions can get thrown here
}

可以看出来支持的几种协议都在 rt.jar!\sun\net\www\protocol 目录下,通过反射调用每个协议目录下的 Handler 来实例化。

所以寻找 sun.net.www.protocol 包下有Handler.java 文件的

即可定位支持的协议主要有以下 8 种(Oracle JDK 1.7.0_75):

file
ftp
gopher
http
https
jar
mailto
netdoc

但在 src.zip!\java\net\URL.java 中,可以发现 gopher 协议默认从系统环境变量中读取 jdk.net.registerGopherProtocol来判断是否启用 gopher 协议的支持。

而默认取出的值为 null ,是不支持启用 gopher 协议的。

private static final String GOPHER = "gopher";
private static final String ENABLE_GOPHER_PROP = "jdk.net.registerGopherProtocol";
private static final boolean enableGopher = AccessController.doPrivileged(
    new PrivilegedAction<Boolean>() {
        @Override
        public Boolean run() {
            String prop = System.getProperty(ENABLE_GOPHER_PROP);
            return prop == null ? false :
                       (prop.equalsIgnoreCase("false") ? false : true);
        }
    });

引用 此文章 的一段描述来讲:

其中从2012年9月开始,Oracle JDK版本中删除了对gopher方案的支持,后来又支持的版本是 Oracle JDK 1.7 update 7 和 Oracle JDK 1.6 update 35

像本地的 Oracle JDK 1.8.0_181 版本,原生就没有gopher协议的相关代码,天生就不支持 gopher 协议。

在仅有的几个支持的协议中,支持oob的协议,除了比较低版本JDK默认支持并且启用gopher 协议外,可以外连的协议只有 http/httpsftp 协议。

二. 特殊字符

xml 相关的特殊字符

参考 该文章 ,如果读取的文件中含有 xml 相关的特殊字符

%
&
同时包含 " 和 '

程序在拼接结果时处理 xml 会报错

FTP协议相关的特殊字符

以下字符可能会破坏FTP指令,导致发送字符串被截断或者失败

/
?
\n

HTTP协议相关的特殊字符

以下字符可能会导致HTTP请求无法发送或者发送数据被截断,因为 \r\n 的原因,导致无法 通过http 协议接受多行文件

\n
\r
#

三. 源码层面解析

HTTP 协议

jdk1.7.0_75\jre\lib\rt.jar!\sun\net\www\http\HttpClient.class

public String getURLFile() throws IOException {
    ...... 省略

    if (var1.indexOf(10) == -1) {
        return var1;
    } else {
        throw new MalformedURLException("Illegal character in URL");
    }
}

一旦发送的 URL 中发现 chr(10)\n ,就会抛出 Illegal character in URL ,所以导致使用 HTTP 协议不能发送多行的文本。

jdk1.8.0_181\jre\lib\rt.jar!\sun\net\www\protocol\http\HttpURLConnection.class ,不一样的 JDK 版本也有类似代码:

private static URL checkURL(URL var0) throws IOException {
    if (var0 != null && var0.toExternalForm().indexOf(10) > -1) {
        throw new MalformedURLException("Illegal character in URL");
    } else {
        return var0;
    }
}

FTP 协议

jdk1.8.0_181\jre\lib\rt.jar!\sun\net\ftp\impl\FtpClient.class中,对于发送命令中遇到 \n 字符时 FTP 会报错Illegal FTP command,导致 FTP 发送多行文本会失败:

private boolean issueCommand(String var1) throws IOException, FtpProtocolException {
    {
        ...... 省略

        if (var1.indexOf(10) != -1) {
            FtpProtocolException var2 = new FtpProtocolException("Illegal FTP command");
            var2.initCause(new IllegalArgumentException("Illegal carriage return"));
            throw var2;
        } else {
            this.sendServer(var1 + "\r\n");
            return this.readReply();
        }
    }
}

已经 有人研究过 关于Java xxe oob 使用 FTP 协议读取多行文本失败的 JDK 版本:

使用ftp 进行 oob 时,对版本有限制, <7u141 和 <8u162 才可以读取整个文件

四. xxe ftp oob server

一条龙利用方法:

xxe-ftp-server.py

标签     

评论