原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

IoT 4周前 admin
91 0 0
作者:fan@知道创宇404实验室
时间:2024年9月6日



 1 前言


参考资料

8月5日网上披露了 CVE-2024-399226 [1],影响多款 GL-iNet 路由器,随后开始漏洞应急。起初对 GL-iNet 路由器不了解导致踩了很多坑、浪费了不少时间,因此在做完应急后对这次漏洞分析和固件仿真进行记录。




 2 产品介绍


参考资料

GL.iNet 是一家专注于智能路由器和网络设备开发的科技公司。成立于 2009 年,总部位于中国,该公司的产品以 OpenWrt 操作系统为基础,提供高度的可定制性和灵活性。公司致力于为家庭、企业以及工业物联网环境提供可靠的网络解决方案。GL.iNet 的设备以其开源特性、强大的功能和优秀的用户体验而受到开发者、网络安全专家和高级用户的青睐。

OpenWrt 是一个基于 Linux 的开源嵌入式操作系统,专为网络设备(如路由器、网关和接入点)设计。与传统的路由器固件不同,OpenWrt 不是单一的、不可变的固件,而是一个完整且可扩展的操作系统,允许自定义以适应任何应用程序。

OpenResty 是一个基于 Nginx的高性能 Web 平台,它将 Lua 脚本引擎嵌入到 Nginx 中,使开发者可以通过 Lua 脚本编写高度可定制的 Web 服务,用来处理复杂的 web 逻辑和 API 请求。OpenResty 通常用于高并发、低延迟的 Web 应用程序开发,特别是在需要处理复杂逻辑或与外部服务交互时。

这种组合使得 GL.iNet 路由器不仅仅是一个网络设备,还可以作为一个小型的 Web 服务器或应用平台。




 3 环境模拟


参考资料

3.1 固件提取

GL.iNet 官网提供历史固件下载[2]。

固件版本:GL-AX1800 Flint 4.5.16

sysupgrade-glinet_ax1800 文件夹下存在 root 文件。

$ file root 
root: Squashfs filesystem, little endian, version 4.0, 44613986 bytes, 4754 inodes, blocksize: 262144 bytes, created: Thu Mar 21 13:28:00 2024

使用 binwalk,从 root 中提取 Squashfs 文件系统。

$ binwalk -Me root

查看 bin/busybox 得知是 32位arm 架构。

$ file squashfs-root/bin/busybox 
squashfs-root/bin/busybox: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-arm.so.1, stripped

3.2 QEMU模拟

使用 qemu-system-arm 从系统角度进行模拟,此时需要一个 arm 架构的内核镜像和文件系统,可以在这个网站下载[3]。

vmlinuz-3.2.0-4-vexpress  linux内核镜像文件
initrd.img-3.2.0-4-vexpress RAM磁盘映像文件
debian_wheezy_armhf_standard.qcow2 虚拟磁盘映像文件

启动虚拟环境。

$ sudo qemu-system-arm -M vexpress-a9 -cpu cortex-a15 -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

//默认可以不指定 cpu 模型,我在模拟过程中遇到报错所以指定了 cpu。

Illegal instruction

启动后用户名和密码都是 root 即可登录模拟的系统。

接下来在宿主机创建一个网卡,使 qemu 内能和宿主机通信。

宿主机安装依赖。

$ sudo apt-get install bridge-utils uml-utilities

将如下代码保存为 net.sh 并运行即可。

#!/bin/bash

# Enable IP forwarding
sudo sysctl -w net.ipv4.ip_forward=1

# Reset iptables
sudo iptables -t nat -F
sudo iptables -t nat -X
sudo iptables -P FORWARD ACCEPT

# Set up NAT
sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE

# Accept traffic on tap0
sudo iptables -I FORWARD -i tap0 -j ACCEPT
sudo iptables -I FORWARD -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT

# Create and configure tap0
sudo ip tuntap add dev tap0 mode tap
sudo ifconfig tap0 192.168.100.254 netmask 255.255.255.0 up

然后配置 qemu 虚拟系统的路由,在 qemu 虚拟系统中运行 net.sh 并运行。

#!/bin/sh
ifconfig eth0 192.168.100.2 netmask 255.255.255.0
route add default gw 192.168.100.254

//虚拟系统可能没有 vim 或 nano ,使用 echo 一行一行写。

这样宿主机和模拟环境互通,使用 scp 将 squashfs-root 文件夹上传到 qemu 系统中的 /root 路径下。

scp -r squashfs-root/ [email protected]:/root

然后挂载 proc 、 dev ,最后 chroot 即可。

root@debian-armhf:~# mount -t proc /proc ./squashfs-root/proc
root@debian-armhf:~# mount -o bind /dev ./squashfs-root/dev
root@debian-armhf:~# chroot ./squashfs-root/ sh


