Question: how to migrate a process into a screen session?
Answer:
- move filedescriptors std{in, out, err} to a pts in screen
- ignore SIGHUP
In Assembler:
1 #include <stdio.h> 2 #include <asm/unistd.h> 3 4 int main() 5 { 6 /* 7 struct sigaction sa; 8 9 sa.sa_handler= SIG_IGN; 10 11 syscall(__NR_rt_sigaction, SIGHUP, &sa, NULL, 8); 12 */ 13 14 __asm__( 15 "_start:\n" 16 "subq $160, %rsp\n" 17 "movq $1, -160(%rbp)\n" 18 "movq $1, %rdi\n" 19 "leaq -160(%rbp), %rsi\n" 20 "movq $0, %rdx\n" 21 "mov $8, %r10d\n" 22 "movq $13, %rax\n" 23 "syscall\n" 24 "mov $0x2, %rax\n" // open 25 "movq $0xffffffffffff006c, %rbx\n" 26 "push %rbx\n" 27 "movq $0x6c756e2f7665642f, %rbx\n" 28 "push %rbx\n" 29 "movq %rsp, %rdi\n" 30 "movq $0x1, %rsi\n" // open WRONLY 31 "syscall\n" 32 "movq %rax, %rdi\n" 33 "movq $0x01, %rsi\n" 34 "movq $0x21, %rax\n" 35 "syscall\n" 36 // now the same for STDIN 37 "mov $0x2, %rax\n" // open 38 "movq %rsp, %rdi\n" 39 "movq $0x0, %rsi\n" // open RDONLY 40 "syscall\n" 41 "movq %rax, %rdi\n" 42 "movq $0x00, %rsi\n" 43 "movq $0x21, %rax\n" 44 "syscall\n" 45 // and now STDERR 46 "mov $0x2, %rax\n" // open 47 "movq %rsp, %rdi\n" 48 "movq $0x1, %rsi\n" // open WRONLY 49 "syscall\n" 50 "movq %rax, %rdi\n" 51 "movq $0x02, %rsi\n" 52 "movq $0x21, %rax\n" 53 "syscall\n" 54 55 ); 56 57 }
- 15: that's just a marker for me to be able to find the function later more easy
- 16: decrease the stack pointer to put a struct sigaction in there
- 17: put SIG_IGN in there - SIG_IGN is just the number 1
- 18: first argument for the rt_sigaction syscall is on which signal you want to operate; we want to ignore signal SIGHUP - SIGHUP has the value 1
- 19: second argument for the rt_sigaction syscall is the pointer to the sigaction struct
- 20: in case you want to store the old signal behaviour you could set the third argument to non-NULL; we don't do this here and set it to null
- 21: the fourth argument is size_t sigsetsize; that's 8
- 22: so, as specified in /usr/include/asm/unistd_64.h the syscall number for rt_sigaction is 13; so we just put that into rax
- 23: syscall: just execute the syscall
that's how easy it is to ignore a signal ;) - 24: now, we want to open a file; the syscall number for open is 2
- 25: move "\0l" into rbx
- 26: push that on the stack
- 27: move "/dev/nul" into rbx
- 28: push that on the stack
- 29: first argument for open is which file you want to open; filename is stored on the stack at rsp
- 30: we open the file in mode O_WRONLY; thats a symbol for 1
- 31: execute that syscall
that's how easy it is to open the file /dev/null in mode O_WRONLY
I put "/dev/null\0" on the stack, because it would be to complicated to put it into the data segment and adjust the address correctly. - 32: the open syscall returned in eax the filedescriptor number; we want to use that number as second argument for dup2; so we put it into rdi
- 33: first argument of dup2 is which filedescriptor should be moved; that's stdout (number 1)
- 34: syscall number for dup2 is 33 or 0x21
- 35: execute the syscall
that's how easy it is to move the stdout to /dev/null - 37: 0x2 is the syscall for the open syscall
- 38: we want to open the file "/dev/null\0"
- 39: second argument for open is how we want to open that file; we want to open it O_RDONLY (=0)
- 40: just syscall
now we have opened "/dev/null\0" twice; first WRONLY, second RDONLY - 41: same as in line 32
- 42: we want to move stdin (=0)
- 43: same as in line 34
- 44: syscall
now we have connected stdin to RDONLY opened /dev/null
lines 45 and following do the same for stderr and WRONLY /dev/null
in binary-code:
1 #define PRE_CMDS "\x48\x81\xec\xa0\x00\x00\x00" \ 2 "\x48\xc7\x85\x60\xff\xff\xff\x01\x00\x00\x00" \ 3 "\x48\xc7\xc7\x01\x00\x00\x00" \ 4 "\x48\x8d\xb5\x60\xff\xff\xff" \ 5 "\x48\xc7\xc2\x00\x00\x00\x00" \ 6 "\x41\xba\x08\x00\x00\x00" \ 7 "\x48\xc7\xc0\x0d\x00\x00\x00" \ 8 "\x0f\x05" \ 9 "\x48\xc7\xc0\x02\x00\x00\x00" 10 #define POST_CMDS "\x48\x89\xe7\x48\xc7\xc6" \ 11 "\x01\x00\x00\x00\x0f\x05\x48\x89" \ 12 "\xc7\x48\xc7\xc6\x01\x00\x00\x00" \ 13 "\x48\xc7\xc0\x21\x00\x00\x00\x0f" \ 14 "\x05\x48\xc7\xc0\x02\x00\x00\x00" \ 15 "\x48\x89\xe7\x48\xc7\xc6\x00\x00" \ 16 "\x00\x00\x0f\x05\x48\x89\xc7\x48" \ 17 "\xc7\xc6\x00\x00\x00\x00\x48\xc7" \ 18 "\xc0\x21\x00\x00\x00\x0f\x05\x48" \ 19 "\xc7\xc0\x02\x00\x00\x00\x48\x89" \ 20 "\xe7\x48\xc7\xc6\x01\x00\x00\x00" \ 21 "\x0f\x05\x48\x89\xc7\x48\xc7\xc6" \ 22 "\x02\x00\x00\x00\x48\xc7\xc0\x21" \ 23 "\x00\x00\x00\x0f\x05"
the pts's filename (e.g. /dev/pts/5) must be pushed between PRE_CMDS and POST_CMDS on the stack
the function that is glueing that all together:
1 #define PRE_CMD "\x48\xbb" 2 #define POST_CMD "\x53" 3 4 void create_shellcode(char *ttyfile, char *code) 5 { 6 char str[8]; 7 int i, j = 0; 8 int cp = 0; // codepointer 9 int len; 10 11 len = create_shellcode_len(ttyfile); 12 13 memcpy(code+cp, PRE_CMDS, PRE_CMDS_LEN); 14 cp+= PRE_CMDS_LEN; 15 memset(str, 0xff, 8); 16 for (i = strlen(ttyfile); i >= 0; i--) 17 { 18 str[i%8] = ttyfile[i]; 19 if (i%8 == 0) 20 { 21 memcpy(code+cp, PRE_CMD, PRE_CMD_LEN); 22 cp+= PRE_CMD_LEN; 23 24 for (j = 0; j < 8; j++) 25 { 26 code[cp] = str[j]; 27 cp++; 28 } 29 30 memcpy(code+cp, POST_CMD, POST_CMD_LEN); 31 cp+= POST_CMD_LEN; 32 } 33 34 } 35 memcpy(code+cp, POST_CMDS, POST_CMDS_LEN); 36 cp+= POST_CMDS_LEN; 37 38 39 if (cp != len) 40 { 41 printf("cp: %d len: %d\n", cp, len); 42 printf("tut tut tu\n"); 43 } 44 45 }
- '\x48\xbb' is:
mov XXX, %rbx - '\x53\ is:
push %rbx
now inject the code like http://www.spin.de/hp/btwotch/blog/id/10236046
1 int main(int argc, char **argv) 2 { 3 process = atoi(argv[1]); 4 struct user_regs_struct regs; 5 char tty[100]; 6 int len; 7 struct sigaction sa; 8 9 //get the ttyname 10 len = readlink("/proc/self/fd/0", tty, 100); 11 if (len > 99) 12 exit(-1); 13 else 14 tty[len] = '\0'; 15 16 len = create_shellcode_len(tty); 17 char *insertcode = malloc(len); 18 char backup[len]; 19 create_shellcode(tty, insertcode); 20 21 #ifdef INTERACTIVE 22 int i; 23 for (i = 0; i < len; i++) 24 printf("0x%.hhx ", insertcode[i]); 25 printf("\n"); 26 #endif 27 28 process = atoi(argv[1]); 29 30 ptrace(PTRACE_ATTACH, process, NULL, NULL); 31 perror("Attached"); 32 waitinput(); 33 ptrace(PTRACE_GETREGS, process, NULL, ®s); 34 perror("Got regs"); 35 waitinput(); 36 getdata(process, regs.rip, backup, len); 37 perror("Got backup (@rip)"); 38 waitinput(); 39 putdata(process, regs.rip, insertcode, len); 40 perror("Put code"); 41 waitinput(); 42 ptrace(PTRACE_CONT, process, NULL, NULL); 43 perror("Cont"); 44 waitinput(); 45 wait(NULL); 46 perror("Wait"); 47 waitinput(); 48 putdata(process, regs.rip, backup, len); 49 ptrace(PTRACE_SETREGS, process, NULL, ®s); 50 perror("Put regs"); 51 waitinput(); 52 53 ptrace(PTRACE_DETACH, process, NULL, NULL); 54 55 sa.sa_handler = termination_handler; 56 sigaction(SIGINT, &sa, NULL); 57 58 59 setvbuf(stdout,(char*)NULL,_IOLBF,8); 60 61 for (;;) 62 sleep(255); 63 64 65 return 0; 66 }
- 10: read which tty/pts the process, you want to move, is using
- 19: generate shellcode
- 46: inject code, wait until executed
- 49: revert origin code
- 50: revert origin registers
- 57: termination-handler for SIGINT (e.g. ctrl-c)
- 60: switch on linebuffer
TODO:
- ctrl-z should be made possible (I heard you would need a kernel patch for that)
- revert old sighup-handler after having moved process
- detect if process is using stdout/stdin/stderr and rewrite correctly -
./a.out > outputfile - other architectures, IA-32, ...
- fix getppid()
now the complete source code:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <signal.h> 5 #include <sys/ptrace.h> 6 #include <asm/ptrace-abi.h> 7 #include <sys/reg.h> 8 #include <sys/user.h> 9 #include <unistd.h> 10 #include <bits/wordsize.h> 11 #include <sys/types.h> 12 #include <sys/wait.h> 13 14 15 #define PRE_CMD_LEN 2 16 #define PRE_CMD "\x48\xbb" 17 #define POST_CMD "\x53" 18 #define POST_CMD_LEN 1 19 20 #define PRE_CMDS_LEN 61 21 #define PRE_CMDS "\x48\x81\xec\xa0\x00\x00\x00" \ 22 "\x48\xc7\x85\x60\xff\xff\xff\x01\x00\x00\x00" \ 23 "\x48\xc7\xc7\x01\x00\x00\x00" \ 24 "\x48\x8d\xb5\x60\xff\xff\xff" \ 25 "\x48\xc7\xc2\x00\x00\x00\x00" \ 26 "\x41\xba\x08\x00\x00\x00" \ 27 "\x48\xc7\xc0\x0d\x00\x00\x00" \ 28 "\x0f\x05" \ 29 "\x48\xc7\xc0\x02\x00\x00\x00" 30 #define POST_CMDS "\x48\x89\xe7\x48\xc7\xc6" \ 31 "\x01\x00\x00\x00\x0f\x05\x48\x89" \ 32 "\xc7\x48\xc7\xc6\x01\x00\x00\x00" \ 33 "\x48\xc7\xc0\x21\x00\x00\x00\x0f" \ 34 "\x05\x48\xc7\xc0\x02\x00\x00\x00" \ 35 "\x48\x89\xe7\x48\xc7\xc6\x00\x00" \ 36 "\x00\x00\x0f\x05\x48\x89\xc7\x48" \ 37 "\xc7\xc6\x00\x00\x00\x00\x48\xc7" \ 38 "\xc0\x21\x00\x00\x00\x0f\x05\x48" \ 39 "\xc7\xc0\x02\x00\x00\x00\x48\x89" \ 40 "\xe7\x48\xc7\xc6\x01\x00\x00\x00" \ 41 "\x0f\x05\x48\x89\xc7\x48\xc7\xc6" \ 42 "\x02\x00\x00\x00\x48\xc7\xc0\x21" \ 43 "\x00\x00\x00\x0f\x05" 44 #define POST_CMDS_LEN 107 45 46 47 //#define INTERACTIVE 48 void waitinput() 49 { 50 #ifdef INTERACTIVE 51 getchar(); 52 #endif 53 } 54 55 pid_t process; 56 57 void termination_handler(int signum) 58 { 59 kill(process, SIGINT); 60 exit(0); 61 } 62 63 int create_shellcode_len(char *ttyfile) 64 { 65 int i, j; 66 67 j = (strlen(ttyfile)/8)+1; 68 i = (j*8)*1; 69 i += POST_CMDS_LEN+PRE_CMDS_LEN; 70 i += (PRE_CMD_LEN+POST_CMD_LEN)*j; 71 return i; 72 } 73 74 void create_shellcode(char *ttyfile, char *code) 75 { 76 char str[8]; 77 int i, j = 0; 78 int cp = 0; // codepointer 79 int len; 80 81 len = create_shellcode_len(ttyfile); 82 83 memcpy(code+cp, PRE_CMDS, PRE_CMDS_LEN); 84 cp+= PRE_CMDS_LEN; 85 memset(str, 0xff, 8); 86 for (i = strlen(ttyfile); i >= 0; i--) 87 { 88 str[i%8] = ttyfile[i]; 89 if (i%8 == 0) 90 { 91 memcpy(code+cp, PRE_CMD, PRE_CMD_LEN); 92 cp+= PRE_CMD_LEN; 93 94 for (j = 0; j < 8; j++) 95 { 96 code[cp] = str[j]; 97 cp++; 98 } 99 100 memcpy(code+cp, POST_CMD, POST_CMD_LEN); 101 cp+= POST_CMD_LEN; 102 } 103 104 } 105 memcpy(code+cp, POST_CMDS, POST_CMDS_LEN); 106 cp+= POST_CMDS_LEN; 107 108 109 if (cp != len) 110 { 111 printf("cp: %d len: %d\n", cp, len); 112 printf("tut tut tu\n"); 113 } 114 115 } 116 117 void getdata(pid_t child, long addr, char *str, int len) 118 { 119 char *laddr; 120 int i = 0,j; 121 union u 122 { 123 long val; 124 char chars[sizeof(long)]; 125 } data; 126 127 j = len / sizeof(long); 128 laddr = str; 129 130 while (i < j) 131 { 132 data.val = ptrace(PTRACE_PEEKDATA, child, addr+(i * sizeof(long)), 133 NULL); 134 memcpy(laddr, data.chars, sizeof(long)); 135 i++; 136 laddr += sizeof(long); 137 } 138 j = len % sizeof(long); 139 140 if (j != 0) 141 { 142 data.val = ptrace(PTRACE_PEEKDATA, child, addr+(i * sizeof(long)), 143 NULL); 144 memcpy(laddr, data.chars, j); 145 } 146 147 str[len] = '\0'; 148 149 150 } 151 152 void putdata(pid_t child, long addr, char *str, int len) 153 { 154 char *laddr; 155 int i = 0, j; 156 union u 157 { 158 long val; 159 char chars[sizeof(long)]; 160 } data; 161 162 j = len/sizeof(long); 163 laddr = str; 164 165 while (i < j) 166 { 167 memcpy(data.chars, laddr, sizeof(long)); 168 ptrace(PTRACE_POKEDATA, child, addr+(i * sizeof(long)), data.val); 169 i++; 170 laddr += sizeof(long); 171 } 172 j = len % sizeof(long); 173 174 if (j != 0) 175 { 176 memcpy(data.chars, laddr, j); 177 ptrace(PTRACE_POKEDATA, child, addr+(i * sizeof(long)), data.val); 178 } 179 180 } 181 182 183 int main(int argc, char **argv) 184 { 185 process = atoi(argv[1]); 186 struct user_regs_struct regs; 187 char tty[100]; 188 int len; 189 struct sigaction sa; 190 191 //get the ttyname 192 len = readlink("/proc/self/fd/0", tty, 100); 193 if (len > 99) 194 exit(-1); 195 else 196 tty[len] = '\0'; 197 198 len = create_shellcode_len(tty); 199 char *insertcode = malloc(len); 200 char backup[len]; 201 create_shellcode(tty, insertcode); 202 203 #ifdef INTERACTIVE 204 int i; 205 for (i = 0; i < len; i++) 206 printf("0x%.hhx ", insertcode[i]); 207 printf("\n"); 208 #endif 209 210 process = atoi(argv[1]); 211 212 ptrace(PTRACE_ATTACH, process, NULL, NULL); 213 perror("Attached"); 214 waitinput(); 215 ptrace(PTRACE_GETREGS, process, NULL, ®s); 216 perror("Got regs"); 217 waitinput(); 218 getdata(process, regs.rip, backup, len); 219 perror("Got backup (@rip)"); 220 waitinput(); 221 putdata(process, regs.rip, insertcode, len); 222 perror("Put code"); 223 waitinput(); 224 ptrace(PTRACE_CONT, process, NULL, NULL); 225 perror("Cont"); 226 waitinput(); 227 wait(NULL); 228 perror("Wait"); 229 waitinput(); 230 putdata(process, regs.rip, backup, len); 231 ptrace(PTRACE_SETREGS, process, NULL, ®s); 232 perror("Put regs"); 233 waitinput(); 234 235 ptrace(PTRACE_DETACH, process, NULL, NULL); 236 237 sa.sa_handler = termination_handler; 238 sigaction(SIGINT, &sa, NULL); 239 240 241 setvbuf(stdout,(char*)NULL,_IOLBF,8); 242 243 for (;;) 244 sleep(255); 245 246 247 return 0; 248 }
See also:


