why does snprintf() write extra characters? - c

In my program, I open a file and write "Hello world" in it. I am using snprintf() to populate 'fname' variable. After this I put gdb on a.out and print the string 'fname'. I see that there are lots of extra character in string 'fname' which I did not assign. Where are these extra characters coming from? Could anyone help please?
3 int main(void)
4 {
5 FILE *debug_fp = NULL;
6 char fname[100];
7
8 snprintf(fname, 100, "./my_debug_%d", getpid());
9 debug_fp = fopen(fname, "w");
10 fprintf(debug_fp, "%s", "Hello world");
11 return 0;
12 }
gdb output:
(gdb) b test.c:10
Breakpoint 1 at 0x4005be: file test.c, line 10.
Breakpoint 1, main () at test.c:10
10 fprintf(debug_fp, "%s", "Hello world");
(gdb) p fname
$1 = "./my_debug_16178\000\000\000\000\000\000\000\000\300\313Ab:\000\000\000\360\005#\000\000\000\000\000\063\004#\000\000\000\000\000\001\000\000\000\000\000\301\000'\006#", '\000' <repeats 13 times>"\300, \313Ab:\000\000\000\360\005#", '\000' <repeats 13 times>"\260, \343\377\377"
(gdb) q
Thank you.

In this case gdb doesn't care about your 0-terminator in the string and just prints the array, i.e. the full 100 characters in fname.
You can also use printf "%s" or p /s if you want gdb to treat your array as a C-string.

As your question is about seeing a lot of extra characters that you didnt assign, it is always the best practice to initialize the memory (simple variables, arrays or pointers) you define, so that you always see what you expect.
In your case, you could do:
char fname[100] = {0};
The response I get from gdb is more predictable thus:
(gdb) b 9
Breakpoint 1 at 0x400610: file st_fname.c, line 9.
(gdb) run
Starting program: /home/gops/data/samples/st_fname.o
Breakpoint 1, main () at st_fname.c:9
9 fprintf(debug_fp, "%s", "Hello world");
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.166.el6_7.7.x86_64
(gdb) p fname
$1 = "./my_debug_26808", '\000' <repeats 83 times>
(gdb)
Now you should see what you expect. Hope it helps.

Related

Buffer overflow attack without changing the return address

