joosooph
joosooph

Reputation: 17

Shellcode not running, despite disabling stack protections

I am exploring shellcode. I wrote an example program as part of my exploration. Using objdump, I got the following shellcode:

\xb8\x0a\x00\x00\x00\xc

for the simple function:

int boo()
{
    return(10);
}

I then wrote the following program to attempt to run the shellcode:

#include <stdio.h>
#include <stdlib.h>

unsigned char code[] = "\xb8\x0a\x00\x00\x00\xc3";  

int main(int argc, char **argv) {
  int foo_value = 0;

  int (*foo)() = (int(*)())code;
  foo_value = foo();

  printf("%d\n", foo_value);
}

I am compiling using gcc, with the options:

-fno-stack-protector -z execstack

However, when I attempt to run, I still get a segfault.

What am I messing up?

Upvotes: 1

Views: 133

Answers (1)

Omar
Omar

Reputation: 973

You're almost there!

You have placed your code[] outside of main, it's a global array. Global variables are not placed on the stack. They can be placed:

  • In the BSS section if there are not initialized
  • In the data section if there are initialized and access in both read/write
  • In the rodata section if there are only accessed in read

Let's verify this You can use readelf command to check all the sections of your binary (I only show the ones we are interested in):

$ readelf -S --wide <your binary>
There are 31 section headers, starting at offset 0x39c0:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
[...]
  [16] .text             PROGBITS        0000000000001060 001060 0001a5 00  AX  0   0 16
[...]
  [18] .rodata           PROGBITS        0000000000002000 002000 000008 00   
[...]
  [25] .data             PROGBITS        0000000000004000 003000 000017 00  WA  0   0  8
[...]
  [26] .bss              NOBITS          0000000000004017 003017 000001 00  WA  0   0  1

Then we can look for your symbol code in your binary:

$ readelf -s <your binary> | grep code
    66: 0000000000004010     7 OBJECT  GLOBAL DEFAULT   25 code

This confirms that your variable/array code is in .data section, which doesn't present the X flag, so you cannot execute code from it.

From there, the solution is obvious, place your array in your main function:

int main(int argc, char **argv) {
  uint8_t code[] = "\xb8\x0a\x00\x00\x00\xc3";  
  int foo_value = 0;
  
  int (*foo)() = (int(*)())code;
  foo_value = foo();

  printf("%d\n", foo_value);
}

However, this may also not work!

Your C compiler may find that yes, you are using code, but never reading from it anything, so it will optimize it and simply allocate it on the stack without initializing it. This is what happens with my version of GCC.

To force the compiler to not optimize the array, use volatile keyword.

int main(int argc, char **argv) {
  volatile uint8_t code[] = "\xb8\x0a\x00\x00\x00\xc3";  
  int foo_value = 0;

  int (*foo)() = (int(*)())code;
  foo_value = foo();

  printf("%d\n", foo_value);
}

In a real use-case, your array would be allocated on the stack and sent as a parameter to another function which itself would modify the array content with shellcode. So you wouldn't encounter such compiler optimization issue.

Upvotes: 1

Related Questions