Contig does not handle paths longer than MAX_PATH, crashes with a buffer overrun!
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:
- 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
- Always allocate a buffer large enough to handle a UNICODE_STRING struct string