I need to call the login function in the below sample code. We can achieve this by changing the return address to the login function directly using buffer overflow attack. But I need to keep the return address as the same. Is there any other way to print logged in message without changing the return address?
char getPass()
{
int flag = 'F';
char pass[10];
gets(pass);
return (char) flag;
}
void login()
{
printf("Logged in");
exit(0);
}
void main()
{
printf("Enter Passwd");
if(getPass() == 'T')
{
login();
}else{
print("Failed");
exit(1);
}
}
Getting this to work depends on how the compiler decided to arrange the variables. If flag appears in memory after pass, then entering in more characters than pass will hold results in flag getting overwritten.
When I ran this program in a debugger and printed the addresses of these variables, I got the following:
(gdb) start
Temporary breakpoint 1 at 0x40060e: file x1.c, line 19.
Starting program: /home/dbush/./x1
Temporary breakpoint 1, main () at x1.c:19
19 printf("Enter Passwd");
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64
(gdb) step
20 if(getPass() == 'T')
(gdb)
getPass () at x1.c:6
6 int flag = 'F';
(gdb)
8 gets(pass);
(gdb) p pass
$1 = "\000\000\000\000\000\000\000\000", <incomplete sequence \341>
(gdb) p &pass
$2 = (char (*)[10]) 0x7fffffffdec0
(gdb) p &flag
$3 = (int *) 0x7fffffffdecc
We can see that in this particular instance that flag is 12 bytes past the start of pass. My machine is also little-endian, meaning that the first of the 4 bytes of flag contain the value to be overwritten.
So we can exploit the buffer overflow vulnerability by entering in 13 characters, the last of which is T. This results in 10 characters being written to pass, two more to the padding bytes between pass and flag, the character T in the first byte of flag, and a 0 for the terminated null byte in the second byte of flag. Now the variable flag contains 'T' which is what gets returned from the function.
Note also that doing so doesn't write past flag into the function's return value. This is possible because flag is an int and little endian byte ordering is used.
Sample input/output:
[dbush#db-centos7 ~]$ ./x1
Enter Passwd1234567890TTT
Logged in[dbush#db-centos7 ~]$

GCC based SIGSEGV error?

So I have been writing a handful of C libraries for my own personal use and I have been doing swell until my latest library, which just contains a bunch of string functions. As you can probably tell by the question title, I am getting a SIGSEGV signal. The problem is this: my research indicates that about 99% of all SIGSEGV errors are due to stack overflow, itself due to bad recursion, but as you will see, I am not using any recursion. Furthermore, there are a few odd problems that occur. For one, printf is exhibiting a lot of funky behavior. GDB encounters printf calls but does not actually seem to execute them until a few lines of code later. Likewise, one of my printf statements is being broken up somehow, and only a part is being called, with another part being chopped off apparently.
Here are the key code snippets, some stuff is named funny because I suspected name clashing may be the cause at one point and may have gone a little overboard...
"firstIndexOf" function (finds the first index of a character in a string, if that character is in said string), found at line 31:
int firstIndexOfFUNCTION(char thisChar, char* inThisString)
{
int lengthABC = strlen(inThisString);
printf("\nLength of %s is %d",inThisString,lengthABC);
int thisFunctionsIndex;
for (thisFunctionsIndex=0;thisFunctionsIndex<lengthABC;thisFunctionsIndex++)
{
printf("\n%dth iteration:\n-char 1 is %c\n-char2 is %c",thisFunctionsIndex,inThisString[thisFunctionsIndex],thisChar);
if (inThisString[thisFunctionsIndex] == thisChar)
{
printf("\nMatch found on iteration %d!",thisFunctionsIndex);
return thisFunctionsIndex;
}
}
printf("\nNo matches detected...");
return -3;
}
The "string_functions_test" function (a function just meant to test the other functions) at line 62:
int string_functions_test()
{
printf("PROGRAM INITIALIZED!\n\n");
char* sft_string;
int sft_index;
sft_string = malloc(sizeof(char)*100);
sft_string = "B um sbm. Sbm B bm.";
printf("2nd BREAKPOINT");
sft_index = firstIndexOfFUNCTION('B',sft_string);
sft_string[sft_index] = 'I';
return 0;
}
and last but not least, good ol' main, at line 107:
int main(int argc, char* argv[])
{
string_functions_test();
return 0;
}
Here is the gdb output for a step-through of my code:
(gdb) b 105
Breakpoint 1 at 0x400970: file string_functions.c, line 105.
(gdb) run
Starting program: /home/user/Development/projects/c/string_functions/source/c/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffde98) at string_functions.c:109
109 string_functions_test();
(gdb) step
string_functions_test () at string_functions.c:64
64 printf("PROGRAM INITIALIZED!\n\n");
(gdb) next
PROGRAM INITIALIZED!
68 sft_string = malloc(sizeof(char)*100);
(gdb) next
69 sft_string = "B um sbm. Sbm B bm.";
(gdb) next
71 printf("2nd BREAKPOINT");
(gdb) next
73 sft_index = firstIndexOfFUNCTION('B',sft_string);
(gdb) step
firstIndexOfFUNCTION (thisChar=66 'B', inThisString=0x400ab9 "B um sbm. Sbm B bm.") at string_functions.c:33
33 int lengthABC = strlen(inThisString);
(gdb) next
34 printf("\nLength of %s is %d",inThisString,lengthABC);
(gdb) next
2nd BREAKPOINT
36 for (thisFunctionsIndex=0;thisFunctionsIndex<lengthABC;thisFunctionsIndex++)
(gdb) next
38 printf("\n%dth iteration:\n-char 1 is %c\n-char2 is %c",thisFunctionsIndex,inThisString[thisFunctionsIndex],thisChar);
(gdb) next
Length of B um sbm. Sbm B bm. is 19
0th iteration:
-char 1 is B
39 if (inThisString[thisFunctionsIndex] == thisChar)
(gdb) next
41 printf("\nMatch found on iteration %d!",thisFunctionsIndex);
(gdb) next
-char2 is B
42 return thisFunctionsIndex;
(gdb) next
47 }
(gdb) next
string_functions_test () at string_functions.c:75
75 sft_string[sft_index] = 'I';
(gdb) next
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400883 in string_functions_test () at string_functions.c:75
75 sft_string[sft_index] = 'I';
(gdb) next
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) quit
You may notice that the printf which prints "2nd Breakpoint" is called, and then the program steps into a different function before the results are seen. I am assuming this is some whacky behavior on the part of the gcc compiler meant to serve as a cpu optimization, but it is sort of messing me up right now obviously. Likewise, the printf in my for loop is being broken up after the first formatted char. These two things are making it super hard to detect what exactly is happening. Has anyone experienced similar behavior?
In case it matters, I am including:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
You are first pointing the pointer sft_string to what is returned from malloc. In the next line you make it point to a literal string. You need to copy it. A literal is built into the source code and cannot be changed during execution. Otherwise it raises a segment fault, which means that an area of memory that has code is being changed. Use strcpy.

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

