---------------------------------------------------------------- Security Report : telnet client slc_add_reply() buffer overflow. by Gael Delalleau (dec. 2004) ---------------------------------------------------------------- Overview -------- A malicious server can send specific telnet options to overflow a static 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 ----------------- It is possible to overflow the 128-bytes static buffer slc_reply in telnet.c: unsigned char slc_reply[128]; There is no size check in the main loop of the slc(cp, len) function, when adding a slc value into the slc_reply buffer with a call to slc_add_reply(). Thus an attacker can provide many SLC commands in a LINEMODE suboption and overflow this buffer. The size of the overflow is limited by the size of the buffer holding the suboptions (256 bytes). Exploitation ------------ On my version of Kerberos telnet (compiled on Linux), there are some interesting static variables that we can overflow that may be used to achieve arbitrary code execution: * the peerdied buffer which is a jmp_buf buffer. It contains saved register values that we can overwrite. It may be used later inside a longjmp() if the send() function returns an unexpected error. * the opt_reply pointer which is used to store environment data. It is used in a realloc() call in env_opt_start() if we send a SB NEW-ENVIRON SEND telnet command. We may be able to trigger heap corruption by modifying this pointer. * the opt_replyend pointer which is used to calculate the size of the opt_reply buffer allocated on the heap, and allocate more space if needed. We may be able to trigger heap corruption by modifying this pointer. The values of the characters in the overflow have some restrictions. They are sequences of three bytes like this: either | | or | 0x00 | 0x00 (for more exact explanation see the filtering of SLC entries in the function slc(cp,len) ) Though this filtering should not prevent successful exploitation on most OSes. My testing on various versions of telnet shows that many versions are vulnerable, and EIP can be controlled easily on some versions of telnet / some systems, depending on the static variables lying after the slc_reply buffer. On Debian Woody, it seems to be straight-forward to control the EIP as shown in the debug outputs below. 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 Debug output: [root@localhost telnet]# gdb ./telnet_krb5 core.20122 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 0x400e9f38 in realloc () from /lib/i686/libc.so.6 (gdb) i r eax 0xdd08bbe6 -586630170 <-- controlled ecx 0xdd08bbee -586630162 <-- controlled edx 0x1 1 ebx 0x401a49a0 1075464608 esp 0xbfffee30 0xbfffee30 ebp 0xbfffee58 0xbfffee58 esi 0xdd08bbee -586630162 edi 0x100 256 eip 0x400e9f38 0x400e9f38 eflags 0x10282 66178 (...) (gdb) bt #0 0x400e9f38 in realloc () from /lib/i686/libc.so.6 #1 0x08051dcb in env_opt_start () at telnet.c:1619 #2 0x08051cdd in env_opt (buf=0xdd08bbee
, len=102) at telnet.c:1551 #3 0x08050979 in suboption () at telnet.c:975 #4 0x08052689 in telrcv () at telnet.c:2018 #5 0x08052e25 in Scheduler (block=0) at telnet.c:2271 #6 0x08052f0d in telnet (user=0x1
) at telnet.c:2396 #7 0x0804d8a5 in tn (argc=0, argv=0x80cf8c0) at commands.c:2679 #8 0x0804e62e in main (argc=1, argv=0x0) at main.c:336 #9 0x4008dc57 in __libc_start_main () from /lib/i686/libc.so.6 (gdb) x/i $eip 0x400e9f38 : mov 0x4(%eax),%ecx <-- controlled parameter given to realloc (gdb) x/100x slc_reply 0x80dc700 : 0x0322faff 0x33000033 0x00330000 0x00003300 <-- start of buffer 0x80dc710 : 0x33000033 0x00330000 0x00003300 0x33000033 0x80dc720 : 0x00330000 0x00003300 0x33000033 0x00330000 0x80dc730 : 0x00003300 0x33000033 0x00330000 0x00003300 0x80dc740 : 0x33000033 0x00330000 0x00003300 0x33000033 0x80dc750 : 0x00330000 0x00003300 0x33000033 0x00330000 0x80dc760 : 0x00003300 0x33000033 0x00330000 0x00003300 0x80dc770 : 0x33000033 0x00330000 0x00003300 0x33000033 0x80dc780 : 0xdd080000 0xbbee08aa 0x08aadd08 0xdd08bbee <-- start of overflow 0x80dc790 : 0xbbee08aa 0x08aadd08 0xdd08bbee 0x00000000 0x80dc7a0 : 0x08aadd08 0xdd08bbee 0xbbee08aa 0x08aadd08 0x80dc7b0 : 0xdd08bbee 0xbbee08aa 0x08aadd08 0xdd08bbee 0x80dc7c0 : 0xbbee08aa 0x08aadd08 0xdd08bbee 0xbbee08aa 0x80dc7d0 : 0x08aadd08 0xdd08bbee 0xbbee08aa 0x08aadd08 0x80dc7e0 : 0xdd08bbee 0xbbee08aa 0x08aadd08 0xdd08bbee 0x80dc7f0 : 0xbbee08aa 0x08aadd08 0xdd08bbee 0xbbee08aa 0x80dc800 : 0x0000f0ff 0x00000000 0x00000000 0x00000000 <-- end of overflow ------------ Telnet client version: Debian stable Vulnerable: YES Debug output: TESTING SUGGESTS THAT WE CAN GET DIRECT CONTROL OF EIP, WITHOUT ANY MORE WORK. [gael@localhost telnet]$ gdb ./telnet_woody core.27033 GNU gdb 5.3-25mdk (Mandrake Linux) (...) Core was generated by `./telnet_woody 127.0.0.1'. Program terminated with signal 11, Segmentation fault. (...) #0 0xbbee08aa in ?? () (gdb) bt #0 0xbbee08aa in ?? () #1 0x08052cb7 in strcpy () #2 0x0804eb75 in strcpy () #3 0x0804f11b in strcpy () #4 0x08051cc8 in strcpy () #5 0x08051ddf in strcpy () #6 0x0804c701 in strcpy () #7 0x0804e618 in strcpy () #8 0x4007bc57 in __libc_start_main () from /lib/i686/libc.so.6 (gdb) i r eax 0x8052ca0 134556832 ecx 0x1fff 8191 edx 0x805dec0 134602432 ebx 0x8067ac8 134642376 esp 0xbfffef44 0xbfffef44 ebp 0xbfffef78 0xbfffef78 esi 0x1fff 8191 edi 0x8067ac8 134642376 eip 0xbbee08aa 0xbbee08aa eflags 0x10287 66183 (...) ------------ Telnet client version: Sun Solaris 9 telnet Vulnerable: YES Debug output: bash-2.05$ uname -a SunOS bigspark 5.9 Generic_112233-08 sun4u sparc SUNW,Ultra-5_10 bash-2.05$ which telnet /bin/telnet bash-2.05$ telnet 192.168.0.39 Trying 192.168.0.39... Connected to 192.168.0.39. Escape character is '^]'. Segmentation Fault (core dumped) bash-2.05$ gdb /bin/telnet core GNU gdb 5.0 (...) Core was generated by `telnet 192.168.0.39'. Program terminated with signal 11, Segmentation Fault. (...) #0 0x15404 in slc_add_reply () (gdb) bt #0 0x15404 in slc_add_reply () #1 0x152a0 in slc () #2 0x147f4 in gettermname () #3 0x165c0 in telrcv () #4 0x16cbc in Scheduler () #5 0x16ddc in telnet () #6 0x1b554 in tn () #7 0x1c3a0 in main () (gdb) i r g0 0x0 0 g1 0xed 237 g2 0xffffffee -18 g3 0x2 2 g4 0x36584 222596 g5 0x0 0 g6 0x0 0 g7 0x0 0 o0 0xaa035526 -1442622170 o1 0xaa035525 -1442622171 o2 0xbb 187 o3 0x8 8 o4 0xee 238 o5 0x35400 218112 sp 0xffbff5a0 -4196960 o7 0x15298 86680 l0 0x34e97 216727 l1 0x6c 108 l2 0x36524 222500 l3 0x0 0 l4 0x0 0 l5 0x0 0 l6 0x3c 60 l7 0x0 0 i0 0x34e0a 216586 i1 0xfc 252 i2 0x143f0 82928 i3 0x0 0 i4 0x0 0 i5 0x0 0 fp 0xffbff600 -4196864 i7 0x147ec 83948 y 0x0 0 psr 0xfe901007 -24113145 icc:N--C, pil:0, s:0, ps:0, et:0, cwp:7 wim 0x0 0 tbr 0x0 0 pc 0x15404 87044 npc 0x15408 87048 fpsr 0x0 0 rd:N, tem:0, ns:0, ver:0, ftt:0, qne:0, fcc:=, aexc:0, cexc:0 cpsr 0x0 0 (gdb) x/2i 0x15404 0x15404 : stb %o3, [ %o1 ] 0x15408 : ld [ %o5 + 0x124 ], %o1 (gdb) ------------ Telnet client version: Putty Vulnerable: NO Note ---- The code snipsets in this advisory are taken from the MIT Kerberos telnet client. - End of Security Report - Gael Delalleau