简介
GoAhead是一个轻量化、适用于嵌入式设备的Web服务器,采用C语言编写,代码量不大,具有高度的可移植性和扩展性。GoAhead支持多进程、多线程,能够处理大量的并发连接,支持SSL/TLS加密和基本的身份认证,支持CGI、ASP。
GoAhead由Embedthis Software LLC开发,早年间是完全开源的,可以直接在Github上下载到源码。但是在2022年的时候,似乎转换成商业定制,官方在Github删除了代码库,因此在Github上无法下载,但是在Gitee上还有镜像库。
地址:GoAhead: GoAhead WebServer 采用开放源代码方式,任何人都可以下载、评估并修改代码,目的是为了使GoAhead WebServer成为市场上最领先的嵌入式Web服务器
本文不会完全分析GoAhead的代码实现、架构,而是聚焦于安全研究较为关注、通常由开发者实现的数据包处理部分。文章的大概阐述思路如下:
- 首先结合源码说明GoAhead的数据包处理特性,主要涉及鉴权、路由处理
- 结合漏洞简述基于GoAhead的server漏洞挖掘思路
源码简单分析请求处理
GoAhead会对数据包按照优先级进行顺序处理,也会根据数据包的路由调用不同的回调函数进行处理。先说说数据包优先级:
- 优先级为1注册的回调函数:所有数据包都需要首先经过该回调函数进行处理,此处也通常被用来做数据包鉴权、请求路径合法性判断、未授权访问路径定义等等;优先级为0注
- 优先级为0注册的回调函数:通常用来定义认证后可访问到的接口逻辑实现
- 优先级为2注册的回调函数:没有回调函数匹配的数据包
1 | int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg, |
比较重要的参数:
char_t *urlPrefix
:指定URL的前缀,也就是需要处理的URL开头部分int (*handler)
:URL对应的回调函数int flags
:URL处理优先级标志,有如下的两个选择:#define WEBS_HANDLER_FIRST 0x1
:所有的数据包都会通过该回调函数进行处理#define WEBS_HANDLER_LAST 0x2
:没有回调函数匹配的数据包会通过该回调函数进行处理
如下是一个真实设备的反编译代码,可以看到GoAhead是通过注册一个flags=WEBS_HANDLER_FIRST=1的回调函数websAuthHandler来判断数据包是否通过认证的,这意味着所有的数据包都会通过函数websAuthHandler进行处理,验证数据包发送者的权限。
1 | websUrlHandlerDefine(&byte_4AA6CC, 0, 0, websAuthHandler, 1); |
例如对一个请求的完整处理过程:使用POST请求访问/goform/websLogin,
- 首先数据包会进入函数webAuthHandler:请求路径鉴权、请求路径合法性判断等
1
websUrlHandlerDefine(&byte_4AA6CC, 0, 0, websAuthHandler, 1);
- 根据一层路径
/goform
,匹配回调函数websFormHandler:1
websUrlHandlerDefine("/goform", 0, 0, websFormHandler, 0);
- 根据二层路径
/websLogin
,匹配回调函数websLogin:1
websFormDefine((int)"websLogin", (int)websLogin);
因此,对于GoAhead作为server的设备来说,如果想挖到认证前的RCE的话,可以主要从优先级为0的登录处理回调函数入手,找到绕过认证的方法,或者看回调函数是否存在缓冲区溢出等能够劫持控制流的漏洞。
漏洞挖掘思路
历史版本漏洞
版本号的确定:搜索字符串GoAhead-Webs,可以确定版本,从而判断是否受到历史漏洞的影响
漏洞编号 | 影响版本 | 漏洞概述 |
---|---|---|
CVE-2017-17562 | < 3.6.5 | 初始化CGI时,在HTTPD请求参数中,使用特殊的参数名LD_PRELOAD劫持libc库,进而远程命令执行 |
CVE-2021-42342 | 4.x、5.x~5.1.5 | 对上述的一个绕过 |
如上的两个漏洞如果要达成认证前RCE,需要/cgi-bin/一层路径可以未授权访问
漏洞案例1:发生在websSecurityHandler中的认证绕过
CVE-2020-15633
该漏洞是发生在LAN口的一个登录认证绕过漏洞,影响设备DIR-867、DIR-878、DIR-882,固件版本1.20B10_BETA。漏洞产生的原因是在处理HNAP请求的过程中,验证用户登录逻辑时处理不当,使用strstr函数来检查无需验证权限的接口,导致可以构造特定URI来绕过身份认证,从而访问敏感接口。
设备采用lighttpd作为webserver,根据配置会将HNAP请求转发到程序/bin/prog.cgi进行处理,prog.cgi是基于GoAhead开发。
1 | fastcgi.server = ( |
漏洞触发过程的函数调用如下:
1 | sub_423ECC -> 0 |
- 在函数sub_423ECC中,会使用函数strstr比较环境变量REQUEST_URI(也就是请求路径)中是否含有字符串列表actions_list中的字符串,然后触发到return 0。
1
2
3
4
5if ( a1[57] && strstr(a1[57], &actions_list[32 * index]) )// REQUEST_URI
{
if ( strcmp(&actions_list[32 * index], "/HNAP1/") || !a1[50] || strcmp(a1[50], "POST") )
return 0;
} - 然后返回到函数sub_4249EC,触发该函数继续返回0;
- 再返回到函数websSecurityHandler中,使得该认证函数返回0,达到认证绕过;
1
websUrlHandlerDefine("/", 0, 0, websSecurityHandler, 1);
其他认证后的接口(大多存在)
大多基于GoAhead开发的server都存在认证后的漏洞,例如缓冲区溢出、命令执行等等。