BusyBox v1.33.2 (2024-03-21 13:28:00 UTC) built-in shell (ash)

/ # ls
bin etc lib overlay rom sbin tmp var
dev init mnt proc root sys usr www



 4 漏洞复现


参考资料

启动 web 服务,前文已经介绍过 GL.iNet 路由器利用 OpenResty 来增强其 web 管理界面和 API 的功能。而 OpenResty 是基于 Nginx 的 web 平台,内置 Lua 脚本支持,所以首先启动 Nginx 服务。

尝试运行 /etc/init.d 下 nginx 脚本(/etc/init.d 目录通常包含系统启动和管理各种服务的脚本,如果需要启动某个服务,通常可以在该目录中找到相应的脚本)。

查看 /etc/init.d/nginx 如何手动启动 nginx

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图1 nginx 脚本源码

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图2 启动 nginx 报错

创建缺少的文件夹再次启动 nginx

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图3 再次启动 nginx

看样子 nginx 好像起来了,访问 web 却是 404

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图4 web 访问 404

这个时候已经没什么头绪了,find 一下所有 nginx 相关文件试试。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图5 查找 nginx 相关文件

每个文件都看看,发现 /etc/uci-defaults/80_nginx-oui 脚本。

/etc/uci-defaults/80_nginx-oui 脚本的主要作用是配置和调整Nginx的相关文件,确保Web服务能够正常运行。

尝试运行 /etc/uci-defaults/80_nginx-oui 看看是否能修复 404 问题。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图6 运行 /etc/uci-defaults/80_nginx-oui

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图7 web 访问成功

成功修复,接下来尝试漏洞复现,先看一下披露的 PoC

curl -H 'glinet: 1' 127.0.0.1/rpc -d '{"method":"call", "params":["", "s2s", "enable_echo_server", {"port": "7 $(touch /root/test)"}]}'

从 PoC 来看好像只能通过 127.0.0.1 利用,先使用 192.168.100.2 试试。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图8 PoC 远程利用

拒绝访问,再使用 127.0.0.1 (之前的会话因为启动 nginx ,需要 ssh 再创建一个会话)。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图9 PoC 本地利用

这次报错为内部错误。继续找问题。根据 PoC 可知请求的路径是rpc ,在 /etc/nginx 下的 nginx 配置文件中查找 rpc 相关信息。

在 /etc/nginx/conf.d/gl.conf 找到请求 rpc 路径的处理方法。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图10 /etc/nginx/conf.d/gl.conf 源码

跟进到 /usr/share/gl-ngx/oui-rpc.lua

代码来看 /usr/share/gl-ngx/oui-rpc.lua 是处理 HTTP POST 请求 jSON-RPC 调用的。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图11 /usr/share/gl-ngx/oui-rpc.lua 源码开头部分

以上代码实现模块导入、请求方式验证和读取请求体。

要注意 ubus 服务是 OpenWrt 系统中一个进程间通信框架,需要启动。

HTTP 请求仅允许 POST ,拒绝其他方式访问。

/usr/share/gl-ngx/oui-rpc.lua 定义了多个处理函数,每个函数对应不同的 rpc 方法(因为 PoC 通过 call 方法调用 s2s.enable_echo_server 进行攻击,所以只截取 rpc_method_call 方法代码)。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图12 /usr/share/gl-ngx/oui-rpc.lua 源码核心部分

rpc_method_call 进行参数校验、会话检查和 Ubus 调用:

  1. 确保 params 中至少三个元素且元素类型正确。

  2. 检查 sid 是否有效,并通过 rpc.access 验证访问权限。

  3. 如果上述判断均通过,使用 rpc.call 执行指定的 Ubus 对象和方法。

继续跟进 /usr/lib/lua/oui/rpc.lua 查看 rpc.access 和 rpc.call 实现。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图13 M.seesion 和 M.access 函数源码

access 通过 is_local 判断是否本地请求。对于本地请求和 glinet 标头的请求,总是允许访问(确定了只能本地利用)。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图14 M.call 函数代码

M.call 函数是核心的 rpc 调用处理器,执行以下步骤:

  1. 检查请求的对象是否已加载,如果未加载,则尝试从 /usr/lib/oui-httpd/rpc/ 目录下加载脚本文件。

  2. 如果脚本文件存在且加载成功,将对象的方法注册到 objects 表中。

  3. 如果无法从 /usr/lib/oui-httpd/rpc/ 目录下加载脚本文件或者找不到对象或方法,则调用 glc_call 执行。

查看 /usr/lib/oui-httpd/rpc/ 目录下是二进制 s2s.so 文件,无法直接加载,则通过 glc_call 调用 /cgi-bin/glc 执行 C 程序实现的 RPC 方法。

