Format String Attack - c

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.

Related

C sprintf exploit (formatting attack)

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...

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.

Input too big for array

I have a small question that I was just wondering about.
#include <stdio.h>
int main()
{
char n_string[5];
printf("Please enter your first name: ");
scanf("%s", n_string);
printf("\nYour name is: %s", n_string);
return 0;
}
On the 5th line I declare a string of 4 letters. Now this means I will only be able to hold 4 characters in that string, correct?
If I execute my program and write the name: Alexander, I get the output:
Your name is Alexander.
My question is, how come I could put a string of 9 characters into an array that holds 4?
You are overwriting a part of your program's stack by doing that, which is generally a very bad thing. In this case, you got lucky, but if you write further you will almost certainly get a segfault, when main tries to return.
Malicious actors will use this as a buffer overflow attack, to overwrite a function's return address.
If your question is "Why does C allow me to do this?", the answer is that C does not do bounds checking on arrays. It treats arrays (more or less) as a pointer to an address in memory, and scanf is more than happy to write to the memory location without worrying about what it actually represents.
You allocated 5 bytes, but since your CPU probably requires 16-byte alignment, the compiler probably allocated 16 bytes. Try this :
char n_string[5];
volatile int some_int;
some_int= 0;
sscanf(..);
printf("%s %d\n", n_string, some_int);
Is some_int still 0? Writing into n_string may have caused a buffer overflow and written bad data to some_int. Of course your compiler probably knows that some_int will stay a zero, so we declare it like volatile int some_int; to stop it from optimizing.
You reserve memory for 4 letters and the terminating zero. You write nine letters and a zero to it. You overstepped your bounds by 5 bytes. Those 5 bytes belonged to someone else, you just trashed his memory.
The most likely candidate for this is variables that are close. Test this, although not guaranteed, chances are you will see what happens with your remaining bytes: they will damage your i variable:
#include <stdio.h>
int main()
{
char n_string[5];
int i = 17;
printf("Please enter your first name: ");
scanf("%s", n_string);
printf("\nYour name is: %s", n_string);
printf("\nThe variable i is %d", i);
return 0;
}
I think there just happens to be valid memory in your process at the address contiguous to your array that means it just happens to work. However, it will be corrupting other memory elsewhere in the process by overwriting it.
Essentially you have a buffer overflow.

Asking for a name and returning the length of the name in C