redirect output to a file from gdb

I'm currently printing the contents of a variable from gdb like this:
(gdb) call printf("%s",buffer)
The buffer contains a large string and I want to redirect it to a file rather than screen.
Enabling logging feature in gdb will not help here. And I'm not able to use > command to redirect either. Ofcourse I can create a file in the program and write the buffer to this file and invoke the write to file through gdb. But is there a easier way out?
This will redirect the target's stdout to a file of your choice, call printf, then restore stdout to its previous setting. fflush is called right before changing the file descriptor, so that output gets sent to the correct place.
$ gdb f
...
(gdb) list
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 main()
6 {
7 char buf[] = "test";
8
9 printf("%p ", (void *)buf);
10 printf("%d\n", strlen(buf));
11 }
(gdb) break 10
Breakpoint 1 at 0x80484d3: file f.c, line 10.
(gdb) run
Starting program: f
Breakpoint 1, main () at f.c:10
10 printf("%d\n", strlen(buf));
(gdb) call fflush(stdout)
0xbffff117 $1 = 0
(gdb) call dup(1)
$2 = 3
(gdb) call creat("/tmp/outputfile",0644)
$3 = 4
(gdb) call dup2(4,1)
$4 = 1
(gdb) call printf("%s\n", buf)
$5 = 5
(gdb) call fflush(stdout)
$6 = 0
(gdb) call dup2(3,1)
$7 = 1
(gdb) call close(3)
$8 = 0
(gdb) call close(4)
$9 = 0
(gdb) cont
Continuing.
4
[Inferior 1 (process 3214) exited with code 02]
(gdb) shell cat /tmp/outputfile
test
You aren't able to use > or you did not know how to use it in gdb? You can redirect output from inside of gdb. Try:
(gdb) run > out.txt
(gdb) run > /dev/null

Confused by gdb print ptr vs print "%s"

1167 ptr = (void*)getcwd(cwd, MAX_PATH_LENGTH-1);
(gdb) n
1168 if (!ptr) {
(gdb) print ptr
$1 = 0xbff2d96c "/media/MMC-SD/partition1/aaaaaaaaaaa"
(gdb) print &cwd
$2 = (char (*)[3500]) 0xbff2d96c
(gdb) print strlen(cwd)
$3 = 36
(gdb) print "%s",cwd
$4 = "/media/MMC-SD/partition1/aaaaaaaaaaa", '\0' <repeats 912 times>, "��O�001\000\000\000\000��027\000\000\000�3����EL鷠3�000��027\000\000\000\000\000\000\000\027\000\000\000\000��/�027\000\000\000�3����N����\230���鷠3�000��027\000\000\000\000\000\000\000��000\000\000\000\001\000\000\000��M鷠3����\000\000\000\000.\231�027��w\005\b\001\000"...
(gdb) print "%s", ptr
$5 = 0xbff2d96c "/media/MMC-SD/partition1/aaaaaaaaaaa"
(gdb) Quit
Why is ptr printing the string correctly but cwd not; this also affects the program and it crashes if I try to use the cwd...
[edit: turns out that crash was caused by a stupid buffer overflow on this var... grr...not gdb, but the print question was still valid]
I agree with mweerden. Trying something I believe is similar to your code, I get:
(gdb) print cwd
$1 = "/media", '\0' <repeats 782 times>, "\016���" ...
(gdb) print (char*) cwd
$2 = 0xbfc8eb84 "/media"
from gdb, so it seems that since cwd was defined as char cwd[3500], gdb prints the entire array, while if you tell gdb to interpret it as a char*, it will work as you expect. If your application crashes, I would assume it is because of something else.
The reason that cwd is printed differently in gdb is because gdb knows that ptr is a char * (I guess) and that cwd is an array of length 3500 (as shown in your output). So when printing ptr it prints the pointer value (and as a service also the string it points to) and when printing cwd it prints the whole array.
I don't see any reason why using cwd instead of ptr would lead to problems, but I would need to see some code to be sure.
That ptr is displayed as nicely-formatted string and cwd as "byte buffer" is probably specific to gdb. In any case it shouldn't affect your application; according to man 3 getcwd, ptr should point to cwd (or it should be NULL if an error occurred).
Can you use ptr without crashing the program?
What type is cwd? The above code snippet doesn't tell us that. It could be that ptr being a void* is treated differently by gdb.

Resources