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...
Related
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.
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
I am running a simple C Application which will get PID Of an process continuously.
This is running on an custom ARM Board.
pid_t GetStreamerPID()
{
pid_t pid = 0;
int ret = 0;
char line[100];
char command[50] = "pidof -s gst-launch-0.10";
memset(line, '\0', 100);
FILE *cmd = popen(command, "r");
if ( cmd == NULL )
{
perror("Popen\n");
exit(0);
}
ret = fread(line, sizeof(char), 20, cmd);
pclose(cmd);
pid = atoi(line);
return pid;
}
Randomly, the code is throwing segmentation Fault at pclose.. I am debugging this from past week and I am unable to find out the cause of the issue.
Attaching gdb backtrace:
Program received signal SIGSEGV, Segmentation fault.
0x76e3a588 in free () from /lib/libc.so.6
(gdb) bt full
#0 0x76e3a588 in free () from /lib/libc.so.6
No symbol table info available.
#1 0x76e25c20 in fclose##GLIBC_2.4 () from /lib/libc.so.6
No symbol table info available.
#2 0x000109b4 in GetStreamerPID () at getPid.c:111
pid = 0
ret = 0
line = '\000' <repeats 99 times>
command = "pidof -s gst-launch-0.10", '\000' <repeats 25 times>
cmd = 0x136c008
#3 0x00010a50 in startStreamer () at getPid.c:147
command = '\000' <repeats 255 times>
pid = 0
#4 0x0001087c in CheckVideoState () at getPid.c:81
iVideoOn = 1
#5 0x00010a20 in MainLoop () at getPid.c:137
No locals.
#6 0x00010b74 in main () at getPid.c:183
No locals.
Also, one more wierd observation is , after I close gdb and run "reboot" command it throws segmentation fault. Again this is random, it can be any command..
I can provide you as much as information you want. Please help me in debugging this wierd issue...
Your crash is happening inside free.
Any such crash is a 99.99% sign that you have heap corruption elsewhere, and very likely has absolutely nothing to do with the code you've shown, or with pclose.
Tools such as Valgrind, Address Sanitizer, or GLIBC mcheck are your best bet.
So here's the code containing the printf (with line numbers, this is from think.c):
30: char *think = getRandomMemory();
31: printf("\33[2K\r");
32: if(think == NULL)
33: think = "NULL";
34: printf("I have an idea: %s\n", think);
35: parse(think);
36: freeMemory(think);
37: printf("> ");
And the code from getRandomMemory() which makes sure the returned pointer points to heap allocated space:
char *getRandomMemory()
{
char *ret;
// --SNIP--
size_t l = strlen(ret) + 1;
char *rret = getMemory(sizeof(char) * l);
for(int i = 0; i < l; i++)
rret[i] = ret[i];
printf("--- %s ---\n", rret);
return rret;
}
And finally this is what gdb gives me when running this. Please note that the "--- test ---" comes from " printf("--- %s ---\n", rret)" above:
(gdb) run
Starting program: /home/v10lator/Private/projekte/KI/Lizzy
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Loading Lizzy 0.1... Done!
> --- test ---
[New Thread 0x7ffff781f700 (LWP 32359)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff781f700 (LWP 32359)]
0x00007ffff7869490 in _IO_vfprintf_internal (s=<optimized out>, format=<optimized out>,
ap=ap#entry=0x7ffff781ee68) at vfprintf.c:1642
1642 vfprintf.c: Datei oder Verzeichnis nicht gefunden.
(gdb) bt
#0 0x00007ffff7869490 in _IO_vfprintf_internal (s=<optimized out>, format=<optimized out>,
ap=ap#entry=0x7ffff781ee68) at vfprintf.c:1642
#1 0x00007ffff7919235 in ___printf_chk (flag=1, format=<optimized out>) at printf_chk.c:35
#2 0x00000000004016bc in printf () at /usr/include/bits/stdio2.h:104
#3 run (first=<optimized out>) at think.c:34
#4 0x00007ffff7bc64c6 in start_thread (arg=0x7ffff781f700) at pthread_create.c:333
#5 0x00007ffff790a86d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
I really don't know what's wrong here, so hopefully someone sees the mistake.
//EDIT: Forgot the getMemory/freeMemory functions:
/*
* This allocates memory.
* The difference between usig malloc directly is that this function will
* print an error and exit the program in case something bad happens.
*/
char *getMemory(size_t size)
{
char *mem = malloc(size);
if(mem == NULL)
crashWithMsg("Internal error (malloc failed)!");
return mem;
}
/*
* This deallocates memory.
* The difference between using free directly is that this function will
* set the pointer to NULL afterwards.
*/
void freeMemory(void **ptr)
{
free(*ptr);
*ptr = NULL;
}
The problem is your call to freeMemory:
freeMemory(think);
You've coded that function to take the address of the pointer to the memory to be freed, rather than the pointer itself. So you need to call it with:
freeMemory(&think);
[Deleted misstated assertion]
Why not use strcpy()?
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