<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    如何使用 IDEA 遠程 Debug 功能調試 DongTai-agent-java

    VSole2021-07-30 19:04:44

    一、遠程 Debug 原理

    首先,Java程序的執行過程分為以下幾個步驟:Java的文件 > 編譯生成的類文件(class文件)> JVM加載類文件 > JVM運行類字節碼文件 > JVM翻譯器翻譯成各個機器認識的不同的機器碼。Java 程序是運行在Java 虛擬機上的,具有良好跨平臺性,是因為Java程序統一以字節碼的形式在JVM中運行,不同平臺的虛擬機都統一使用這種相同的程序存儲格式。因為都是類字節碼文件,只要本地代碼和遠程服務器上的類文件相同,兩個 JVM 通過調試協議進行通信。另外需要注意的是,被調試的服務器需要開啟調試模式,服務器端的代碼和本地代碼必須保持一致,則會造成斷點無法進入的問題。

    總結:Java 遠程調試的原理是兩個JVM之間通過debug協議進行通信,然后以達到遠程調試的目的。兩者之間可以通過socket進行通信。

    二、編譯打包 DongTai-agent-java

    1.Fork DongTai-agent-java[1] 項目到自己的github倉庫

    2.將項目 clone 到本地

    3.進入 DongTai-agent-java 根目錄,執行打包命令。

       & mvn clean package -Dmaven.test.skip=true
    

    注:jdk 版本為1.8。

    4.打包結束后項目根目錄下會生成文件夾 release,其目錄結構:

       release
       ├── iast-agent.jar
       └── lib
           ├── dongtai-servlet.jar
           ├── iast-core.jar
           └── iast-inject.jar
    

    5.使用 IDEA 打開要使用 agent 啟動的測試項目(本篇文章以自建測試項目 SpringTest 為例),將這四個 jar 包添加到項目 Libraries 中。


    三、IDEA 配置遠程 Debug

    1.在 Run/Debug Configurations 中配置遠程 Debug 啟動項

    打開Inteliij IDEA,頂部菜單欄選擇Run-> Edit Configurations,進入下圖的運行/調試配置界面。

    點擊左上角“+”號,選擇 Remote JVM Debug。分別填寫右側三個紅框中的參數:Name,Host(想要指定的遠程調試端口)。

         Host:運行該項目的遠程IP
         Port:遠程 IP 的端口
         Command:遠程主機在啟動 Java 應用時需要添加的參數
    

    2.配置 springtest 的啟動命令

       $ java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -javaagent:/path/to/agent.jar -jar springtest.jar
    

    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005:Remote Debug 配置的 JVM 參數

    -javaagent:/path/to/agent.jar:被遠程 Debug 的DongTAi-iast-agent

    springtest.jar:將測試項目 springtest 打包,使用該 jar 包啟動項目

    三、遠程 Debug

    1.在 IDEA 中打斷點

    在剛剛引入了四個 jar 包中打斷點,以 iast-core 的transform()方法為例。

    transform() 方法會在類文件被加載時調用,在 transform 方法里,我們可以對傳入的二進制字節碼進行改寫或替換,生成新的字節碼數組后返回,JVM 會使用 transform 方法返回的字節碼數據進行類的加載。

    2.運行項目 springtest,然后在 IDEA 中點擊 debug

    使用上面配置的啟動命令運行 springtest

    在 IDEA 中查看到斷點信息,遠程 Debug 成功

    四、通過 Debug 探索 transform 方法

    DongTai-agent-java 對應用的每個類進行字節碼插樁:

        public byte[] transform(ClassLoader loader, String internalClassName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] srcByteCodeArray) {
            boolean isRunning = EngineManager.isLingzhiRunning();
            if (isRunning) {
                EngineManager.turnOffLingzhi();
            }
    
            StopWatch clock = null;
            if (this.logger.isDebugEnabled()) {
                clock = new StopWatch();
                clock.start();
            }
    
            try {
                CodeSource codeSource = protectionDomain != null ? protectionDomain.getCodeSource() : null;
                if (codeSource != null && internalClassName != null && !internalClassName.startsWith("com/secnium/iast/")) {
                    this.COMMON_UTILS.scanCodeSource(codeSource);
                }
    
                if (ConfigMatcher.isHookPoint(internalClassName, loader)) {
                    byte[] sourceCodeBak = new byte[srcByteCodeArray.length];
                    System.arraycopy(srcByteCodeArray, 0, sourceCodeBak, 0, srcByteCodeArray.length);
                    ClassReader cr = new ClassReader(sourceCodeBak);
                    int flags = cr.getAccess();
                    int targetClassLoaderObjectID = ObjectIDs.instance.identity(loader);
                    String[] interfaces = cr.getInterfaces();
                    String superName = cr.getSuperName();
                    String className = cr.getClassName();
                    this.COMMON_UTILS.setLoader(loader);
                    this.COMMON_UTILS.saveAncestors(className, superName, interfaces);
                    HashSet<String> ancestors = this.COMMON_UTILS.getAncestors(className, superName, interfaces);
                    ClassWriter cw = this.createClassWriter(loader, cr);
                    ClassVisitor cv = this.PLUGINS.initial(cw, IastContext.build(className, className, ancestors, interfaces, superName, flags, sourceCodeBak, codeSource, loader, this.listenerId, this.namespace, targetClassLoaderObjectID));
                    if (cv instanceof AbstractClassVisitor) {
                        cr.accept(cv, 8);
                        AbstractClassVisitor dumpClassVisitor = (AbstractClassVisitor)cv;
                        if (dumpClassVisitor.hasTransformed()) {
                            ++this.transformClassCount;
                            if (this.logger.isDebugEnabled() && null != clock) {
                                clock.stop();
                                this.logger.debug("conversion class {} is successful, and it takes {}ms, total {}.", new Object[]{internalClassName, clock.getTime(), this.transformClassCount});
                            }
    
                            byte[] var20 = this.dumpClassIfNecessary(cr.getClassName(), cw.toByteArray(), srcByteCodeArray);
                            return var20;
                        }
                    } else if (this.logger.isDebugEnabled() && null != clock) {
                        clock.stop();
                        this.logger.debug("failed to convert the class {}, and it takes {} ms", internalClassName, clock.getTime());
                    }
                }
            } catch (Throwable var24) {
                ErrorLogReport.sendErrorLog(ThrowableUtils.getStackTrace(var24));
            } finally {
                if (isRunning) {
                    EngineManager.turnOnLingzhi();
                }
    
            }
    
            return srcByteCodeArray;
        }
    

    1.transform 方法參數、返回值的意義

    ? loader:ClassLoader類對象,類加載器,將class文件加載到jvm虛擬機中去。

    ? internalClassName:被掃描類的類名

    ? classBeingRedefined:要重定義的類所對應的 Class 對象

    ? protectionDomain:定義權限,ProtectionDomain類封裝了域的特征,該域包含一組類,這些類的實例在代表給定的Principal集執行時被授予一組權限

    ? srcByteCodeArray:被掃描類的原始字節碼

    ? return:如果從 transform 方法中return null 的話,將會告訴運行時環境我們并沒有對這個類進行變更。如果要修改類的字節的話,需要在 transform 中提供字節碼操縱的邏輯并 return 修改后的字節。

    2.DongTai-agent-java 中 transform 方法對每個類做了什么

    ? this.COMMON_UTILS.scanCodeSource(codeSource) :對每個類所依賴的 jar 包進行掃描,并將信息發送至洞態IAST云端,在云端對這些 jar 包進行掃描(在云端稱為應用組件),將有安全漏洞的組件進行展示并提示該組件的安全版本。

    ?if (ConfigMatcher.isHookPoint(internalClassName, loader)) :在對類進行 HOOK 前需要判斷該類是否在DongTai-agent-java 自定義的 HOOK 黑名單中,以下類會出現在 HOOK 黑名單:

    ? agent自身的類

    ? 已知的框架類、中間件類

    ? 類名為null

    ? JDK內部類且不在hook點配置白名單中

    ? 接口

    ? 將不在黑名單中的類進行 HOOK,將信息發送至洞態IAST云端

    五、總結

    遠程 Debug 不僅為研發人員在編寫、調優、測試 DongTai-agent-java 提供方便,也為想要了解 DongTai-agent-java 的同學對其實現原理提供極大地便利,歡迎對該技術感興趣的同學進行嘗試。

    ?DongTai-agent-java[2]

        ?DongTai[3]

    References

    [1] DongTai-agent-java: https://github.com/HXSecurity/DongTai-agent-java

    [2] DongTai-agent-java: https://github.com/HXSecurity/DongTai-agent-java

    [3] DongTai: https://github.com/HXSecurity/DongTai

    jvm原理idea
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    一、遠程 Debug 原理首先,Java程序的執行過程分為以下幾個步驟:Java的文件 > 編譯生成的類文件
    深入理解 RMI 之漏洞原理篇環境是 jdk8u65本文側重于理解原理,攻擊篇會放到后續一篇中講。0x01 前言RMI 作為后續漏洞中最為基本的利用手段之一,學習的必要性非常之大。RMI 依賴的通信協議為 JRMP,該協議為 Java 定制,要求服務端與客戶端都為 Java 編寫。這個協議就像 HTTP 協議一樣,規定了客戶端和服務端通信要滿足的規范。
    淺談Java反序列化漏洞
    2022-05-11 15:48:41
    本篇文章參考P神知識星球的《Java漫談》系列文章,有條件的可以為p牛充電!(星球名:代碼審計,我已經沖了) 然后推薦想初步理解java反序列化、并且深度了解一兩個利用鏈的萌新,一步一步跟著文中在idea里調試理解每一步,不要求很快看完,可以收藏或者點贊后,慢慢看 , 希望能收獲一點東西 然后大佬們可以退了,因為寫的都是java反序列化很淺的東西,順便別罵QAQ
    最常見的情況是使用 Tomcat 作為 Java Web 服務器,使用 Spring 提供的開箱即用的強大 的功能,并依賴其他開源庫來完成負責的業務功能實現
    Filebeat監視您指定的日志文件或位置,收集日志事件,并將它們轉發到Elasticsearch或 Logstash進行索引。使用Kibana,可以通過各種圖表進行高級數據分析及展示。
    前言最近注意到了Apache Commons Configuration 在2.7版本已經不安全了,能夠直接影響該組件,來分析學一下漏洞原理漏洞分析前置Commons Configuration是一個java應用程序的配置管理類庫。可以從properties或者xml文件中加載軟件的配置信息,用來構建支撐軟件運行的基礎環境。在一些配置文件較多較的復雜的情況下,使用該配置工具比較可以簡化配置文件的解析和管理。也提高了開發效率和軟件的可維護性。同樣可以使用這種變量插值影響范圍2.4 ~ 2.7漏洞首先引入Commons-Configuration的依賴
    JSP Webshell的檢測工具
    2021-12-13 12:04:53
    在11月初,我做了一些JSP Webshell的免殺研究,主要參考了三夢師傅開源的代碼。然后加入了一些代碼混淆手段,編寫了一個免殺馬生成器JSPHorse,沒想到在Github上已收獲500+的Star
    Java命名和目錄接口是Java編程語言中接口的名稱( JNDI )。它是一個API(應用程序接口),與服務器一起工作,為開發人員提供了查找和訪問各種命名和目錄服務的通用、統一的接口。 可以使用命名約定從數據庫獲取文件。JNDI為Java?戶提供了使?Java編碼語?在Java中搜索對象的?具。 簡單來說呢,JNDI相當與是Java里面的一個api,它可以通過命名來查找數據和對象。
    近期,“核彈級漏洞” Apache Log4j2 遠程代碼執行漏洞細節被公開,攻擊者利用漏洞可以遠程執行代碼。 Apache Log4j2 是一款優秀的 Java 日志框架,該工具重寫了 Log4j 框架,并且引入了大量豐富的特性。該日志框架被大量用于業務系統開發,用來記錄日志信息。 漏洞原理簡述
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类