Almost every tutorial about writing the shellcode, usually begin with an example of attempts to use some sort of syscall in assembler mnemonic code, translate to the hex values, and very next of implement to the C language or better undirected in some vulnerability application. So based upon it, this brief introduction will be devoted for sys call handler indeed. Short description of our environment : mac os x (darwin kernel), xcode package (including development tools like: GNU C/C++ language compiler, GNU debugger, otool, nasm assembler, linker etc.). During daily work under a macintosh OS, we will see some subtile differences in ie. architecture of kernel, resources management, interrupts handlers, virtual memory accessing and the others. So first of all, the main aim of this “tutorial” appart of a shellcode ofcourse, will be show these distinctions (at least these listed above) and instruct step by step how to get rid of our habits acquired through the experience under other unix systems, specially these open source like: Linux, FreeBSD (as a curiosity, a darwin kernel is also a open source project), and avoid unecessary errors.
NOTE: The codes presented in this article will not be compatible with mac os PPC (Power PC x86 64), but it’ll work under BSD or Solaris. If You’re not sure, check before (eg. by command: uname -a)
Darwin lukas_ 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386.
First of all, we have to figure out where is the storage of our sys calls table.
Below is the example mnemonic code for call a method sys_kill.
xor eax, eax
mov eax, -1
mov al, 37
on the beginning, we define our separate sections (segments) towards text and data and global variable ie. opening label: _start
after that, we focus on particular parts of assembly code which send a sys_kill signal to a specific process identifier (in this example to all running processes and services) using a kernel mode.
37 - number of syscall - sys_kill (compare with a syscall table above)
EBX = PID number (look at the specification below)
ECX = signal identifier
First two lines resets a %eax register and push hex value 0x09 on the stack, what is synonumous to put the same value into EBX register, and this means number of signal - in this example SIGKILL.
Next, we inform what is the identifier of process that we need to shutdown. A value -1 means every running process including child processes started by the others. Now once again we shall a reset the register eax, and add to the AL register system call number (37) and call the kernel interrupt 0x80.
sh-3.2# nasm -f macho killer.asm NOTE: mach-O is an executable format under the 32-bit mac os, similar as ELF in Linux.
sh-3.2# ld -o killer killer.o ld: could not find entry point “start” (perhaps missing crt1.o) for inferred architecture i386
Uppps, Huston, huston we’ve got a problem ;) This if first habit for users with background in Linux - _start is an entry point but not for linker program under mac. How to solve that? We have at least two distinct methods. First is a change a name of label into start (instead of _start that we defined) directly in source code. Second, we can use a specific switch straight from command line.
sh-3.2# ld -e _start -o killer killer.o
Now you can try how our masterpiece works. And one attention - better do not run it when you are logged as a root , unless you necessarily want to reset your machine, cause the execute this code may have unpredictable effects. But there is one inaccuracy. But before i’ll discuss further details, lets try to disassemble our binary file, build a plain shellcode and embed in C language.
sh-3.2# objdump -d killer
sh: objdump: command not found
Forget about it. We have to get acquainted with the other tool, actually otool. (i recommed see the man page first).
int main(int argc, char **argv)
/*creating a function pointer*/
func = (int (*)()) code;
But at this point a little problem has occurred. So called, golden rule of writing the shellcodes proclaims, that the null bytes are not allowed. If we had to exploit this shellcode in some vulnerable program, it wouldn’t be work. Null byte is treat as the end of string. But before i’ll show how to get rid of them from our code, most appropriate would be to explain where actually did they come from. Lets take a look once again on the diassembly code, but now using more efficient debugger.
sh-3.2# gdb killer GNU gdb 6.3.50-20050815 (Apple version gdb-960) (Sun May 18 18:38:33 UTC 2008)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “i386-apple-darwin”…Reading symbols for shared libraries . done
If we’ll investigate a code and compare places where null bytes appears, we can see that they occurs exactly three times, and exactly after that we put a signal number on a stack. As you surely remember we used to that a special register EAX. But %eax has a 32 bit amount, and we allocated only one hex value, what is equal 8 bits. So, where is the rest 24 bits? Yeah, you guessed, in these three null bytes - each represents 8 bits, and is empty. How to fix it? I’ll surprise you, it’s more simpler than you think. Consider following example.
mov al, 0x09
xor eax, eax
So replace the line “push 0x09” within code above and check results.