What is the vulnerability in this C code? - c

I'm trying to understand buffer overflow attacks better, this is one of the exercises that came up, that has a buffer overflow vulnerability. I would like to know how one can exploit the vulnerability in this code.
I wasn't sure how to search for it.
int
main(int argc, char **argv)
{
(void) foo(argv[1]);
exit(0);
}
int
foo(char *arg)
{
return bar(arg);
}
int
bar(char *arg)
{
char lbuf[1024];
if (strlen(arg) >= 1024)
return -1;
memset(lbuf, 0, sizeof(lbuf));
sprintf(lbuf, "%s", "Welcome: ");
read(0, lbuf + strlen(lbuf), sizeof(lbuf) - strlen(lbuf) - 1);
printf(lbuf);
fflush(stdout);
return 0;
}

There is no buffer-overflow there, at all. But that doesn't mean it's secure.
The problem you are expected to find is this line:
printf(lbuf);
Whenever you provide a format-string, make sure it is safely under your control and only asks for those arguments you provided. Accessing arguments not provided, or of the wrong type, results in undefined behavior (all kinds of bizarre and potentially dangerous things can happen). Additionally, one can use %n to poke some memory, which is more obviously dangerous.
In this case, lbuf contains Welcome: followed by arbitrary insecure user-input.
In addition, the program unconditionally reads argv[1] (assumption argc > 0), and further assumes it points to a string (assumption argc > 1) when passing it to strlen().

Your code is just an UB without any possible hacks (if we consider only the buffer overflow and will analyze any other possible ones).
Buffer overflow to be used a attacking technique must overwrite some data used later in the program. It may be changing the variables, or placing some code (less common but possible)
an example:
#include <stdio.h>
#include <string.h>
int CheckPassword(void)
{
char passwd[5];
int passwordcorect = 0;
printf("Enter password:");
gets(passwd);
if(!strcmp(passwd, "1234"))
{
passwordcorect = 1;
}
return passwordcorect;
}
int main()
{
if(CheckPassword())
{
printf("\nSpecial priviledges granted!!\n");
}
else
{
printf("\nWrong!!\n");
}
return 0;
}
Compiled with mingw.
And the result:
Why did it happen? Because the buffer has overwritten the passwordcorrect variable. It is system, implementation etc related but hacking is not something abstract or portable :)

Related

I have written this ceaser cipher program in c,but everytime i run it it crashes

I have written this caesar cipher program in c language,it runs fine until I provide the integer value for key but after that it crashes.
can anyone please correct this code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char alphabets[] = "abcdefghijklmnopqrstuvwxyz";
int arrow,key;
int search(char x)
{
for(arrow=0;arrow<strlen(alphabets);arrow++)
{
if(x==alphabets[arrow])
{
return arrow;
}
}
}
char cipherGenerator(int arrow)
{
arrow=arrow+key;
if(arrow>strlen(alphabets))
{
arrow = (arrow%strlen(alphabets))-1;
}
return alphabets[arrow];
}
int main()
{
char plain_text[]="",cipher_text[]="";
int i;
printf("Enter the plain text\n");
gets(plain_text);
printf("Enter the key\n");
scanf("%d",&key);
for(i=0;i<strlen(plain_text);i++)
{
strcat(cipher_text,cipherGenerator(search(plain_text[i])));
}
printf("The cipher text is %s:-",cipher_text);
return 0;
}
The crash can be explained by the attempt of writing into arrays of length 1.
char plain_text[]="",cipher_text[]=""; //these arrays have length 1
gets(plain_text); //will fail and crash here
strcat(cipher_text,cipherGenerator(search(plain_text[i]))); //will crash here
Regarding the usage of gets:
The gets() function does not perform bounds checking, therefore this function is extremely vulnerable to buffer-overflow attacks. It cannot be used safely (unless the program runs in an environment which restricts what can appear on stdin). For this reason, the function has been deprecated in the third corrigendum to the C99 standard and removed altogether in the C11 standard. fgets() and gets_s() are the recommended replacements.
Never use gets().

Retrieve information using stack buffer overflow (C)

