4

I am trying to inject a piece of shellcode inside a 32-bit ELF executable. I am running Ubuntu 14.04 64-bit. Hence, all the commands I have run require explicit switches to produce 32-bit code. I am using elf-infector to inject my shellcode.

C source of the host binary is given below:

/* simple_if.c */

#include <stdio.h>
#include "s2e.h"

int main()
{
  int var_cond;
  printf("Enter 0/1: ");
  scanf("%d", &var_cond);
  if(!var_cond)
    printf("Entered value: 0\n");
  else
    printf("Entered value: 1\n");

  return 0;
}

First I tried with a "Hello World" ASM payload:

; hello.asm
global _start
section .text

_start:
    jmp MESSAGE      ; 1) lets jump to MESSAGE

GOBACK:
    mov eax, 0x4
    mov ebx, 0x1
    pop ecx          ; 3) we are poping into `ecx`, now we have the
                     ; address of "Hello, World!\r\n" 
    mov edx, 0xF
    int 0x80
    jmp end          ; Injector will insert a jump to original entry point

    ;mov eax, 0x1    ; Intentionally not returning the control
    ;mov ebx, 0x0
    ;int 0x80

MESSAGE:
    call GOBACK       ; 2) we are going back, since we used `call`, that means
                      ; the return address, which is in this case the address 
                      ; of "Hello, World!\r\n", is pushed into the stack.
    db "Hello, World!", 0dh, 0ah    
end:

Compiled both the host and the parasite and injected the shellcode at the end.

gcc -m32 simple_if.c -o simple_if
nasm -f elf hello.asm -o hello.o
ld -m elf_i386 hello.o -o hello

# Test the assembled code
./hello
Hello, World!
Segmentation fault (core dumped)
# Segfault is natural, we are not gracefully returning to OS

# Now extract the shellcode
for i in `objdump -d ./hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' `; do echo -n "\\\\x$i" ; done | paste -d '' -s | sed 's/^/"/' | sed 's/$/"/g'
"\xeb\x14\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\x59\xba\x0f\x00\x00\x00\xcd\x80\xeb\x14\xe8\xe7\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a"

# Update parasite.h
make
./infector simple_if

Run the infected file
./simple_if
Hello, World!
Enter 0/1: 8
Entered value: 1
Segmentation fault (core dumped)

But, I expect the program should gracefully exit. Because, the infector inserts a jump to the OEP at the end of the shellcode. I tried the same with a different payload. But, in this case, the program runs in an infinite loop a never exits.

global     _start    
section    .text

_start:
    mov    ecx,0x23f0
    mov    edx,0x804869c
    jmp    prog_name

stub:
    pop    eax
    push   ebx
    mov    ebx,edx
    ;db     0x0f,0x3f,0x00,0xaa,0x00,0x00,0x00,0x00,0x00,0x00
    pop    ebx
    xor    eax,eax
    jmp    jump_start

prog_name:
    call   stub
    db "simple_if",0x00,0x90

jump_start:

This is what the infected file produces.

./simple_if
Enter 0/1: 9
Entered value: 1
Enter 0/1: 7
Entered value: 1
Enter 0/1: 6
Entered value: 1
Enter 0/1: 5
Entered value: 1
Enter 0/1: ^C

With GDB, I can see the shellcode is executed first and then the program jumps to OEP. The crash occurs thereafter. Can anybody please give me any clue what is going wrong?

  • does the infinite loop version also run the shellcode infinitely? It looks like the shellcode is being reached repeatedly and returning control to the start of the program each time. – peter ferrie Sep 24 '15 at 15:26
  • Compile your program with -O0 -g and gdb it. Run it; when it gets the signal, inspect eip (info registers) and the stack backtrace (bt). If that doesn't get you anywhere, set a breakpoint at the return in main (break simple_if.c:16, double check the line number), run, single step through what happens after that (stepi and maybe nexti over functions like exit handlers). – Guntram Blohm Sep 24 '15 at 16:39
  • It's possible that the registers and/or flags were changed from the previous values. Try pushad/popad and pushfd/popfd at the beginning and end of your shellcode respectively. This will restore the original registers and EFlags. If nothing else, just so we can rule it out a a problem. – Goodies Dec 15 '15 at 8:09
1

As @goodies said in the comment what is happening here is that you are destroying some register values and thus causing a crash.

Extend your payload with pusha/popa like this

_start:
  pusha
  jmp MESSAGE

and here

int 0x80
popa
jmp end     

And if you do all the steps now, you will get the requested result:

./simple_if 
Hello, World!
Enter 0/1: 9
Entered value: 1

It's usually the best approach when dealing with payload to maintain the state of the registers unless you specifically want some behavior to occur by modifying the regs.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.