I am very new to C and as a class assignment my instructor wanted us to play with buffer overflows. I found the following online as an example and I can't figure out how to use it!
#include <stdio.h>
char temp[32];
unsigned int setThis=1;
printf("Enter your temp: \n");
fgets(temp, 34, stdin); //Takes a 34 buffer size when temp can only be 32
printf("Value of you setThis: %d", setThis);
So my question is, how do i set "setThis" to a certain variable?
Any help is appreciated, BeastlyJman.
There's no guaranteed way to do it, but typically variables are put on the stack such that the first variable is last in memory. So if you declare setThis before temp[32], then setThis will be at the end of the temp array, and you can overwrite it.
But as I said, there's no guarantee that's what the compiler will do. You should really check the assembly code that the compiler generates to see where temp and setThis are located.
Also, you can save yourself some typing if you reduce the size of temp to temp[8] and then pass 10 to fgets. To cause an overflow, you need to type more characters than the buffer can hold.
Related
Could you please explain me memory allocation in C for strings and integer array after using sprintf function?
#include <stdio.h>
#include <stdlib.h>
int main() {
char str[10];
long long int i = 0, n = 7564368987643389, l;
sprintf(str, "%lld", n); // made it to a string
printf("%c%c", str[11], str[12]);
}
In the above code, string size is 10 inclusive of null character. How come we access 11 and 12 elements in it? The program prints 43
Here
sprintf(str,"%lld",n);
n i.e 7564368987643389 converted into character buffer & stored into str. It looks like
str[0] str[2] str[4] str[6] str[8] str[10] str[12] ..
--------------------------------------------------------------------------------------
| 7 | 5 | 6 | 4 | 3 | 6 | 8 | 9 | 8 | 7 | 6 | 4 | 3 | 3 | 8 | 9 | \0 |
--------------------------------------------------------------------------------------
str str[1] str[3] str[5] str[7] str[9] str[11] ..
As you can see str[11] is 4 and str[12] is 3. Hence the printf() statement below prints:
printf("%c %c",str[11],str[12]);
4 3
But since you have declared str of 10 characters and in sprintf() you are trying to store more than 10 characters, it causes undefined behavior.
You’ve written past the end of the array into memory you don’t own - the behavior on doing so is undefined, and any outcome is possible.
C does not require bounds checking on array writes or accesses. You won’t get an ArrayIndexOutOfBounds-type exception if you index past the end of the array.
In this case you didn’t overwrite anything important, so the program ran as you would expect, but it doesn’t have to. You could have corrupted data in an adjacent object, or you could have gotten a runtime error from the OS.
You are responsible for knowing how big the target buffer is and not reading or writing past the end of it. The language will not protect you here.
Could you please explain me memory allocation in C for strings and integer array?
Most of the time in C, memory allocation is your responsibility. In particular, when you call functions such as strcpy, sprintf and fread, that write potentially arbitrarily many characters to a buffer you supply, it is your responsibility to ensure, somehow, beforehand, that the buffer is big enough.
Some functions, such as fread, let you say how big your buffer is, so that they can be sure not to overflow it. Others, such as strcpy, sprintf, and scanf with directives like %s, do not. You must be especially careful with these functions.
When you write something like
char str[10];
sprintf(str, "%lld", 7564368987643389);
where you supply a buffer that is not big enough for the result, two questions tend to arise:
Why didn't it work?
Why did it work?
If it didn't work, the reason why should be obvious: the destination buffer simply wasn't big enough. And if despite that problem, it did seem to work, the reason is because C doesn't typically enforce (doesn't explicitly guard against) buffer overflow.
Suppose I buy some land -- a 1600 square foot plot -- in an undeveloped neighborhood. Suppose my title deed says:
The property line runs south for 40 feet from an iron stake, then 40 feet west, then 40 feet north, then 40 feet east.
So I've got 40 x 40 foot plot of land, but the only feature on the ground that positively identifies where my property is, is an iron stake at one corner. There isn't a crisp black line painted on the soil, or anything, precisely delineating the property lines.
Suppose I hire an architect and a builder, and we build a house on my new plot of land, and we screw up our measurements, and we build the house 10 feet into a neighboring parcel of land (that I don't own). What happens?
What does not happen is that the instant we dig that first footing or pour that first concrete or erect that first wall that crosses over the property line, a giant error message appears in the sky saying "PROPERTY LINE EXCEEDED".
No, this kind of error is not guaranteed to get detected right away. The problem might not be noticed (by a building inspector, or by the owner of the adjacent property) until tomorrow, or next week, or next year; and under some circumstances it might never get noticed at all.
And the situation is just about exactly the same with C memory allocation. If you write more to an array than it's allocated to hold, the problem might not reveal itself for a while, or it might not reveal itself at all: the program might seem to work perfectly, despite this reasonably dire error it contains.
For this reason, not only do you have to be careful with memory allocation in C, there are some good habits to get into. Not only is it important to declare you arrays (or malloc your buffers) big enough, but you also want to make sure that, whenever possible, the size is checked. For example:
When you call functions like fread, that accept a destination buffer and the size of that buffer, make sure the size you pass is accurate.
Instead of calling functions like sprintf that accept a destination buffer but with no way to specify its size, prefer alternative functions like snprintf that do allow the size to be specified and that therefore can guard against overflow.
If there's a function that doesn't allow the buffer size to be specified and for which there's no better alternative, maybe just don't use that function at all. Examples are strcpy and scanf with the %s and %[ directives.
When you write your own functions that accept pointers to buffers and that write characters or other data into those buffers, make sure you provide an argument by which the caller can explicitly supply the buffer size, and make sure your function honors this limit.
The program has undefined behavior because:
sprintf stores the characters 7564368987643389 plus a null terminator (a total of 17 bytes) in the destination array str defined with a length of only 10 bytes. sprintf does not receive the length of the array, hence writes the output to memory beyond the end of the array if it is too short. You should always use snprintf(str, sizeof str, "%lld", n); to avoid such undefined behavior.
printf("%c%c", str[11], str[12]); reads 2 bytes beyond the end of the str array, namely the 12th and the 13th bytes. This has undefined behavior, but if printf did successfully store the 17 bytes into the memory starting at the address of str, reading these bytes may yield the values '4' and '3', and produce an output of 43, which may or may not be visible as you did not end the program's output with a newline.
Writing and reading beyond the end of an array has undefined behavior, it may cause the program to crash or may seem to function as expected, but undesirable side effects can occur and go unnoticed for a while. On your system it seems nothing bad happened, but on some other system, it may cause tremendous damage... imagine if the program were running as part of a nuclear powerplant regulation system, you would not want to test the system's resilience this way.
I suggest creating some function you need.
Like this.
#include <stdio.h>
#include <stdlib.h>
char* LL_Int_To_Str(long long int A){
int Lenz=0,i;
int NegFlag=0;
if(A<0){
A=~A+1;
NegFlag=1;
}
long long int B=A;
do{
B/=10;
Lenz++;
}while(B);
char *Result=(char*)malloc(sizeof(char)*(Lenz+1+NegFlag));
Result[Lenz+NegFlag]='\0';
for(i=Lenz-1;i>-1-NegFlag;i--){
Result[i+NegFlag]=(A%10)+48;
A/=10;
}
if(NegFlag){
Result[0]='-';
}
return Result;
}
int main(){
int i;
long long int n=7564368987643389;
//long long int n=-7564368987643389;
char* StrX=LL_Int_To_Str(n);
/*char* Loop;//Debug
for(Loop=StrX;*Loop!='\0';Loop++){
printf("%c\n",*Loop);
}*/
printf("%s\n",StrX);
free(StrX);
return 0;
}
Then you can make sure nothing mistake.
Sometimes you think you can use some function save your time.
But most of time ,it's waste.
Another suggest
#include <limits.h>
printf("%lld\n",LLONG_MAX);
You can find max of long long int is 9223372036854775807
So max size of string requires is 19+1+1 (1 for '\0' 1 for '-')
Just use char str[21]; solve all problem
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.
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.
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.
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.