I found one interesting exercises on the net, it states that the specific input can overflow the buffer in such a way that the 'secret' will be printed to stdout.
I tried to figure it out by my self but I haven't done well.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_name(char *name, char *pr) {
char local[20];
printf("%s:",pr);
gets(local);// BUG
strncat(name,local,20);
}
int foo () {
char name[28]="Hello..";
char secret[12]="TOP SECRET";
char buf[24];
char n1[]="Enter your name";
char n2[]="Enter Secret code";
get_name(name,n1);
memset(buf, 0, sizeof(buf));
// Lets ONLY use strncpy for better control!!!
strncpy(buf, name, sizeof(buf));//BUG
printf("%s\n", buf);
memset(name,0,sizeof(name));
get_name(name, n2);
if (strncmp(secret,name,10)==0)
printf("Welcome and %s\n",buf);
else {printf("Wrong code, better try again..\n");}
return 0;
}
int main(int argc, char **argv)
{
foo();
printf("Bye\n");
return 0;
}
There is no way to know what the outcome of such buffer overflows will do. You can't know or assume what memory they will overwrite. Most likely they will only cause some sort of run-time crash. Any exploit would have to have a very specific system in mind. Which means that nobody would be able to answer your question without knowing the details of a given system.
What your "random internet person" is aiming for, is likely to overwrite the null termination of Hello.. with some garbage, so that the "TOP SECRET" string will get printed along with it. You can't assume that those two strings are allocated adjacently, however. You could try to type 28 letter long input to gets and see what happens... there are no guarantees of any given behavior. On my computer it does nothing exciting apart from printing some garbage. Reverse-engineering of my binary reveals that that's because the arrays are indeed not allocated adjacently.
In addition, your comments about strncpy are misguided, strncpy is dangerous and should be avoided, see this.

How to put a char into a empty pointer of a string in pure C

I want to store a single char into a char array pointer and that action is in a while loop, adding in a new char every time. I strictly want to be into a variable and not printed because I am going to compare the text. Here's my code:
#include <stdio.h>
#include <string.h>
int main()
{
char c;
char *string;
while((c=getchar())!= EOF) //gets the next char in stdin and checks if stdin is not EOF.
{
char temp[2]; // I was trying to convert c, a char to temp, a const char so that I can use strcat to concernate them to string but printf returns nothing.
temp[0]=c; //assigns temp
temp[1]='\0'; //null end point
strcat(string,temp); //concernates the strings
}
printf(string); //prints out the string.
return 0;
}
I am using GCC on Debain (POSIX/UNIX operating system) and want to have windows compatability.
EDIT:
I notice some communication errors with what I actually intend to do so I will explain: I want to create a system where I can input a unlimited amount of characters and have the that input be store in a variable and read back from a variable to me, and to get around using realloc and malloc I made it so it would get the next available char until EOF. Keep in mind that I am a beginner to C (though most of you have probably guess it first) and haven't had a lot of experience memory management.
If you want unlimited amount of character input, you'll need to actively manage the size of your buffer. Which is not as hard as it sounds.
first use malloc to allocate, say, 1000 bytes.
read until this runs out.
use realloc to allocate 2000
read until this runs out.
like this:
int main(){
int buf_size=1000;
char* buf=malloc(buf_size);
char c;
int n=0;
while((c=getchar())!= EOF)
buf[n++] = c;
if(n=>buf_size-1)
{
buf_size+=1000;
buf=realloc(buf, buf_size);
}
}
buf[n] = '\0'; //add trailing 0 at the end, to make it a proper string
//do stuff with buf;
free(buf);
return 0;
}
You won't get around using malloc-oids if you want unlimited input.
You have undefined behavior.
You never set string to point anywhere, so you can't dereference that pointer.
You need something like:
char buf[1024] = "", *string = buf;
that initializes string to point to valid memory where you can write, and also sets that memory to an empty string so you can use strcat().
Note that looping strcat() like this is very inefficient, since it needs to find the end of the destination string on each call. It's better to just use pointers.
char *string;
You've declared an uninitialised variable with this statement. With some compilers, in debug this may be initialised to 0. In other compilers and a release build, you have no idea what this is pointing to in memory. You may find that when you build and run in release, your program will crash, but appears to be ok in debug. The actual behaviour is undefined.
You need to either create a variable on the stack by doing something like this
char string[100]; // assuming you're not going to receive more than 99 characters (100 including the NULL terminator)
Or, on the heap: -
char string* = (char*)malloc(100);
In which case you'll need to free the character array when you're finished with it.
Assuming you don't know how many characters the user will type, I suggest you keep track in your loop, to ensure you don't try to concatenate beyond the memory you've allocated.
Alternatively, you could limit the number of characters that a user may enter.
const int MAX_CHARS = 100;
char string[MAX_CHARS + 1]; // +1 for Null terminator
int numChars = 0;
while(numChars < MAX_CHARS) && (c=getchar())!= EOF)
{
...
++numChars;
}
As I wrote in comments, you cannot avoid malloc() / calloc() and probably realloc() for a problem such as you have described, where your program does not know until run time how much memory it will need, and must not have any predetermined limit. In addition to the memory management issues on which most of the discussion and answers have focused, however, your code has some additional issues, including:
getchar() returns type int, and to correctly handle all possible inputs you must not convert that int to char before testing against EOF. In fact, for maximum portability you need to take considerable care in converting to char, for if default char is signed, or if its representation has certain other allowed (but rare) properties, then the value returned by getchar() may exceed its maximum value, in which case direct conversion exhibits undefined behavior. (In truth, though, this issue is often ignored, usually to no ill effect in practice.)
Never pass a user-provided string to printf() as the format string. It will not do what you want for some inputs, and it can be exploited as a security vulnerability. If you want to just print a string verbatim then fputs(string, stdout) is a better choice, but you can also safely do printf("%s", string).
Here's a way to approach your problem that addresses all of these issues:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define INITIAL_BUFFER_SIZE 1024
int main()
{
char *string = malloc(INITIAL_BUFFER_SIZE);
size_t cap = INITIAL_BUFFER_SIZE;
size_t next = 0;
int c;
if (!string) {
// allocation error
return 1;
}
while ((c = getchar()) != EOF) {
if (next + 1 >= cap) {
/* insufficient space for another character plus a terminator */
cap *= 2;
string = realloc(string, cap);
if (!string) {
/* memory reallocation failure */
/* memory was leaked, but it's ok because we're about to exit */
return 1;
}
}
#if (CHAR_MAX != UCHAR_MAX)
/* char is signed; ensure defined behavior for the upcoming conversion */
if (c > CHAR_MAX) {
c -= UCHAR_MAX;
#if ((CHAR_MAX != (UCHAR_MAX >> 1)) || (CHAR_MAX == (-1 * CHAR_MIN)))
/* char's representation has more padding bits than unsigned
char's, or it is represented as sign/magnitude or ones' complement */
if (c < CHAR_MIN) {
/* not representable as a char */
return 1;
}
#endif
}
#endif
string[next++] = (char) c;
}
string[next] = '\0';
fputs(string, stdout);
return 0;
}

