zl程序教程

您现在的位置是:首页 >  前端

当前栏目

Zyxel 认证绕过补丁分析 (CVE-2022-0342)

认证 分析 2022 补丁 绕过 CVE
2023-06-13 09:17:11 时间

Zyxel USG/ZyWALL系列固件版本4.20至4.70、USG FLEX系列固件版本4.50至5.20、ATP系列固件版本4.32至5.20、V**系列固件版本4.30至5.20、NSG系列固件版本的CGI程序存在身份验证绕过漏洞V1.20 到 V1.33 补丁 4,这可能允许攻击者绕过 Web 身份验证并获得设备的管理访问权限。

Zyxel 如何管理 HTTP 身份验证

在 Zyxel 设备上,Web 界面通过 Apache HTTP 服务器进行管理。主要配置文件是 /usr/local/zyxel-gui/httpd.conf 其中包含以下行:

LoadModule auth_zyxel_module modules/mod_auth_zyxel.so

此Apache 模块由 Zyxel 开发和维护,并管理身份验证过程。

登录过程会生成一个名为“authtok”的 cookie,用于在下一个请求中对用户进行身份验证。

比较补丁

将mod_auth_zyxel.so的两个版本与Bindiff进行比较,可以很容易地识别修复问题的修改例程:

“check_authtok”函数是Apache直接调用的函数,用于验证身份验证;“create_server_config”也已修改。

根据分析,可以看到部分代码已被删除:

易受攻击的伪代码是:

打补丁的是:

基本上,在某些情况下与神秘的“非 GUI 访问”相关的允许无需身份验证直接访问的所有代码都已被删除。

例程“get_server_conf”获取 /tmp/__HTTP_SERVER_CONFIG 文件的内容并将其放入一些变量中:

然后将这些变量与Apache 传递给“check_authtok”函数的数据结构的一部分进行比较。

根据Apache 文档,传递给函数的数据结构是“request_rec”,它在 http://svn.apache.org/repos/asf/httpd/httpd/trunk/include/httpd.h中定义

比较期间使用的第一个指针是“request_rec + 4”,这意味着 32 位处理器上结构的第二个元素(希望编译器优化没有混淆数据结构的顺序)。在这种情况下“conn_rec *connection;”:

struct request_rec {
    /** The pool associated with the request */
    apr_pool_t *pool;
    /** The connection to the client */
    conn_rec *connection;
    /** The virtual host for this request */
    server_rec *server;
    /** Pointer to the redirected request if this is an external redirect */
    request_rec *next;
    /** Pointer to the previous request if this is an internal redirect */
    request_rec *prev;

访问的第二个指针是“conn_rec”结构的第 4 个元素,即“apr_sockaddr_t *local_addr;” 在同一文件中定义:

struct conn_rec {
    /** Pool associated with this connection */
    apr_pool_t *pool;
    /** Physical vhost this conn came in on */
    server_rec *base_server;
    /** used by http_vhost.c */
    void *vhost_lookup_data;
    /* Information about the connection itself */
    /** local address */
    apr_sockaddr_t *local_addr;
    /** remote address; this is the end-point of the next hop, for the address
     *  of the request creator, see useragent_addr in request_rec
     */
    apr_sockaddr_t *client_addr;

访问的第三个指针是apr_network_io.h文件中定义的 apr_sockaddr_t 的第 4 个元素,它是“apr_port_t端口;” :

239 struct apr_sockaddr_t {
240     /** The pool to use... */
241     apr_pool_t *pool;
242     /** The hostname */
243     char *hostname;
244     /** Either a string of the port number or the service name for the port */
245     char *servname;
246     /** The numeric port */
247     apr_port_t port;
248     /** The family */
249     apr_int32_t family;

因此,与 get_server_conf() 函数的结果进行比较的数据是收到请求的本地端口。

也可以通过查看“get_server_conf”函数访问的文件来确认这一点,该文件包含 Apache HTTP 服务器使用的主要端口:

问题的根本原因

我们需要了解为什么该检查会影响身份验证。由于检查是在套接字上进行的,我们可以假设两种不同的场景:

  • 我们可以连接到其他端口,通过修改HTTP协议的“Host”头,去到不同的虚拟主机;
  • 我们可以从一些虚拟主机访问一些 CGI,这些虚拟主机可通过与控制文件中存在的端口不同的端口访问。

从理论上讲,Apache HTTP Server 应该根据监听发生的端口和接口来保证环境的分离,因此我们的第一个假设不太可能是正确的。

让我们检查一下 Apache 在我们的系统上使用了哪些端口:

通过浏览器访问 TCP 端口 8008 我们得到:

貌似是2FA相关的东西,配置在/var/zyxel/service_conf/httpd_twofa.conf文件中:

访问 TCP 端口 54088 我们得到这个页面:

好像是和blocking alert page相关的东西,配置在/var/zyxel/service_conf/cf_blockpage_https.conf文件中:

通过查看Apache HTTP Server的主配置文件(/usr/local/zyxel-gui/httpd.conf)可以看到“cgi-bin”目录配置在全局区域,也就是说所有的CGI将可以在每个不同的虚拟主机上访问:

开发

将迄今为止发现的所有信息放在一起,利用起来非常容易。基于补丁,我们可以假设所有 CGI 都可以在 Apache 公开的所有接口上访问。

使用无效 cookie 通过标准端口访问 CGI 将返回身份验证错误:

但是通过非标准端口访问相同的 CGI 将提供对 CGI 的完全访问权限,因此也可以访问设备配置: