CVE-2020-7248 OpenWRT libubox标记二进制数据序列化漏洞(更新中)

发布于:2024-07-24 ⋅ 阅读:(174) ⋅ 点赞:(0)

提要

        该文档会一直处于更新当中,当状态为完毕后,才是更新完成。由于网络上关于该漏洞原理的分析文档和资源实在是太少,而本人关于该方向也才是刚入门,能力有限,所以复现需要的时间较长,需要补充和学习的东西较多,若大家有什么建议,欢迎评论区一起讨论进步。

漏洞简介

        OpenWrt是一套针对嵌入式设备的Linux操作系统,libubox是其中的一个提供事件循环、二进制格式处理、Linux链表实现和JSON辅助处理的基础库。

        该漏洞与标记的二进制数据的JSON转换部分(blob)有关。Blob属性有足够大的double类型数值,由blobmsg_format_json处理,会溢出为堆栈上分配的JSON输出指定的缓冲区数组。攻击者可以向blobmsg_format_json提供特制的二进制blob或JSON输入,从而在double值序列到JSON缓冲区时造成堆栈溢出。

        libubox库是OpenWrt项目的核心组件,并在项目的其他部分使用。通过在项目的LXR[1]中查找上述易受攻击的blobmsg_format_json函数,可以看到这些相互依赖关系,该函数揭示了netifd、procd、ubus、rpcd、uhttpd中的引用。也就是说,依赖调用到blobmsg_format_json的有很多其它的部分,我们本次复现主要针对rpcd对这个漏洞的利用。

        简单介绍一下rpcb

参考:

[OpenWrt Wiki] Security Advisory 2020-01-31-2 - libubox tagged binary data JSON serialization vulnerability (CVE-2020-7248)

论文:A Grounded Theory Based Approach to Characterize So! ware" Attack Surfaces

受影响的漏洞版本:

        OpenWrt 18.06.0 - 18.06.6

        OpenWrt 19.07.0-rc1 - 19.07.0

漏洞原理分析

        本次我们选取的漏洞分析环境的版本是Openwrt18.06.5,具体的漏洞的源代码等内容我们在另一篇博客,关于CVE-2020-7982的漏洞复现中,已经提到了代码的位置,如下地址参考:

CVE-2020-7982 OpenWrt 远程命令执行漏洞学习(完结)_openwrt 漏洞-CSDN博客

本次实验要分析的源代码的参考地址如下,后续我们不再赘述

https://git.openwrt.org/?p=project/libubox.git;a=blob;f=blobmsg_json.c;h=ec8b482c30c96a355aca58651632bc509a16bedf;hb=HEAD

根据漏洞的介绍,我们需要先找到libubox的源代码

该项目的地址如下

https://git.openwrt.org/?a=project_list;pf=project

之后我们在blobmsg_json.h中可以找到我们想要的函数blobmsg_format_json

根据函数的内容声明,其会先调用blobmsg_format_json_with_cb这个函数,我们可以在blobmsg_json.c文件中找到这个函数

首先定义了一个strbuf的结构体s,并且初始化内容为0。strbuf 结构体通常用于在C语言中表示可变长度的字符串缓冲区。它通常包含有关缓冲区内容和大小的信息,以便可以方便地进行字符串操作。

一般而言,strbuf 结构体可能包含以下成员:

  • char *buf:指向存储字符串数据的内存缓冲区的指针。
  • size_t len:当前字符串的长度。
  • size_t alloc:分配给缓冲区的内存空间大小。

之后其调用函数setup_strbuf 具体如下图

我们首先先找到blob_attr这个数据结构的结构样式,我们可以找到blob.h这个文件,我们在其中可以看到blob_attr这个结构,如下图所示

其中uint32_t是一个32位,也就是4字节的数据类型,而data是一个可变长度的数据类型,所以一般来说,原始的blob_attr结构的长度应该是32位。

那么首先setup_strbuf函数会调用blob_len函数来进行处理,我们同样可以在blob.h文件中找到函数blob_len,如下图

我们可以根据最开始的引用,

在文件utils.h中找到函数be32_to_cpu的结构,最终我们发现了两个

总的来说,其作用就是定义了一个内联函数 blob_len,用于计算属性的有效载荷长度。通过 be32_to_cpu 宏将 attr->id_len 中的大端字节序转换为CPU本地字节序。CPU本地字节序则表示CPU处理器默认采用的字节序方式。因为不同的CPU架构可能采用不同的字节序,所以需要在不同字节序之间进行转换,以确保数据在不同平台上的正确解释和处理。这具体可以参考计组相关的知识。然后使用按位与操作符和 BLOB_ATTR_LEN_MASK 来提取有效载荷长度,并减去 struct blob_attr 的大小。其中我们在blob.h中看到了

        这样一个定义,BLOB_ATTR_ID_MASK被定义为了0x7f000000,其二进制的形式是1111111000000000000000000000000,根据按位与的运算逻辑,本质就是把有效载荷数据的前7位进行按位与操作,而后续多出来的字节数据都会被置为0,最终其有效长度也是8x4bit=32bit,也就是4B的长度大小。

        最终我们获得了attr的长度,将其赋值给s的len这样一个成员变量。

漏洞环境搭建

漏洞复现

payload

$ ubus call luci getFeatures '{ "banik": 00192200197600198000198100200400.1922 }'

漏洞修复


网站公告

今日签到

点亮在社区的每一天
去签到