How can I get a buffer overflow in a global variable?

I'm working on detecting and preventing BOF attacks and I'd like to know, how can I overflow a global struct?
My code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct{
char name[20];
char description[10];
} test;
int main(int argc, char **argv){
if(argc != 2)
exit(-1);
*(*(argv+1)+20) = '\x00'; //terminate string after 20 characters
strcpy(test.name, argv[1]); //no BOF here... stopped at 20
printf("%s\n", test.name);
char *desc;
desc = malloc(10);
if(!desc){
printf("Error allocating memory\n");
exit(-1);
}
scanf("%s", desc); //no bounds checking - this is where I BOF
strcpy(test.description, desc); //copy over 10 characters into 10 char buffer
printf("%s\n", test.description); //this prints out whatever I type in
//even thousands of characters, despite it having a buffer of 10 chars
}
You overflow a global buffer the same way you do any other buffer type; you store more data in it than there are bytes allocated for it. Perhaps the question is "and what damage does that do?", and the answer is the usual: it depends.
Basically, when you overflow a specific global buffer, you write over some other global variables, and what happens next depends on whether the other variable is referenced again, and what it is supposed to hold. It won't, typically, have function return addresses and the like, so it can be more difficult to exploit.
char *desc = malloc(10);
scanf("%s", desc); //no bounds checking - this is where I BOF
strcpy(test.description, desc); //copy over 10 characters into 10 char buffer
One of the things you will need to address during testing on modern Linux systems are the calls to scanf and strcpy. Modern systems use FORTIFY_SOURCE, and it tries to remediate some classes of buffer overflows.
FORTIFY_SOURCE uses "safer" variants of high risk functions like memcpy and strcpy. The compiler uses the safer variants when it can deduce the destination buffer size. If the copy would exceed the destination buffer size, then the program calls abort().
To disable FORTIFY_SOURCE for your testing, you should compile the program with -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.