继续跟进 /www/cgi-bin/glc 文件。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图15 /www/cgi-bin/glc 反编译源码

大致实现逻辑与 /usr/share/gl-ngx/oui-rpc.lua 类似,请求方式验证和读取请求体后动态加载并调用函数,区别在于 /www/cgi-bin/glc 使用 dlopen 动态加载对应的共享库(.so 文件)。

如此看来 PoC 满足/usr/share/gl-ngx/oui-rpc.lua 和 /usr/lib/lua/oui/rpc.lua 两段代码逻辑。

curl -H 'glinet: 1' 127.0.0.1/rpc -d '{"method":"call", "params":["", "s2s", "enable_echo_server", {"port": "7 $(touch /root/test)"}]}'

请求发送一个 POST 请求到 rpc 路径,携带 JSON 数据:

{
"method": "call",
"params": ["", "s2s", "enable_echo_server", {"port": "7 $(touch /root/test)"}]
}

权限校验参数检查均通过但是报内部错误,打印 nginx 日志看看。

修改 /etc/nginx/nginx.conf 并重启 nginx

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图16 修改 /etc/nginx/nginx.conf 配置文件

再用 PoC 测试一次查看日志。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图17 nginx 日志信息

报错信息显示 ubus-proxy 和 fcgiwrap 未启动或未正常配置,尝试启动 ubus fcgiwrap

ubus: /sbin/ubusd
fcgiwrap: /etc/init.d/fcgiwrap
原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析
原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图18 PoC 本地利用成功

终于复现成功了。




 5 漏洞分析


参考资料

漏洞只能本地利用未免有些太鸡肋了,继续进行漏洞分析,再尝试寻找远程利用的方法。

通过 PoC 可知漏洞通过 s2s API 传递恶意 shell 命令,分析一下 /usr/lib/oui-httpd/rpc/s2s.so

漏洞出现在 s2s.enable_echo_server 检查并启动 echo_server 过程中:

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图19 /usr/lib/oui-httpd/rpc/s2s.so 反编译源码

虽然代码中检查了 port 参数是否为有效的数字,但没有严格限制其内容,仅验证了其是否为正数且小于 65535。然而,在字符串形式下,它仍然允许嵌入特殊字符,如 $(),这些字符可以被 shell 解释器解析为命令。

在 v16(v27, 128, "%s -p %s -f", "/usr/bin/echo_server", v9); 中,port 参数 (v9) 被直接传递给 snprintf 函数,生成的命令字符串随后通过 system(v27); 执行。

由于 v9 可以包含类似 7 $(touch /root/test) 的字符串,shell 会执行其中的命令 touch /root/test,导致命令注入。

漏洞成因分析起来还是比较容易的,最后一个问题,如何通过远程实现漏洞利用。公开的 PoC 是通过 rpc 路径调用 call 方法触发 s2s.enable_echo_server 漏洞。然而,由于会在 rpc.access 阶段进行权限校验,因此需要找到一个不需要权限校验的路径来执行 call 方法。

回过头再看一眼 /usr/lib/lua/oui/rpc.lua 的 glc_call 方法。

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图20 glc_call 函数源码

如果直接请求 /cgi-bin/glc 路径,将会调用 glc_call 函数。glc_call 函数会向另一个内部路径(/cgi-bin/glc)发起一个内部 HTTP POST 请求,并传递方法名称、参数等信息。执行 call 方法并且跳过之前的权限校验,修改 PoC 尝试远程利用。

curl http://192.168.100.2/cgi-bin/glc -d '{"object":"s2s","method":"enable_echo_server","args":{"port":"7 $(touch /root/test2024)"}}'
原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析
原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

图21 PoC 远程利用成功




 6 总结


参考资料

漏洞应急最烦环境弄不好,这次就因为一开始不了解 GL-iNet 路由器导致纯在瞎折腾浪费时间,最后在大佬的指点下搭建好环境。记录过程中尽量复刻了当时工作的操作顺序,逻辑上有很多地方其实有更简单的解决方法不用绕这么多弯,诸君见笑。




 7 相关链接


参考资料
[1] 漏洞详情:
https://github.com/gl-inet/CVE-issues/blob/main/4.0.0/s2s%20interface%20shell%20injection.md
[2] 固件下载:

https://dl.gl-inet.cn/

[3] 内核镜像和文件系统下载:

https://people.debian.org/~aurel32/qemu/



原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析




作者名片



原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析
往 期 热 门
(点击图片跳转)

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

“阅读原文”更多精彩内容!

原文始发于微信公众号(知道创宇404实验室):原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析

版权声明:admin 发表于 2024年9月6日 下午3:50。
转载请注明:原创 Paper | GL-iNet 路由器 CVE-2024-39226 漏洞分析 | CTF导航

相关文章