#include <stdio.h>
int main(void) {
for(;;) {
printf("I am a boring program\n");
sleep(3);
}
}
#include <stdio.h>
int main(void){
int i;
for (i = 0; i < 10; i++)
printf("I AM AN EVIL FUCKING PARASITE!!!\n");
}
[+] Target pid: 389
[+] map_elf_binary(ptr, ../parasite)
[+] Parasite entry point will be main(): 0x400506
[+] Found text segment
[+] Found data segment
[+] Found dynamic segment
[+] Found dynamic string table
[+] Found dynamic symbol table
[+] Found G.O.T
[+] PLT count: 72 entries
[DEBUG]-> get_sym_from_libc() addr of __libc_dl_*: 7f112c69cb00
[+] PT_ATTACHED -> 389
[+] calling bootstrap
-- [RIP - 0x00400000] Single step
rax: 0xfffffffffffffdfc (-516)
rbx: 0x7ffce59de1a0 (140724160815520)
rcx: 0xffffffffffffffff (-1)
rdx: 0x04000000 (67108864)
rsi: 0x000005c8 (1480)
rdi: 0x00c00000 (12582912)
rbp: 0xffffffff (4294967295)
rsp: 0x7ffce59de188 (140724160815496)
r8: 0x7ffce59de2a0 (140724160815776)
r9: 0x7ffce59de0e0 (140724160815328)
r10: 0x00000008 (8)
r11: 0x00000246 (582)
r12: 0x7ffce59de220 (140724160815648)
r13: 0x7ffce59de450 (140724160816208)
r14: 0x00000000 (0)
r15: 0x00000000 (0)
First 12 bytes from RIP:
55 48 89 e5 48 81 ec a0 48 81 ec a0
-- [RIP - 0x003ffffe] Single step
rax: 0x000000db (219)
rbx: 0x7ffce59de1a0 (140724160815520)
rcx: 0xffffffffffffffff (-1)
rdx: 0x04000000 (67108864)
rsi: 0x000005c8 (1480)
rdi: 0x00c00000 (12582912)
rbp: 0xffffffff (4294967295)
rsp: 0x7ffce59de188 (140724160815496)
r8: 0x7ffce59de2a0 (140724160815776)
r9: 0x7ffce59de0e0 (140724160815328)
r10: 0x00000008 (8)
r11: 0x00000246 (582)
r12: 0x7ffce59de220 (140724160815648)
r13: 0x7ffce59de450 (140724160816208)
r14: 0x00000000 (0)
r15: 0x00000000 (0)
First 12 bytes from RIP:
ff ff ff ff ff ff ff ff 89 e5 48 81
[!] Target process has been stopped, something went wrong. Signal: 11 (Segmentation fault)
call_fn(BOOTSTRAP_CODE, ...) failed: Success
[...]
void display_regs(pid_t pid, struct user_regs_struct *pt_reg ) {
long word[3] = {0};
char *buf = (char*)word;
word[0] = ptrace(PTRACE_PEEKTEXT, pid, pt_reg->rip, NULL);
word[1] = ptrace(PTRACE_PEEKTEXT, pid, pt_reg->rip+4, NULL);
word[2] = ptrace(PTRACE_PEEKTEXT, pid, pt_reg->rip+8, NULL);
printf("\n-- [RIP - 0x%08lx] Single step \n"
"rax: 0x%08lx (%ld)\nrbx: 0x%08lx (%ld)\nrcx: 0x%08lx (%ld)\n"
"rdx: 0x%08lx (%ld)\nrsi: 0x%08lx (%ld)\nrdi: 0x%08lx (%ld)\n"
"rbp: 0x%08lx (%ld)\nrsp: 0x%08lx (%ld)\nr8: 0x%08lx (%ld)\n"
"r9: 0x%08lx (%ld)\nr10: 0x%08lx (%ld)\nr11: 0x%08lx (%ld)\n"
"r12: 0x%08lx (%ld)\nr13: 0x%08lx (%ld)\nr14: 0x%08lx (%ld)\n"
"r15: 0x%08lx (%ld)\n"
"First 12 bytes from RIP:\n"
"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
pt_reg->rip,
pt_reg->rax, pt_reg->rax, pt_reg->rbx, pt_reg->rbx, pt_reg->rcx, pt_reg->rcx,
pt_reg->rdx, pt_reg->rdx, pt_reg->rsi, pt_reg->rsi, pt_reg->rdi, pt_reg->rdi,
pt_reg->rbp, pt_reg->rbp, pt_reg->rsp, pt_reg->rsp, pt_reg->r8, pt_reg->r8,
pt_reg->r9, pt_reg->r9, pt_reg->r10, pt_reg->r10, pt_reg->r11, pt_reg->r11,
pt_reg->r12, pt_reg->r12, pt_reg->r13, pt_reg->r13, pt_reg->r14, pt_reg->r14,
pt_reg->r15, pt_reg->r15,
buf[0] & 0xff, buf[1] & 0xff, buf[2] & 0xff, buf[3] & 0xff, buf[4] & 0xff,
buf[5] & 0xff, buf[6] & 0xff, buf[7] & 0xff, buf[8] & 0xff, buf[9] & 0xff, buf[10] & 0xff, buf[11] & 0xff);
}
/*
* call_fn() allows one to inject a function
* (select by functionPayloads_t) into the remote
* process, and execute it. The return value for
* the function is stored in payloads.function[func].retval
*/
#define SLACK_SIZE 32
int call_fn(functionPayloads_t func, handle_t *h, uint64_t ip)
{
[...]
case 6:
pt_reg->rdi = (uintptr_t)h->payloads.function[func].args[0];
pt_reg->rsi = (uintptr_t)h->payloads.function[func].args[1];
pt_reg->rdx = (uintptr_t)h->payloads.function[func].args[2];
pt_reg->rcx = (uintptr_t)h->payloads.function[func].args[3];
pt_reg->r8 = (uintptr_t)h->payloads.function[func].args[4];
pt_reg->r9 = (uintptr_t)h->payloads.function[func].args[5];
break;
}
display_regs(h->tasks.pid, pt_reg);
if (ptrace(PTRACE_SETREGS, h->tasks.pid, NULL, pt_reg) < 0)
return -1;
//if (ptrace(PTRACE_CONT, h->tasks.pid, NULL, NULL) < 0)
// return -1;
do {
ptrace(PTRACE_SINGLESTEP, h->tasks.pid, 0, 0);
if (waitpid(h->tasks.pid, &status, 0) == -1) {
perror("waitpid");
return -1;
}
if (ptrace(PTRACE_GETREGS, h->tasks.pid, NULL, pt_reg) < 0) {
perror("PTRACE_GETREGS");
return -1;
}
display_regs(h->tasks.pid, pt_reg);
if (WIFEXITED(status)) {
fprintf(stderr, "\n[!] Target process has exited, something went wrong. Status: %d\n", WEXITSTATUS(status));
return -1;
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "\n[!] Target process has been killed, something went wrong. Signal: %d (%s)\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
if (WCOREDUMP(status)) {
fprintf(stderr, "\tChild process has produced a core dump. Damn it.\n");
}
return -1;
} else if (WIFSTOPPED(status)) {
fprintf(stderr, "\n[!] Target process has been stopped, something went wrong. Signal: %d (%s)\n", WSTOPSIG(status), strsignal(WSTOPSIG(status)));
return -1;
} else if (WIFCONTINUED(status)) {
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
/* Get return value */
if (ptrace(PTRACE_GETREGS, h->tasks.pid, NULL, pt_reg) < 0) {
perror("PTRACE_GETREGS");
return -1;
}
h->payloads.function[func].retval = (pt_reg_t)pt_reg->rax;
return 0;
}
[...]
int main(int argc, char **argv)
{
[...]
if(run_bootstrap(¶site) < 0) {
goto done;
}
As can be seen, there is a really strange behaviour that I don't understand going on in host's body:
55 push $rsp
48 89 mov $rsp, $rbp
...
I don't understand that course of action, neither how it can be traced or fixed.
Any ideas?
Hello there,
I am unable to run the Saruman correctly due to a really weird bug on my Debian 8:
Linux M 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux. Saruman crashes the host program right incall_fn(BOOTSTRAP_CODE, ...)at the very first instruction of program's entry point.Host:
~/devel/infector/saruman2 $ ./launcher `pidof host` ../parasite ""Parasite:
Launching slightly modified Saruman's code:
One can notice that the second registers dump differs from first one in:
0xff- not to mention, that following bytes:89 e5 48 ...are shifted even further from RIP - four bytes off.Here are all modifications made to Saruman (
launcher.c):display_regsfor tracing purposescall_fnfunction to instead ofPTRACE_CONTgot intoPTRACE_SINGLESTEPrun_bootstrapinmain()as saruman should fail when bootstrap did not manage to run.As can be seen, there is a really strange behaviour that I don't understand going on in host's body:
Then, after a single step, where
push $rspshould occur, out of the sudden we land at 2 bytes before entry point (0x3ffffe), RAX modified, and bytes at RIP malformed.Host gets it's SIGSEGV and it's life is over.
I don't understand that course of action, neither how it can be traced or fixed.
Any ideas?