Java反序列化:CommonsCollections3调试分析
基础知识
1. Java 反射
1.1 getConstructor
getConstructor
是Java反射API中的一个方法,用于获取类的公共构造方法的引用。构造方法是一种特殊的方法,用于创建类的实例(对象),并且通常在对象创建时进行初始化。
getConstructor的函数原型:
public Constructor<?> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
parameterTypes
:一个可变参数,用于指定要获取的构造方法的参数类型列表。NoSuchMethodException
:如果没有找到匹配指定参数类型的公共构造方法,则会抛出此异常。SecurityException
:如果存在安全管理器且其checkMemberAccess
方法拒绝访问构造方法,则会抛出此异常。
1.2 newInstance
newInstance
是Java反射API中的一个方法,用于创建类的实例并返回该实例的引用。
newInstance的函数原型:
public T newInstance() throws InstantiationException, IllegalAccessException
T
表示要创建的类型
2. InstantiateTransformer
InstantiateTransformer
是Apache Commons Collections库中的一个类,用于创建对象的转换器。具体来说,它用于通过类名实例化一个新对象,并将其作为转换结果返回。
看看源码:
public class InstantiateTransformer<T> implements Transformer<Class<? extends T>, T>, Serializable {
private static final long serialVersionUID = 3786388740793356347L;
private static final Transformer NO_ARG_INSTANCE = new InstantiateTransformer();
private final Class<?>[] iParamTypes;
private final Object[] iArgs;
public static <T> Transformer<Class<? extends T>, T> instantiateTransformer() {
return NO_ARG_INSTANCE;
}
public static <T> Transformer<Class<? extends T>, T> instantiateTransformer(Class<?>[] paramTypes, Object[] args) {
if (paramTypes == null && args != null || paramTypes != null && args == null || paramTypes != null && args != null && paramTypes.length != args.length) {
throw new IllegalArgumentException("Parameter types must match the arguments");
} else {
return paramTypes != null && paramTypes.length != 0 ? new InstantiateTransformer(paramTypes, args) : new InstantiateTransformer();
}
}
private InstantiateTransformer() {
this.iParamTypes = null;
this.iArgs = null;
}
public InstantiateTransformer(Class<?>[] paramTypes, Object[] args) {
this.iParamTypes = paramTypes != null ? (Class[])paramTypes.clone() : null;
this.iArgs = args != null ? (Object[])args.clone() : null;
}
public T transform(Class<? extends T> input) {
try {
if (input == null) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a null object");
} else {
Constructor<? extends T> con = input.getConstructor(this.iParamTypes); // 获取公开构造器
return con.newInstance(this.iArgs); // 创建对象实例
}
} catch (NoSuchMethodException var3) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (InstantiationException var4) {
throw new FunctorException("InstantiateTransformer: InstantiationException", var4);
} catch (IllegalAccessException var5) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", var5);
} catch (InvocationTargetException var6) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", var6);
}
}
}
3. TrAXFilter
在其构造方法中具有
public class TrAXFilter extends XMLFilterImpl {
private Templates _templates;
private TransformerImpl _transformer;
private TransformerHandlerImpl _transformerHandler;
private boolean _useServicesMechanism = true;
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}
public Transformer getTransformer() {
return _transformer;
}
private void createParent() throws SAXException {
XMLReader parent = null;
try {
SAXParserFactory pfactory = SAXParserFactory.newInstance();
pfactory.setNamespaceAware(true);
if (_transformer.isSecureProcessing()) {
try {
pfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
}
catch (SAXException e) {}
}
SAXParser saxparser = pfactory.newSAXParser();
parent = saxparser.getXMLReader();
}
catch (ParserConfigurationException e) {
throw new SAXException(e);
}
catch (FactoryConfigurationError e) {
throw new SAXException(e.toString());
}
if (parent == null) {
parent = XMLReaderFactory.createXMLReader();
}
// make this XMLReader the parent of this filter
setParent(parent);
}
public void parse (InputSource input) throws SAXException, IOException
{
XMLReader managedReader = null;
try {
if (getParent() == null) {
try {
managedReader = XMLReaderManager.getInstance(_useServicesMechanism)
.getXMLReader();
setParent(managedReader);
} catch (SAXException e) {
throw new SAXException(e.toString());
}
}
// call parse on the parent
getParent().parse(input);
} finally {
if (managedReader != null) {
XMLReaderManager.getInstance(_useServicesMechanism).releaseXMLReader(managedReader);
}
}
}
public void parse (String systemId) throws SAXException, IOException
{
parse(new InputSource(systemId));
}
public void setContentHandler (ContentHandler handler)
{
_transformerHandler.setResult(new SAXResult(handler));
if (getParent() == null) {
try {
createParent();
}
catch (SAXException e) {
return;
}
}
getParent().setContentHandler(_transformerHandler);
}
public void setErrorListener (ErrorListener handler) { }
}
4. TemplatesImpl动态加载字节码
-
Templates接口
-
TemplatesImpl动态加载字节码过程
/*
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
ClassLoader.defineClass() => 加载字节码
*/
5.AbstractMapDecorator类
这个类是java.util.Map
接口的装饰器(Decorator),它允许你通过包装另一个Map
实现来添加额外的功能或修改Map
的行为,而无需修改原始Map
实现的代码。
public abstract class AbstractMapDecorator implements Map {
protected transient Map map;
protected AbstractMapDecorator() {
}
public AbstractMapDecorator(Map map) {
if (map == null) {
throw new IllegalArgumentException("Map must not be null");
} else {
this.map = map;
}
}
protected Map getMap() {
return this.map;
}
public void clear() {
this.map.clear();
}
public boolean containsKey(Object key) {
return this.map.containsKey(key);
}
public boolean containsValue(Object value) {
return this.map.containsValue(value);
}
public Set entrySet() {
return this.map.entrySet();
}
public Object get(Object key) {
return this.map.get(key);
}
public boolean isEmpty() {
return this.map.isEmpty();
}
public Set keySet() {
return this.map.keySet();
}
public Object put(Object key, Object value) {
return this.map.put(key, value);
}
public void putAll(Map mapToCopy) {
this.map.putAll(mapToCopy);
}
public Object remove(Object key) {
return this.map.remove(key);
}
public int size() {
return this.map.size();
}
public Collection values() {
return this.map.values();
}
public boolean equals(Object object) {
return object == this ? true : this.map.equals(object);
}
public int hashCode() {
return this.map.hashCode();
}
public String toString() {
return this.map.toString();
}
}
调试分析
基本过程和CC1链一致,主要是将最后的恶意代码触发由InvokerTransformer
改装成InstantiateTransformer
,然后利用TrAXFilter
来调用TemplatesImpl
来加载Java字节码
Gadget Chain
/* Gadget Chaain*/
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
LazyMap.readObject()
Map(Proxy).entrySet()
LazyMap.get()
InstantiateTransformer.transform()
TrAXFilter.TrAXFilter()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
调试过程
- 看调用栈,几乎就是CC1那条路,不赘述了吧