首页
社区
课程
招聘
[原创]Realtek RTL8195A Wi-Fi漏洞分析
发表于: 2021-2-6 22:29 11797

[原创]Realtek RTL8195A Wi-Fi漏洞分析

2021-2-6 22:29
11797

本文主要分析vdoo发现的一些RTL8195A WIFI模块的漏洞。

下载最新的SDK

解压后在下面目录里面有一堆.a文件,漏洞就存在与这些.a里面

为了分析的方便,首先将.a链接成.so

然后就可以用IDA加载so进行分析了

本节基于最新的SDK和ameba-2.0.4-build20180817有漏洞版本SDK进行分析,同时对补丁和漏洞进行分析

ClientEAPOLKeyRecvd函数会调用CheckMIC来处理数据

EAPOLMsgRecvd为外部数据

Octet为数据地址,Length为数据长度,这里没有检查Length,从而导致栈溢出。

最新版本的CheckMIC函数如下

在最新版的SDK里面会检查length不能超过0x200

调用点

EAPOLMsgRecvd为外部数据,Octet为数据地址,Length为数据长度

问题还是位于CheckMIC函数

问题逻辑是,首先从数据包里面取出了2个字节作为长度存放到v8,然后没有检查v8是否会大于Length,就传给rt_md5_hmac去算一个hash,在rt_md5_hmac里面会越界读。

补丁版本

增加了长度检查

漏洞应该是位于ClientEAPOLKeyRecvd,函数会调用DecWPA2KeyData

EapolKeyMsg为外部数据,这里3个参数表示长度,直接从外部数据中取出,然后在DecWPA2KeyData里面会解密数据

解密结果会存放在tmp2,tmp2是栈数组,大小为257,如果keylen比较大就会导致栈溢出。

补丁,在调用ClientEAPOLKeyRecvd时会检查取出的keylen.

这个漏洞位于 AES_UnWRAP 函数,由于函数的二进制代码位于rom,这里直接分析原文提供的代码

主要问题是AES_UnWRAP循环解密时会不断把结果拷贝到栈数组R中,如果cipher_len过大,就会溢出数组R。

R的定义

漏洞位于ClientEAPOLKeyRecvd,函数会调用DecWPA2KeyData

EapolKeyMsg为外部数据,这里3个参数表示长度,直接从外部数据中取出,然后在DecWPA2KeyData里面会解密数据

DecWPA2KeyData解密完数据后会把keylen长度的数据拷贝到 kout,即decrypted_data 其大小为 128字节,所以可能导致栈溢出。

修复方案

额外增加了一个参数,表示Kout的大小,然后在DecWPA2KeyData里面会去校验

漏洞位于ClientEAPOLKeyRecvd

其中 v23 指向外部数据,然后从v23里面取出2字节的数据作为长度,调用rtl_memcpy将数据拷贝到栈上,decrypted_data大小为128字节,栈溢出。

该漏洞在最新版本中依然存在

https://www.vdoo.com/blog/realtek-rtl8195a-vulnerabilities-discovered

my blog
https://www.cnblogs.com/hac425/p/14375707.html

