With gdb or ltrace or strace there is no way to disassamble or read or trace its execution
There is only an output, therefore it must call some printf() or puts() function.
Two solutions can be used for solution.
One is to use the ptrace functions to execute the code as child process, attach to it and read about its execution
#include <sys/ptrace.h> #include <sys/user.h> #include <sys/reg.h> #include <sys/wait.h> #include <sys/syscall.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> //#include <linux/user.h> int wait_for_syscall(pid_t child) { int status; while (1) { ptrace(PTRACE_SYSCALL, child, 0, 0); waitpid(child, &status, 0); if (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80) return 0; if (WIFEXITED(status)) return 1; } } int main() { pid_t child; int status,retval,syscall; long orig_ebx; long orig_ecx; int wait_val; child = fork(); printf("Child = %di\n",child); if(child == 0) { ptrace(PTRACE_TRACEME,0,NULL,NULL); execl("/utumno/utumno0","utumno0",NULL); } else { waitpid(child,&status,0); ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACESYSGOOD); while(1) { if (wait_for_syscall(child) != 0) break; syscall = ptrace(PTRACE_PEEKUSER, child, 4 * 11,NULL); printf("syscall(%d) = ", syscall); if (wait_for_syscall(child) != 0) break; retval = ptrace(PTRACE_PEEKUSER, child, sizeof(long)*11); printf("%d\n", retval); } } return 0; }
It executes /utumno/utumno1, then attach to it and trace the syscalls called.
utumno0@utumno:/tmp/u0$ gcc -m32 ptrace_calls.c -o ptrace_calls utumno0@utumno:/tmp/u0$ ./ptrace_calls Child = 7719 syscall(45) = 45 brk syscall(33) = 33 access syscall(192) = 192 mmap syscall(33) = 33 access syscall(197) = 197 removexattr syscall(192) = 192 lgetxattr syscall(6) = 6 lstat syscall(33) = 33 dup2 syscall(5) = 5 fstat .... syscall(125) = 125 mprotect syscall(125) = 125 mprotect syscall(91) = 91 munmap syscall(197) = 197 fstat64 syscall(45) = 45 brk syscall(45) = 45 brk Read me! :P syscall(4) = 4 write
We see a sequence that is very similar to any other executable: only the last one (the write) is a syscall that is part of the "manually created code" of utumno1.
Luckily some great people wrote a program that uses ptrace to get the assembler code and create a copy of the executable in readable format: http://reverse.lostrealm.com/tools/xocopy.html
utumno0@utumno:/tmp/u0$ gcc xocopy.c -o xocopy -m32 utumno0@utumno:/tmp/u0$ ./xocopy -a 0x08049000 /utumno/utumno0 ptrace(PTRACE_PEEKTEXT, pid, 0x08049000, 0): Input/output error
Unfortunately it seems not working due to input/outpu error.
I tried writing my own program with ptrace to read memory areas of the child process with no luck.
So let's follow another path.
If the executable writes something, it may use puts().
So what if we write a library where we redefine puts() (or better we hook/hijack it) and read from memory?
#define _GNU_SOURCE #include <stdio.h> #include <stdint.h> #include <dlfcn.h> int puts(const char *s) { int i; char *pt; static void* (*my_puts)(const char*s) = NULL; if (!my_puts){ my_puts = dlsym(RTLD_NEXT, "puts"); } printf("%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-"); printf("Hooked-%s", s); for( i = 0x804841a; i < 0x80484cb; i++) { pt = i; printf("%c", *pt); printf(""); } return 0; }
The above code define puts and also prints some areas from the memory using "%x" and fixed address
Let's compile it, create an so library. Then using LD_PRELOAD to load the library while running the vulnerable code
utumno0@utumno:/tmp/u0$ gcc -m32 -fPIC -c hookputs.c
utumno0@utumno:/tmp/u0$ ld -shared -m elf_i386 -o hookputs.so hookputs.o -ldl
utumno0@utumno:/tmp/u0$ LD_PRELOAD="./hook.so" ltrace /utumno/utumno0
ERROR: ld.so: object './hook.so' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored. failed to initialize process 12130: No such file or directory couldn't open program '/utumno/utumno0': No such file or directory
utumno0@utumno:/tmp/u0$ Hooked: puts function assword: a******w
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.