Malloc and scanf

I'm fairly competent in a few scripting languages, but I'm finally forcing myself to learn raw C. I'm just playing around with some basic stuff (I/O right now). How can I allocate heap memory, store a string in the allocated memory, and then spit it back out out? This is what I have right now, how can I make it work correctly?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = (char*)malloc(10);
scanf("Enter a string",&toParseStr);
printf("%s",toParseStr);
return 0;
}
Currently I'm getting weird output like '8'\'.
char *toParseStr = (char*)malloc(10);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s",toParseStr);
free(toParseStr);
Firstly, the string in scanf is specifies the input it's going to receive. In order to display a string before accepting keyboard input, use printf as shown.
Secondly, you don't need to dereference toParseStr since it's pointing to a character array of size 10 as you allocated with malloc. If you were using a function which would point it to another memory location, then &toParseStr is required.
For example, suppose you wanted to write a function to allocate memory. Then you'd need &toParseStr since you're changing the contents of the pointer variable (which is an address in memory --- you can see for yourself by printing its contents).
void AllocateString(char ** ptr_string, const int n)
{
*ptr_string = (char*)malloc(sizeof(char) * n);
}
As you can see, it accepts char ** ptr_string which reads as a pointer which stores the memory location of a pointer which will store the memory address (after the malloc operation) of the first byte of an allocated block of n bytes (right now it has some garbage memory address since it is uninitialized).
int main(int argc, char *argv[])
{
char *toParseStr;
const int n = 10;
printf("Garbage: %p\n",toParseStr);
AllocateString(&toParseStr,n);
printf("Address of the first element of a contiguous array of %d bytes: %p\n",n,toParseStr);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
free(toParseStr);
return 0;
}
Thirdly, it is recommended to free memory you allocate. Even though this is your whole program, and this memory will be deallocated when the program quits, it's still good practice.
You need to give scanf a conversion format so it knows you want to read a string -- right now, you're just displaying whatever garbage happened to be in the memory you allocated. Rather than try to describe all the problems, here's some code that should at least be close to working:
char *toParseStr = malloc(10);
printf("Enter a string: ");
scanf("%9s", toParseStr);
printf("\n%s\n", toParsestr);
/* Edit, added: */
free(toParseStr);
return 0;
Edit: In this case, freeing the string doesn't make any real difference, but as others have pointed out, it is a good habit to cultivate nonetheless.
Using scanf() (or fscanf() on data you don't control) with a standard "%s" specifier is a near-certain way to get yourself into trouble with buffer overflows.
The classic example is that it I enter the string "This string is way more than 10 characters" into your program, chaos will ensue, cats and dogs will begin sleeping together and a naked singularity may well appear and consume the Earth (most people just state "undefined behaviour" but I think my description is better).
I actively discourage the use of functions that cannot provide protection. I would urge you (especially as a newcomer to C) to use fgets() to read your input since you can control buffer overflows with it a lot easier, and it's more suited to simple line input than scanf().
Once you have a line, you can then call sscanf() on it to your heart's content which, by the way, you don't need to do in this particular case since you're only getting a raw string anyway.
I would use:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSZ 10
int main(int argc, char *argv[]) {
char *toParseStr = malloc(BUFFSZ+2);
if (toParseStr == NULL) {
printf ("Could not allocate memory!\n");
return 1;
}
printf ("Enter a string: ");
if (fgets (toParseStr, BUFFSZ+2, stdin) == NULL) {
printf ("\nGot end of file!\n");
return 1;
}
printf("Your string was: %s",toParseStr);
if (toParseStr[strlen (toParseStr) - 1] != '\n') {
printf ("\nIn addition, your string was too long!\n");
}
free (toParseStr);
return 0;
}
You don't need an & before toParseStr in scanf as it is already a pointer
also call free(toParseStr) afterwards
First, the errors that was keeping your program from working: scanf(3) takes a format-string, just like printf(3), not a string to print for the user. Second, you were passing the address of the pointer toParseStr, rather than the pointer toParseStr.
I also removed the needless cast from your call to malloc(3).
An improvement that your program still needs is to use scanf(3)'s a option to allocate memory for you -- so that some joker putting ten characters into your string doesn't start stomping on unrelated memory. (Yes, C will let someone overwrite almost the entire address space with this program, as written. Giant security flaw. :)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = malloc(10);
printf("Enter a short string: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
return 0;
}

Resources