• [原创] Realtek RTL8195A Wi-F历史i漏洞分析和新漏洞挖掘


    前言

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

    环境搭建

    下载最新的SDK

    https://github.com/ambiot/amb1_arduino/blob/master/Arduino_package/release/ameba_1-2.0.10-build20210203.tar.gz
    

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

    ameba_1-2.0.10-build20210203hardwarevariants
    tl8195a
    

    为了分析的方便,首先将.a链接成.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 -w  -shared *.o -o  liball.so
    

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

    漏洞分析

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

    VD-1406 (CVE-2020-9395) – Stack-based buffer overflow vulnerability

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

    CheckMIC(v5->EAPOLMsgRecvd, v5->PTK, &v5->EAPOLMsgRecvd)
    

    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);
    

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

    最新版本的CheckMIC函数如下

    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);
    

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

    调用点

    CheckMIC_constprop_14(sta->EAPOLMsgRecvd.Octet, sta->EAPOLMsgRecvd.Length, sta->PTK) )
    

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

    VD-1407 – Read out of bounds vulnerability

    问题还是位于CheckMIC函数

    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参数
    

    问题逻辑是,首先从数据包里面取出了2个字节作为长度存放到v8,然后没有检查v8是否会大于Length,就传给rt_md5_hmac去算一个hash,在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;
        }
    

    增加了长度检查

    VD-1408 – Stack-based buffer overflow vulnerability

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

              if ( !DecWPA2KeyData_0(
                      v5,
                      EapolKeyMsg + 95,
                      (EapolKeyMsg[94] + (EapolKeyMsg[93] << 8)),
                      &v5->PTK[16],
                      16,
                      decrypted_data) )
    

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

    int __fastcall DecWPA2KeyData(WPA_STA_INFO *pStaInfo, unsigned __int8 *key, int keylen, unsigned __int8 *kek, int keklen, unsigned __int8 *kout)
    {
    
      *default_key_iv = 0xA6A6A6A6;
      *&default_key_iv[4] = 0xA6A6A6A6;
      if ( (pStaInfo->EapolKeyMsgRecvd.Octet[2] & 7) == 1 )
      {
        rtl_memcpy_0(tmp1, pStaInfo->EAPOLMsgRecvd.Octet + 63, 16);
        rtl_memcpy_0(&tmp1[16], kek, keklen);
        sub_14D5C(&rc4_ctx, tmp1, keklen + 16);
        rt_arc4_crypt_0(&rc4_ctx, tmp2, tmp1, 256);
        rt_arc4_crypt_0(&rc4_ctx, tmp2, pStaInfo->EapolKeyMsgRecvd.Octet + 95, keylen);
    

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

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

          v13 = (key_msg[94] + (key_msg[93] << 8));
          if ( sta->EAPOLMsgRecvd.Length - 0x70 <= v13
            || !DecWPA2KeyData_0(sta, key_msg + 95, v13, &sta->PTK[16], 16, &stack, 255) )
    

    VD-1409 – Stack-based buffer overflow vulnerability

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

    
    void AES_UnWRAP(unsigned char * cipher, int cipher_len,
    			   		 unsigned char * kek,	int kek_len,
    			    		unsigned char * plain)
    {
    
        v5__cipher_len = (cipher_len + 7) & (cipher_len >> 32);
        if ( cipher_len >= 0 )
          v5__cipher_len = cipher_len;
        v6__cipher = cipher;
        v7__aligned_cipher_len = v5__cipher_len >> 3;
        nblock = v7__aligned_cipher_len - 1;
        aes_set_key(&ctx, kek, 128);
        memcpy(A, v6__cipher, 8u);
        if ( v7__aligned_cipher_len - 1 > 0 )
        {
          v8__R = R;
          v9__cipher_ptr = (int)(v6__cipher + 8);
          v10__block_counter = 0;
          do
          {
            v11__R = v8__R;
            v12__cipher_ptr = (const void *)v9__cipher_ptr;
            ++v10__block_counter;
            ++v8__R;
            v9__cipher_ptr += 8;
            // STACK OVERFLOW -->
            memcpy(v11__R, v12__cipher_ptr, 8u);
          }
          while ( v10__block_counter != nblock );
        }
    

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

    R的定义

    unsigned __int8 R[32][8];
    

    VD-1410 – Stack-based buffer overflow vulnerability

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

              if ( !DecWPA2KeyData_0(
                      v5,
                      EapolKeyMsg + 95,
                      (EapolKeyMsg[94] + (EapolKeyMsg[93] << 8)),
                      &v5->PTK[16],
                      16,
                      decrypted_data) )
    

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

    int __fastcall DecWPA2KeyData(WPA_STA_INFO *pStaInfo, unsigned __int8 *key, int keylen, unsigned __int8 *kek, int keklen, unsigned __int8 *kout)
    {
      
        v9 = kout;
        rtl_memcpy_0(v9, v10, keylen);
    

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

    修复方案

    !DecWPA2KeyData_0(sta, key_msg + 95, v13, &sta->PTK[16], 16, &stack, 0xFF) 
    

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

      if ( key_len > kout_length || key_len >= 0x102 )
        return 0;
    

    VD-1411 – Stack-based buffer overflow vulnerability(未修复)

    漏洞位于ClientEAPOLKeyRecvd

    void __fastcall ClientEAPOLKeyRecvd(_adapter *padapter, sta_info *psta)
    {
    
      eapol_msg = v5->EAPOLMsgRecvd.Octet;
    
      v5->EapolKeyMsgRecvd.Octet = eapol_msg + 18;
      v7 = eapol_msg[20] & 8;
      if ( (eapol_msg[20] & 8) == 0 )
      {
    
        v23 = v5->EapolKeyMsgRecvd.Octet;
        v24 = (v23[2] >> 4) & 3;
        if ( *v23 == 2 )
        {
          rtl_memcpy_0(decrypted_data, v21->GTK[v24], v23[94] + (v23[93] << 8));
    

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

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

        v27 = sta->EapolKeyMsgRecvd.Octet;
        v28 = (v27[2] >> 4) & 3;
        if ( *v27 == 2 )
        {
          freertos_memcpy_0(&stack, v25 + 32 * v28 + 232, v27[94] + (v27[93] << 8));// 栈溢出
    

    新漏洞

    在分析漏洞时,确定了外部数据的流动,从而开展漏洞挖掘,最终发现一些漏洞

    https://github.com/ambiot/amb1_arduino/issues/2
    

    参考链接

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

  • 相关阅读:
    牛客多校第九场 && ZOJ3774 The power of Fibonacci(二次剩余定理+斐波那契数列通项/循环节)题解
    2019牛客多校第九场B Quadratic equation(二次剩余定理)题解
    URAL 1132 Square Root(二次剩余定理)题解
    牛客多校第九场H Cutting Bamboos(主席树 区间比k小的个数)题解
    配置android.support.v7.widget.Toolbar 搜索框样式
    Google之路
    Editplus 竖选,竖插入技巧
    JNDI
    Spring Hibernate Transaction示例
    AOP 入门
  • 原文地址:https://www.cnblogs.com/hac425/p/14375707.html
Copyright © 2020-2023  润新知