Contig does not handle paths longer than MAX_PATH, crashes with a buffer overrun!

Alexander Riccio 1 Reputation point
2022-09-19T22:55:46.653+00:00

Contig actually appears to be using the unsafe vswprintf function, which actually makes this a crashing bug, not just an invalid behavior bug. If it weren't for stack cookies, in theory, someone could do some kind of privilege escalation exploit by just having a long enough path! The exception is FAST_FAIL_STACK_COOKIE_CHECK_FAILURE, and the stack trace is:

00 00196988 00403bce     Contig+0x5d69  
01 00197200 00403ba5     Contig+0x3bce  
02 00197a8c 00403ba5     Contig+0x3ba5  
03 00198318 00403ba5     Contig+0x3ba5  
04 00198ba4 00403ba5     Contig+0x3ba5  
05 00199430 00403ba5     Contig+0x3ba5  
06 00199cbc 00403ba5     Contig+0x3ba5  
07 0019a548 00403ba5     Contig+0x3ba5  
08 0019add4 00403ba5     Contig+0x3ba5  
09 0019b660 00403ba5     Contig+0x3ba5  
0a 0019beec 00403ba5     Contig+0x3ba5  
0b 0019c778 00403ba5     Contig+0x3ba5  
0c 0019d004 00403ba5     Contig+0x3ba5  
0d 0019d890 00403ba5     Contig+0x3ba5  
0e 0019e11c 00403ba5     Contig+0x3ba5  
0f 0019e9a8 00403ba5     Contig+0x3ba5  
10 0019f234 00403ba5     Contig+0x3ba5  
11 0019fac0 004050b0     Contig+0x3ba5  
12 0019ff28 00405c3a     Contig+0x50b0  
13 0019ff70 758afa29     Contig+0x5c3a  
14 0019ff80 77367b5e     KERNEL32!BaseThreadInitThunk+0x19  
  

A bit of work in ghidra shows me all the classic signs of directory tree enumeration in Contig+0x3bce, and that Contig+0x5d69 is probably the __gs_stkchk function or whatever it's called these days:

  _WIN32_FIND_DATAW local_870;  
  wchar_t local_620 [260];  
  wchar_t local_418 [259];  
  wchar_t wStack530;  
  short local_210 [260];  
  
  
// ... snip ...  
  
      _vswprintf((wchar_t *)param_2,L"*.*");  
      if (DAT_00469d57 != '\0') {  
        _vswprintf(&wStack530 + 1,L"%s\\*.*",param_1);  
        _vswprintf(local_620,L"%s\\*.*",param_1);  
        goto LAB_00403884;  
      }  
      _vswprintf(&wStack530 + 1,L"%s",param_1);  
  
// ... snip ...  
  
LAB_00403884:  
  pvVar5 = FindFirstFileW(local_620,(LPWIN32_FIND_DATAW)&local_870);  
  pcVar12 = FindNextFileW_exref;  
  uVar10 = extraout_DL;  
  if (pvVar5 != (HANDLE)0xffffffff) {  
  

The easiest ways to fix it are to either:

  1. have a fast path that uses a MAX_PATH stack buffer most of the time (as the dev of altWinDirStat, this heap allocation is measurable on fast IO systems!), and allocate the larger buffer on demand as needed
  2. Always allocate a buffer large enough to handle a UNICODE_STRING struct string
Sysinternals
Sysinternals
Advanced system utilities to manage, troubleshoot, and diagnose Windows and Linux systems and applications.
1,082 questions
0 comments No comments
{count} votes