elfmaster / saruman Goto Github PK
View Code? Open in Web Editor NEWELF anti-forensics exec, for injecting full dynamic executables into process image (With thread injection)
ELF anti-forensics exec, for injecting full dynamic executables into process image (With thread injection)
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 in call_fn(BOOTSTRAP_CODE, ...)
at the very first instruction of program's entry point.
Host:
~/devel/infector/saruman2 $ ./launcher `pidof host` ../parasite ""
#include <stdio.h>
int main(void) {
for(;;) {
printf("I am a boring program\n");
sleep(3);
}
}
Parasite:
#include <stdio.h>
int main(void){
int i;
for (i = 0; i < 10; i++)
printf("I AM AN EVIL FUCKING PARASITE!!!\n");
}
Launching slightly modified Saruman's code:
[+] 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
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_regs
for tracing purposescall_fn
function to instead of PTRACE_CONT
got into PTRACE_SINGLESTEP
run_bootstrap
in main()
as saruman should fail when bootstrap did not manage to run.[...]
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
...
Then, after a single step, where push $rsp
should 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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.