OverTheWire.org - Utumno - Level 0 Writeup

The vulnerable executable /utumno/utumno0 is executable but not readable.
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.