Search code examples
cmacosdebuggingfuzzingxnu

Mac OS (10.13.1) task_for_pid for forked process "(os/kern) failure"


Last time I'm trying to write simple genetic fuzzer (using strictly Mac OS, just for fun). My idea is something like that :

-> Main program that control forked process

--> forked process load binary code from disk and jump into it.

-> parent ask for task (task_for_pid(mach_task_self(),childPID,&task))

-> parent try to catch traps (0xcc), checking if we had been there before, just like AFL works (of course simplifying)

--> child loads some raw binary code (in my example has to be System V ABI)

I get error as below :

16:10|domin568[15] ~/Desktop/experiments/Instrumentation $ ./run.sh
PARENT 3866
task_for_pid() failed with message (os/kern) failure !
CHILD 3867

run.sh :

#!/bin/sh
clang -sectcreate __TEXT __info_plist Info.plist -o server server.c
codesign -s instrument ./server
./server

"instrument" is present at my keychain, and Always Trust for code singing, so I think it should't be case.

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>SecTaskAccess</key>
    <array>
        <string>allowed</string>
        <string>debug</string>
    </array>
</dict>
</plist>

Of course my code is only useful for specific case, it tries to fuzz one function which input is string and compare it with other string.

server.c :

#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <mach/mach.h>
#include <stdlib.h>
int main (int argc,char ** argv)
{
    pid_t pid = fork();
    pid_t parentPID, childPID; //maybe it's not really safe, nevermind
    int status;
    if (pid == 0)
    {
        printf ("CHILD %i\n",getpid());
        childPID = getpid();

        FILE * f = fopen(argv[1],"rb");
        if (f == NULL)
        {
            return -2;
            puts ("Cannot open file specified\n");
        }
        int from,to = 0;
        sscanf(argv[2],"%x",&from);
        sscanf(argv[3],"%x",&to);
        if (from >= to)
        {
            puts ("R u out of your mind ? check your range of bytes within the file... \n");
            return -3;
        }
        int fileSize = to - from;
        void * mem = mmap (NULL,fileSize,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE,fileno(f),0);
        if (mem == MAP_FAILED)
        {
            puts ("[!] Cannot allocate memory for file");
            return -4;
        }
        printf ("[-] File mapped to virtual memory : [%p]\n",mem);

        int (*pFunc)(char * str) = (int(*)(char *))(mem+from);

        int ret = pFunc("AAAAA");
        printf ("Returned : %d\n",ret);


    }
    else 
    {
        printf ("PARENT %i\n",getpid());
        parentPID = getpid();

        kern_return_t kret;
        mach_port_t task;
        mach_port_t target_exception_port;
        kret = task_for_pid (mach_task_self(),childPID,&task);
        if (kret != KERN_SUCCESS)
        {
            printf ("task_for_pid() failed with message %s !\n",mach_error_string(kret));
            sleep(100000);
        }

        //save the set of exception ports registered in the process 

        exception_mask_t       saved_masks[EXC_TYPES_COUNT];
        mach_port_t            saved_ports[EXC_TYPES_COUNT];
        exception_behavior_t   saved_behaviors[EXC_TYPES_COUNT];
        thread_state_flavor_t  saved_flavors[EXC_TYPES_COUNT];
        mach_msg_type_number_t saved_exception_types_count;

        task_get_exception_ports(task,
                        EXC_MASK_ALL,
                        saved_masks,
                        &saved_exception_types_count,
                        saved_ports,
                        saved_behaviors,
                        saved_flavors);

        //allocate and authorize a new port 

        mach_port_allocate(mach_task_self(),
                   MACH_PORT_RIGHT_RECEIVE,
                   &task);

        mach_port_insert_right(mach_task_self(),
                       target_exception_port,
                       target_exception_port,
                       MACH_MSG_TYPE_MAKE_SEND);

        //register the exception port with the target process 

        task_set_exception_ports(task,
                         EXC_MASK_ALL,
                         target_exception_port,
                         EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
                         THREAD_STATE_NONE);

        ptrace (PT_ATTACHEXC, childPID,0,0);
    }

    return 0;
}

Why this outputs error ? Is it case of how fork works under OSX ? What's the problem out there ? I'm not expert of how osx works underneath so maybe I missed something. Thanks for help :) !

Dominik


Solution

  • You call pid_t pid = fork(); therefore the PID of the child process in the parent process is stored in pid variable not in the childPID.

    The childPID variable is initialized in the child process only according to your example code.

    The task_for_pid() call is using childPID - basically you are using an uninitialized memory.