I am practicing a function return address overwriting exploit. However, the program instruction pointer instead gets overwritten by gibberish. I have tried compiling with -fno-builtin
and -fno-stack-protector
, but nothing seems to change the behavior.
Code (from "Hacking the Art of Exploitation", 2nd Edition, Page 125):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_authentication(char *password) {
char password_buffer[16];
int auth_flag = 0;
strcpy(password_buffer, password);
if(strcmp(password_buffer, "brillig") == 0)
auth_flag = 1;
if(strcmp(password_buffer, "outgrabe") == 0)
auth_flag = 1;
return auth_flag;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
if(check_authentication(argv[1])) {
printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
printf(" Access Granted.\n");
printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
} else {
printf("\nAccess Denied.\n");
}
}
Running in the debugger:
run $(perl -e 'print "\x97\x62\x55\x56"x8')
This address is to come in at the start of "Access Granted". See below disassembly at 0x56556297 <+82>: add esp,0x4
:
0x5655627e <+57>: push eax
0x5655627f <+58>: call 0x565561d9 <check_authentication>
0x56556284 <+63>: add esp,0x4
0x56556287 <+66>: test eax,eax
0x56556289 <+68>: je 0x565562ba <main+117>
0x5655628b <+70>: lea eax,[ebx-0x1fd1]
0x56556291 <+76>: push eax
0x56556292 <+77>: call 0x56556060 <puts@plt>
0x56556297 <+82>: add esp,0x4
0x5655629a <+85>: lea eax,[ebx-0x1fb4]
0x565562a0 <+91>: push eax
0x565562a1 <+92>: call 0x56556060 <puts@plt>
0x565562a6 <+97>: add esp,0x4
0x565562a9 <+100>: lea eax,[ebx-0x1f9e]
0x565562af <+106>: push eax
0x565562b0 <+107>: call 0x56556060 <puts@plt>
Stack before string copy:
(gdb) next
9 strcpy(password_buffer, password);
(gdb) x/12x $esp
0xffffd190: 0x00000002 0xffffd264 0xffffd270 0x565562fd
0xffffd1a0: 0x00000000 0x56559000 0xffffd1b8 0x56556284
0xffffd1b0: 0xffffd429 0x00000000 0x00000000 0xf7dd6e46
(gdb)
Stack after string copy:
(gdb) next
11 if(strcmp(password_buffer, "brillig") == 0)
(gdb) x/12x $esp
0xffffd190: 0x56556297 0x56556297 0x56556297 0x56556297
0xffffd1a0: 0x56556297 0x56556297 0x56556297 0x56556297
0xffffd1b0: 0xffffd400 0x00000000 0x00000000 0xf7dd6e46
(gdb)
... and the crash with backtrace and value of instruction pointer.
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xfdabe850 in ?? ()
(gdb) bt
#0 0xfdabe850 in ?? ()
#1 0x565562a6 in main (argc=-1159180033, argv=0x83fffffd)
at auth_overflow2.c:26
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) i r $eip
eip 0xfdabe850 0xfdabe850
(gdb)
Where does this value of "eip" come from? Is there some advanced Linux protection I did not (or cannot) turn off?
I am running on:
tester@Test:/$ uname -a
Linux Test 5.10.0-kali3-amd64 #1 SMP Debian 5.10.13-1kali1 (2021-02-08) x86_64 GNU/Linux
I did it on a 64bit system. Here is check_authentication disassebly , you can here that function allocates 32 bytes of space for stack [ sub rsp,0x20 ] where all of the variables are stored , and after that you need additional 8 bytes of memory for you rip . So in order to overwrite your instruction pointer you need to first fill the initial 32 bytes and then give the address of the place that you want to go to See here precisely two 'A' have been inserted in rip. BTW if you are learning then i would suggest you to use TCC , it creates very simple output which you can easily understand in assembly.
User contributions licensed under CC BY-SA 3.0