├── README.md ├── traceGen.py └── trace.c /README.md: -------------------------------------------------------------------------------- 1 | # PwnWAF 2 | pwn log tools for AWD 3 | 4 | ## Description 5 | Use traceGen.py to generate elf file. 6 | 7 | * elf\_name: which elf we want to log file 8 | * log\_path: log file 9 | * machine: the platform of this elf, (only surpport x86/x86\_64) 10 | 11 | **NOTICE**: elf\_name and log\_path must be absolutely path 12 | 13 | ## Usage: 14 | 15 | ```bash 16 | python traceGen.py machine elf_name log_path 17 | ``` 18 | 19 | For example: 20 | 21 | ```bash 22 | python traceGen.py 64 /path/to/elf/test.bin /path/to/log/log.txt 23 | ``` 24 | 25 | and the elf\_name.out is log bin file.Then rename this file(or others) to make xinetd boot this file. This file will start a child process to exec elf\_name file, and parent process will record info: 26 | ``` 27 | +-----+ 28 | |child| --> execute /path/to/elf/test.bin 29 | +-----+ 30 | 31 | +------+ 32 | |parent| --> log I/O to /path/to/log/log.txt 33 | +------+ 34 | ``` 35 | 36 | and log.txt will like this: 37 | ``` 38 | WRIGING 39 | Welcome to my pwn world! 40 | 41 | READING 42 | aaaaaaaaaaaaaaa 43 | 44 | WRIGING 45 | your input is :aaaaaaaaaaaaaaa 46 | ``` 47 | -------------------------------------------------------------------------------- /traceGen.py: -------------------------------------------------------------------------------- 1 | #!usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | __author__ = "link" 5 | 6 | import os 7 | import argparse 8 | 9 | DEBUG = 0 10 | 11 | def generate_new_file(elf_name, machine, log_path): 12 | """ generate new c file with argument 13 | 14 | @param elf_name:elf path that we want to be logged 15 | @param machine: elf machine bit 16 | @param log_path: the path that we save log file 17 | """ 18 | fd = open("trace.c", 'r') 19 | content = '' 20 | for eachline in fd: 21 | content += eachline 22 | 23 | fd.close() 24 | # replace the old infomation 25 | content = content.replace("TEMPFILENAME", elf_name) 26 | content = content.replace("TEMPBIT", machine) 27 | content = content.replace("TEMPLOGNAME", log_path) 28 | 29 | # write to tmp file 30 | fd = open("tmp_trace.c", 'w') 31 | fd.write(content) 32 | fd.close() 33 | 34 | 35 | 36 | if __name__ == "__main__": 37 | parser = argparse.ArgumentParser(description="Generate file to log attach flow") 38 | # group = parser.add_mutually_exclusive_group() 39 | # group.add_argument("32", action="store_true") 40 | # group.add_argument("64", action="store_true") 41 | parser.add_argument("machine",help="bytes of elf(32/64)", choices=['32','64']) 42 | parser.add_argument("elf_name", help="absolute path of elf") 43 | parser.add_argument("log_path", help="abdolute path of log.txt") 44 | 45 | args = parser.parse_args() 46 | 47 | elf_name = args.elf_name 48 | machine = args.machine 49 | log_path = args.log_path 50 | 51 | if elf_name == None or machine == None or log_path == None: 52 | print parser.echo 53 | else: 54 | print("file name {}, in {} bits machine, log file will save at{}".format(elf_name, machine, log_path)) 55 | generate_new_file(elf_name, machine, log_path) 56 | # then, we use os to make file 57 | tmp_path = os.path.realpath("tmp_trace.c") 58 | print tmp_path 59 | if machine == '32': 60 | os.system("gcc -m32 -o {}.out {}".format(tmp_path[:-2], tmp_path)) 61 | elif machine == '64': 62 | os.system("gcc -o {}.out {}".format(tmp_path[:-2], tmp_path)) 63 | if DEBUG: 64 | pass 65 | else: 66 | os.system("rm {}".format(tmp_path)) 67 | 68 | -------------------------------------------------------------------------------- /trace.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | 17 | #define FILENAME "TEMPFILENAME" 18 | #define LOGNAME "TEMPLOGNAME" 19 | #define MACHINE TEMPBIT 20 | 21 | enum SYSTYPE { 22 | READ, 23 | WRITE 24 | }; 25 | 26 | 27 | int check_standard(int fd){ 28 | return fd == 1 || fd == 0; 29 | } 30 | 31 | void write_log(pid_t pid, char* addr, int size, enum SYSTYPE flag){ 32 | int fd = open(LOGNAME, O_CREAT|O_APPEND|O_WRONLY, 0666); 33 | int i = 0,j = 0; 34 | long data; 35 | char* buf = (char*)malloc((size+1)*sizeof(long)); 36 | memset(buf, '\0', sizeof(buf)); 37 | // printf("begin write\n"); 38 | for(i = 0; i < (sizeof(long)+size -1)/sizeof(long); i++){ 39 | data = ptrace(PTRACE_PEEKDATA, pid, addr+i*sizeof(long), NULL); 40 | // printf("\ndata is %x,addr is %lx\n", data, addr + i*sizeof(long)); 41 | for(j = 0; j < sizeof(long) ;j++){ 42 | *(buf + i*sizeof(long) + j ) = *((char*)(&data) + j); 43 | // printf("buf[i] is %x\n", *(buf + i*sizeof(long)+j)); 44 | if(buf[sizeof(long)*i+j] == '\0'|| buf[sizeof(long)*i+j] == '\n') 45 | goto finish; 46 | } 47 | } 48 | finish: 49 | buf[sizeof(long)*i+j+1] = '\n'; 50 | if(flag == READ){ 51 | write(fd, "\nREADING:\n", 10); 52 | } 53 | else if (flag == WRITE){ 54 | write(fd, "\nWRITING:\n", 10); 55 | } 56 | write(fd, buf, sizeof(long)*i+j+1); 57 | close(fd); 58 | free(buf); 59 | // printf("write finish\n"); 60 | } 61 | 62 | int main(int argc, char* argv[]){ 63 | setvbuf(stdin,0,2,0); 64 | setvbuf(stdout,0,2,0); 65 | pid_t pid; 66 | struct user_regs_struct regs; 67 | int status; 68 | int insyscall = 0; 69 | int first_time = 1; 70 | pid = fork(); 71 | int sys_num; 72 | enum SYSTYPE sys_status; 73 | // we use child process to exec 74 | if(pid == 0){ 75 | ptrace(PTRACE_TRACEME, 0, NULL, NULL); 76 | argv[1] = FILENAME; 77 | status = execvp(FILENAME, argv+1); 78 | if(status<0){ 79 | perror("ERROR EXEC\n"); 80 | return -1; 81 | } 82 | } 83 | // parent to get child syscall 84 | else if (pid > 0){ 85 | 86 | while(1){ 87 | wait(&status); 88 | if(WIFEXITED(status)) 89 | break; 90 | // get rax to ensure witch syscall 91 | ptrace(PTRACE_GETREGS, pid, NULL, ®s); 92 | #if MACHINE == 64 93 | sys_num = regs.orig_rax; 94 | #elif MACHINE == 32 95 | sys_num = regs.orig_eax; 96 | #endif 97 | if (sys_num != SYS_read&&sys_num != SYS_write){ 98 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 99 | continue; 100 | } 101 | if (insyscall==0){ 102 | insyscall = 1; 103 | ptrace(PTRACE_SYSCALL, pid, 0, 0); 104 | } 105 | else{ 106 | // we should ignor the first time 107 | // checl it is standard pipe or not 108 | int is_standard = 0; 109 | #if MACHINE == 64 110 | is_standard = check_standard(regs.rdi); 111 | #elif MACHINE == 32 112 | is_standard = check_standard(regs.ebx); 113 | #endif 114 | if(!is_standard){ 115 | first_time = 0; 116 | ptrace(PTRACE_SYSCALL, pid, NULL ,NULL); 117 | insyscall ^= 1; 118 | continue; 119 | } 120 | if(sys_num == SYS_read) 121 | sys_status = READ; 122 | else if (sys_num == SYS_write) 123 | sys_status = WRITE; 124 | int size = 0; 125 | char* addr = NULL; 126 | #if MACHINE == 64 127 | size = regs.rdx; 128 | // size = (size + sizeof(long)-1)/sizeof(long) * sizeof(long) +1; 129 | addr = (char*)regs.rsi; 130 | // printf(" the addr is %lx with size %lx", addr, size); 131 | #elif MACHINE == 32 132 | size = regs.edx; 133 | addr = (char*)regs.ecx; 134 | 135 | #endif 136 | write_log(pid, addr, size, sys_status); 137 | insyscall = 0; 138 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 139 | } 140 | } 141 | return 0; 142 | } 143 | else{ 144 | perror("ERROR FORK!\n"); 145 | return -1; 146 | } 147 | 148 | } 149 | --------------------------------------------------------------------------------