I've been struggling with this code for quite some time now.
This is my first time posting here. I am new to C, and I feel that I almost got it.
I have to ask for your name, middle initial, and last name. Then I greet you and tell you the length of your name. Sounds simple enough. I have the following code, I have to use the header file as it is here and that makes things worse. Any help would be greatly appreciated, I feel that I already applied all my knowledge to it and still can't get it to work.
This is my header file:
#ifndef NAME_H_
#define NAME_H_
struct name{
char first[20];
char middle;
char last[20];
};
#endif
and this is my .c file:
#include "name.h"
#include <stdio.h>
#define nl printf("\n");
int strlen(char*s);
char first;
char middle;
char last;
main()
{
printf("enter your first name : ");
scanf("%c", &first);
printf("\n enter your middle initial name : ");
scanf("%c", &middle);
printf("\n enter your last name: ");
scanf("%c", &last);
printf("\n\n Hello %c",first, " %c" ,middle, " %c", last);
printf("\n The String returned the following length: ",strlen);
}
I have t use printf and scanf, then store the name components a name "structure" imported from name.h and lastly use int strlen(char *s); to calculate it.
I get this output with the weird indentation and everything:
enter your first name : Joe
enter your middle initial name :
enter your last name:
Hello J
The String returned the following length: [-my user id]$
Thanks!
Several things about this are not quite right.
First, you shouldn't be declaring strlen yourself. It's a standard C library function, which means you should include the appropriate header. In this case,
#include <string.h>
Second, you're storing the input in variables of type char. Those are literally what they say: they store a single character. So unless you're only allowing people to have single-character names, you need a bit more than that. This sort of string input problem is actually rather tricky in C, since you have to do explicit memory management and don't know how much data the user is going to send you in advance. One of the simpler things is to just use a large buffer and truncate, but for a more complex program you'd want to do error handling and possibly dynamically resize the buffer. But for starters:
char first[1024];
char middle[1024];
char last[1024];
will at least get you started. Your struct name has some of this, but you're not currently using it (and the sizes are pretty small).
Next, scanf is a tricky way to get input strings. scanf of a %s pattern will happily read more than 1024 characters and write over the end of the buffer and destroy your program. This is why C programmers usually read input data using fgets instead, since then you can more easily say how big of a buffer you're willing to read:
fgets(first, sizeof(first), stdin);
Be aware that if the user enters more than 1023 characters, it will read the first 1023 characters and then leave the rest there, where you'll end up reading it as part of the middle name. String handling in C is complex! C is not good at this sort of thing; that's why people tend to use Perl or similar languages for this sort of interactive string handling where you don't know sizes in advance. In C, you have to pursue a strategy like repeatedly calling fgets until you get a newline at the end of the result and then deciding whether to dynamically resize your data structure or throw an error. Alternately, you can use scanf with %1023s but you need to qualify the format to specify the maximum length. The syntax is a bit weird and tricky; fgets is simpler when you're reading character strings.
As mentioned in the other answer, strlen is a function that you need to call on a char * variable (or char array) to get the length of the string it holds. You probably want to call it on first, middle, and last and add them together.
Finally, in your last printf, you have to pass one format and then all of the arguments for that format. You want something more like:
printf("\n\n Hello %s %s %s", first, middle, last);
(once you fix the type of those variables).
This is a lot of random detail. I hope it helps some. The important brief takeaway is that a string in C is a sequence of char ending in a char with a value of 0, and all C data structures have to be sized in advance (either statically or dynamically with malloc). C furthermore has no bounds checking, so it's completely up to you to ensure that you only read as much data as you created space for.
use
strlen(first)
to get the length of variable first ..similarly for other varibles... To get the cumulative length use
printf("\n Length: ",strlen(first)+strlen(middle)+strlen(last));

C: scanf behavior in a for-loop

I came across the following code :
int i;
for(; scanf("%s", &i);)
printf("hello");
As per my understanding, if we provide integer input scanf would be unsuccessful in reading and therefore return 0, thus the loop should not run even once. However, it runs infinitely by accepting all types of inputs as successful reads.
Would someone kindly explain this behaviour?
That is the incorrect format specifier for an int: should be "%d".
It is attempting to read a string into an int variable, probably overwriting memory. As "%s" is specified, all inputs will be read thus scanf() returns a value greater than zero.
(Edit: I don't think this answer should have been accepted. Upvoted maybe, but not accepted. It doesn't explain the infinite loop at all, #hmjd does that.)
(This doesn't actually answer the question, the other answers do that, but it's interesting and good to know.)
As hmjd says, using scanf like this will overwrite memory ("smash the stack"), as it starts writing to i in memory, and then keeps going, even outside the 4 bytes of memory that i takes up (or 8 bytes, on a 64-bit platform).
To illustrate, consider the following bit of code:
#include<stdio.h>
int main() {
char str_above[8] = "ABCDEFG";
int i;
char str_below[8] = "ABCDEFG";
scanf("%s", &i);
printf("i = %d\n", i);
printf("str_above = %s\nstr_below = %s\n", str_above, str_below);
return 0;
}
Compiling and running it, and entering 1234567890 produces the following output:
i = 875770417
str_above = 567890
str_below = ABCDEFG
Some points:
i has little correspondence to the integer 1234567890 (it is related to the values of the characters '1',...,'4' and the endianness of the system).
str_above has been modified by scanf: the characters '5',...,'0','\0' have overrun the end of the block of memory reserved for i and have been written to the memory reserved for str_above.
The stack has been smashed "upwards", i.e. str_above is stored later in memory than i and str_below is stored earlier in memory. (To put it another way &str_above > &i and &str_below < &i.)
This is the basis for "buffer overrun attacks", where values on the stack are modified by writing too much data to an array. And it is why gets is dangerous (and should never be used) and using scanf with a generic %s format specifier should also never be done.

Resources