https://github.com/ambiot/amb1_arduino/blob/master/Arduino_package/release/ameba_1-2.0.10-build20210203.tar.gz
https://github.com/ambiot/amb1_arduino/blob/master/Arduino_package/release/ameba_1-2.0.10-build20210203.tar.gz
ameba_1-2.0.10-build20210203\hardware\variants\rtl8195a
ameba_1-2.0.10-build20210203\hardware\variants\rtl8195a
ar -x lib_ameba.a
ar -x lib_codec.a
ar -x lib_hs_uart_redirect.a
ar -x lib_mdns.a
ar -x lib_p2p.a
ar -x lib_rtlstd.a
ar -x lib_sdcard.a
ar -x lib_usbh.a
ar -x lib_wlan.a
ar -x lib_xmodem.a
ar -x lib_arduino_alexa.a
ar -x lib_google_cloud_iot.a
ar -x lib_i2c_redirect.a
ar -x lib_mmf.a
ar -x lib_platform.a
ar -x lib_rtsp.a
ar -x lib_usbd.a
ar -x lib_websocket.a
ar -x lib_wps.a
rm console_i2c.o
rm alexa_mem.o
arm-none-eabi-gcc --shared *.o -o  liball.so
ar -x lib_ameba.a
ar -x lib_codec.a
ar -x lib_hs_uart_redirect.a
ar -x lib_mdns.a
ar -x lib_p2p.a
ar -x lib_rtlstd.a
ar -x lib_sdcard.a
ar -x lib_usbh.a
ar -x lib_wlan.a
ar -x lib_xmodem.a
ar -x lib_arduino_alexa.a
ar -x lib_google_cloud_iot.a
ar -x lib_i2c_redirect.a
ar -x lib_mmf.a
ar -x lib_platform.a
ar -x lib_rtsp.a
ar -x lib_usbd.a
ar -x lib_websocket.a
ar -x lib_wps.a
rm console_i2c.o
rm alexa_mem.o
arm-none-eabi-gcc --shared *.o -o  liball.so
CheckMIC(v5->EAPOLMsgRecvd, v5->PTK, &v5->EAPOLMsgRecvd)
CheckMIC(v5->EAPOLMsgRecvd, v5->PTK, &v5->EAPOLMsgRecvd)
bool __fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8 *key, int keylen)
{
 
  v3 = EAPOLMsgRecvd.Octet;
  v4 = EAPOLMsgRecvd.Octet[20];
  v6 = &tmpbuf[95];
  rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
bool __fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8 *key, int keylen)
{
 
  v3 = EAPOLMsgRecvd.Octet;
  v4 = EAPOLMsgRecvd.Octet[20];
  v6 = &tmpbuf[95];
  rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
 
bool __fastcall CheckMIC_constprop_14(int data, unsigned int length, int a3)
{
 
 
  v6 = *(data + 20);
  if ( length > 0x200 // 新增length的检查
    return 0;
  v8 = &stack[95];
  freertos_memcpy_0(stack, data, length);  //
  freertos_memset_0(&stack[95], 0, 16);
bool __fastcall CheckMIC_constprop_14(int data, unsigned int length, int a3)
{
 
 
  v6 = *(data + 20);
  if ( length > 0x200 // 新增length的检查
    return 0;
  v8 = &stack[95];
  freertos_memcpy_0(stack, data, length);  //
  freertos_memset_0(&stack[95], 0, 16);
 
CheckMIC_constprop_14(sta->EAPOLMsgRecvd.Octet, sta->EAPOLMsgRecvd.Length, sta->PTK) )
CheckMIC_constprop_14(sta->EAPOLMsgRecvd.Octet, sta->EAPOLMsgRecvd.Length, sta->PTK) )
bool __fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8 *key, int keylen)
{
 
 
  v3 = EAPOLMsgRecvd.Octet;
  v4 = EAPOLMsgRecvd.Octet[20];
  v6 = &tmpbuf[95];
  rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
  flag = v4 & 7;
  v8 = (ntohs_0(*&tmpbuf[16]) + 4);  // 从外部数据取出长度 v8
  if ( flag == 1 )
  {
    rt_md5_hmac_0(&tmpbuf[14], v8, key, 16, &tmpbuf[95]); // 作为 rt_md5_hmac参数
bool __fastcall CheckMIC(OCTET_STRING EAPOLMsgRecvd, unsigned __int8 *key, int keylen)
{
 
 
  v3 = EAPOLMsgRecvd.Octet;
  v4 = EAPOLMsgRecvd.Octet[20];
  v6 = &tmpbuf[95];
  rtl_memcpy_0(tmpbuf, EAPOLMsgRecvd.Octet, EAPOLMsgRecvd.Length);
  flag = v4 & 7;
  v8 = (ntohs_0(*&tmpbuf[16]) + 4);  // 从外部数据取出长度 v8
  if ( flag == 1 )
  {
    rt_md5_hmac_0(&tmpbuf[14], v8, key, 16, &tmpbuf[95]); // 作为 rt_md5_hmac参数
 
v9 = (ntohs_0(*&stack[16]) + 4);
if ( (length - 13) <= v9 )  // 检查长度
  return 0;
if ( (v6 & 7) != 1 )
{
  if ( (v6 & 7) == 2 )
  {
    v8 = digest;
    rt_hmac_sha1_0(&stack[14], v9, a3, 16, digest);
    return rtl_memcmp_0(v8, data + 95, 16) == 0;
  }
v9 = (ntohs_0(*&stack[16]) + 4);
if ( (length - 13) <= v9 )  // 检查长度
  return 0;
if ( (v6 & 7) != 1 )
{
  if ( (v6 & 7) == 2 )
  {
    v8 = digest;
    rt_hmac_sha1_0(&stack[14], v9, a3, 16, digest);
    return rtl_memcmp_0(v8, data + 95, 16) == 0;
  }
if ( !DecWPA2KeyData_0(
        v5,
        EapolKeyMsg + 95,
        (EapolKeyMsg[94] + (EapolKeyMsg[93] << 8)),
        &v5->PTK[16],
        16,
        decrypted_data) )
if ( !DecWPA2KeyData_0(
        v5,
        EapolKeyMsg + 95,
        (EapolKeyMsg[94] + (EapolKeyMsg[93] << 8)),
        &v5->PTK[16],

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-2-6 22:30 被暗香沉浮编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (3)
雪    币: 14539
活跃值: (17553)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2021-2-8 15:10
0
雪    币: 1781
活跃值: (1326)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
RTL如果资料公开;漏洞更多
2021-2-8 19:16
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
大佬
2021-8-17 18:07
0
游客
登录 | 注册 方可回帖
返回
//