I have a very rudimentary understanding of C (though I do understand programming concepts in general). I have an assignment to create a buffer overflow that yields something (like access to unauthorized area, free money, etc.) and not just crash the program.
I've tried different sized buffers and can always "crash" the program but I can't get it to launch any code (i.e., /bin/su). Am I approaching this incorrectly?
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <string.h>
#define BUFSIZE 20
int main() {
int month=12;
int day=31;
int year=2016;
int confirm = 0;
double dollars = 5.00;
char *sitenum="97871";
char acctnum[BUFSIZE];
printf("Welcome to the Acme AP-AR System. This is the Accounts Receivable module. \n");
/* Gathering date information */
printf("Please enter the month of transaction as an integer value (2 digits). \n");
printf("For example, July would be 07, December would be 12. Please input the month: ");
for (;;) { /* Start of month input validation loop */
scanf("%d", &month);
if(month>=1 && month<=12) {
printf("Validated. \n");
break;
}
else {
printf("Please enter a value between 1 and 12! \n");
continue;
}
} /* End of month input validation loop */
printf("\nPlease enter the day of transaction as an integer value (2 digits). \n");
printf("For example, the 3rd would be 03, the 25th would be 25. Please input the day: ");
for (;;) { /* Start of day input validation loop */
scanf("%d", &day);
if(day>=1 && day<=31) {
printf("Validated. \n");
break;
}
else {
printf("Please enter a value between 1 and 31! \n");
continue;
}
} /* End of day input validation loop */
/* Gathering sender account number */
printf("\nPlease enter the sender Account Number: ");
scanf("%s", acctnum);
/* Gathering transaction amount */
printf("\nPlease enter the USD amount (including cents) received: $ ");
scanf("%lf", &dollars);
/* Confirming data entry */
printf("\nTransaction information.\n Date: %d-%d-%d \n", month,day,year);
printf("Account: %s-%s \n", sitenum, acctnum);
printf(" Amount: $ %.2lf \n", dollars);
printf("\nProcess transaction information? (Yes=1/No=0) ");
for (;;) { /* Start of confirmation validation loop */
scanf("%d", &confirm);
if(confirm==1) {
printf("Transaction processed. \n");
break;
}
else {
printf("Transaction voided! \n");
break;
}
} /* End of confirmation validation loop */
return (EXIT_SUCCESS);
}
When executing, if you enter 25 characters for the day of month, the program will continue until the end. Only after the last input does it terminate with the stack smashing error. I'm afraid I'm trying to do something that can't be done, but a day (literally, the past 8 hours) of Google searches hasn't yielded an example that I've been able to use.
Can someone push me in a different direction that will get me close to what I'm trying to achieve? Thanks.
You will need an in-depth understanding of the target architecture (x86, x86-64, etc.) to accomplish that. A typical approach would involve carefully constructing the contents of the buffer overflow so that it 1) contains the code you wish to run when the input data is reinterpreted as machine instructions, and 2) overwrites the return address of the stack frame so that it jumps into your code instead of returning to the calling function.
I don't feel comfortable providing code that actually does this, but it's certainly possible to do.
EDIT: By the way, I don't think the assignment was intended to require actually running arbitrary code. I'm guessing based on the code you posted that you're supposed to just overwrite part of the stack so that it looks like you're accessing a different "sitenum". That's definitely possible since the sitenum pointer is going to be stored after acctnum in the stack (at least typically). So if you craft your buffer overrun carefully, you can change the sitenum pointer to point somewhere else. For example, (assuming the sitenum pointer is immediately after acctnum in the stack), you could input 1 extra character into the acctnum, and the null terminating character will overwrite the least significant byte of the sitenum pointer, which most likely will point to a different location then.
In my view, it's a terrible assignment though, because 1) the stack can be arranged differently based on a large number of factors, and 2) most modern development environments will default to adding runtime checks to prevent this kind of stack corruption. For example, in MS Visual C++, you would have to go out of your way to disable the Basic Runtime Checks and Buffer Security Check features to avoid an exception.
Anyway, hope that helps.
Here's a simple example of overwriting the return address on the stack to execute another function(will then promptly crash). Works in Windows VS2015 on x86.
#include "stdafx.h"
void hello()
{
printf("hello world!\n");
}
void run(int a)
{
int * ret = &a;
--ret; // stack grows downward on x86
*ret = (int)hello;
}
int main()
{
int a = 42;
run(a);
printf("this won't print\n");
}
Here's another simple example(VS2015/x86) that saves the return address first, and then after hello() is executed, will put the return address to main() back on the stack. Notice it starts first with a local variable declared in run() and not one passed in as an argument. It comes down to understanding what order the return address, arguments passed, the direction the stack goes, and where the current stack frame starts. You'll probably get notification of failing a run time check in your debugger environment after execution, but you should see this printed to the console:
hello world
main
#include "stdafx.h"
int saveret;
void hello()
{
int a = 43;
printf("hello world!\n");
// put saved return address to main() back on stack
int * ret = &a;
ret += 4;
*ret = saveret;
}
void run()
{
int a = 42;
int * ret = &a;
ret += 4; // stack grows downward on x86
saveret = (int)*ret;
*ret = (int)hello;
}
int main()
{
run();
printf("main\n");
}
Related
Hello i have been struggling with my code for a while and finally found that the free() funtion is the cause. I think i am missing something about the details of how free() works.
My output is :
test test test test test
ID: 200
RELEASE YEAR: 2006
ID: 201
RELEASE YEAR: 2006
ID: 202
RELEASE YEAR: 2006
ID: 203
RELEASE YEAR: 2006
ID: 204
RELEASE YEAR: 2006
AB
Edit : Added the full code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1000 //Do not edit this macro.
typedef struct{
int film_id;
char title[255];
char description[1023];
unsigned int release_year;
char rental_duration;
float rental_rate;
unsigned char length;
float replacement_cost;
char rating[10];
char last_update[30];
} RECORD_t, *RECORD; //Do not edit this struct.
RECORD *find_by_year(int release_year, RECORD film_array, int start, int end,int *found);
int main(){
RECORD rec = (RECORD)malloc(sizeof(RECORD_t)*MAX); //Do not edit this line.
FILE *file = fopen("data.txt", "rb"); //Do not edit this line.
if (file == NULL) { //Do not edit this line.
printf("Cannot open the file.\n"); //Do not edit this line.
exit(0); //Do not edit this line.
} //Do not edit this line.
fread(rec, sizeof(RECORD_t)*MAX, 1, file); //Do not edit this line.
fclose(file); //Do not edit this line.
int i,test;
RECORD *rec_arr;
rec_arr=find_by_year(2006,rec,200,203,&test);
for(i=0;i<test;i++){
printf("ID: %d\n", rec_arr[i]->film_id);
printf("RELEASE YEAR: %d\n", rec_arr[i]->release_year);
printf("\n\n");
fflush(stdout);
}
printf("A");
fflush(stdout);
// file = fopen("data.txt", "wb"); //Do not edit this line.
// fwrite(rec, sizeof(RECORD_t)*MAX, 1, file); //Do not edit this line.
// fclose(file); //Do not edit this line.
free(rec); //Do not edit this line.
printf("B");
fflush(stdout);
free(rec_arr);
printf("C");
fflush(stdout);
return 1; //Do not edit this line.
}
RECORD *find_by_year(int release_year, RECORD film_array, int start, int end,int *found) {
RECORD *rec_arr=malloc(sizeof(RECORD)*1);
RECORD *narray;//for realloc check
int size=1,i,j;
start--;
if(rec_arr==NULL){//if malloc fails
printf("MALLOC FAILED find_by_year returning NULL\n");
fflush(stdout);
return NULL;
}
for(i=start;i<=end;i++){
if(film_array[i].release_year==release_year){
rec_arr[size-1]=&film_array[i];
size++;
narray=realloc(rec_arr,size);//increment the size by 1
//ERROR HANDLING
if(narray==NULL){//if realloc fails
printf("INNER REALLOC FAILED find_by_year");
fflush(stdout);
narray =malloc(sizeof(RECORD) * size);
if(narray==NULL){ //if malloc fails
printf("INNER MALLOC ALSO FAILED find_by_year returning NULL\n");
fflush(stdout);
return NULL;
}
for(j=1;j<size;j++){//copy
narray[size-1]=rec_arr[size-1];
free(rec_arr);
}
}
printf("test ");
fflush(stdout);
rec_arr=narray;
}
}
printf("\n");
fflush(stdout);
*found=size-1;
if(size==1)//if not found anything
return NULL;
return rec_arr;
}
From the results of debugging free(rec_arr) fails everytime what could be the problem here. I cropped the code and i am almost sure that the cropped parts are working from the debugging.
The main thing wrong with your code is the approach. Repeatedly incrementing the size of an array by one using realloc() is horrifically inefficient. Instead, just do one pass over the data to check how many records match, then allocate the entire storage at once and do a second pass to populate it. Or, allocate an array as large as all the records, populate just the part you need, and don't worry about the "wasted" memory because it probably doesn't matter.
Either of the above approaches will result in much simpler code with fewer bugs.
This line is incorrect:
narray=realloc(rec_arr,size);//increment the size by 1
The second argument to realloc should be the number of bytes, not the number of records. You should multiply size by sizeof(RECORD) .
Here's some general recommendations about the rest of the code:
I suggest just aborting in the if(narray=NULL) case. That code will almost never happen anyway , and probably will fail anyway even if it does enter. Recovering from out-of-memory is an advanced topic (especially taking into account that modern operating systems overcommit).
You mentioned using Eclipse+CDT -- you should be able to step through the code in the debugger instead of having to use printf debugging statements.
It would be good to check for rec being NULL on the first line of main, and also check the return value of find_by_year -- if it returns NULL then you don't want to go on to do the i loop. Your function does not set *found in the case of returning NULL, sometimes, so the caller has to do the null check before using the record count.
I don't really agree with the other suggestion to change the realloc strategy. Keeping the code simple to read is not a bad plan , either for beginners or experts. And I doubt it is really inefficient as modern operating systems have a minimum allocation size so the realloc calls will basically be doing nothing unless your search returns more than say 1000 records.
I've created a program that let's you change the password from a file if you enter the previous password that was in that file.What I want to do is to be able to create a username that's gets assigned with a password.The username and the password should be written in the file without deleting anything that was there before.The program should also be able to validate the password for the username in the file.Here is my current code,but i can't manage to write multiple things in the given file.I don't want you to give me the code for my question, only the algorythm with some tips.Thank you!
#include<stdio.h>
#include <conio.h>
#include <fstream>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *passwords;
int p='*',i,j,count,triesLeft,a,numberofTries=0;
char password[5] = {0,0,0,0,0};
char passwordCheck[5] = {0,0,0,0,0};
passwords = fopen("passwords.txt","r");
printf("You have 3 tries to enter your password!\n");
for(count=0;count<3;count++)
{
numberofTries++;
triesLeft = 3 - count;
printf("You have %d tries left!\n", triesLeft);
printf("Enter your password: ");
scanf("%s", &passwordCheck);
fscanf(passwords,"%s",&password);
if(strcmp(password, passwordCheck) == 0)
{
numberofTries--;
printf("Press 0 if you want to set up a new password, press 1 to stop the program\n");
scanf("%d", &a);
if(a==0)
{
passwords = fopen("passwords.txt","w");
printf("New password:");
for(i=0;i<5;i++)
{
password[i] = getch();
putchar(p);
}
for(j=0;j<5;j++)
{
fprintf(passwords,"%c",password[j]);
}
}
else if(a==1)
{
printf("Old password still in place");
}
break;
}
else
{
printf("Wrong password!");
}
}
if(numberofTries == 3)
{
printf("You are out tries!");
}
fclose(passwords);
}
Have a look at the fopen documentation. The magic phrase here is "access mode". As you open the file, the FILE pointer points to a certain position inside of the file. By setting the appropriate access mode, you can choose where the position pointer will be placed when the file is opened. Maybe the function fseek is interesting for you, too. It allows you to move that pointer.
A few more tips for your code:
Make sure that you don't use to many unneccessary variables, since
they make your code confusing.
When you use fopen, always check wether the pointer is set correctly
(check for NULL), otherwise your program may crash with a
segmentation fault if it is unable to find or access the file.
In C everything that differs from 0 or NULL is true. That applies for
pointers as for numeric values. Feel free to use the negation
operator "!" in combination with such tests.
Easy access program
Using linux first of all. I am trying to make a program that will first sign up a user in case he ain't got an account after that he will be directed to a login screen where he will enter his account details and then will be logged in. After that he will be given options to provide easy access to websites e.t.c. Like if the user enters 1 he will be directed to f.b, 2 for quora and so on. I successfully managed to code the program to the log in phase but i did it in a single function i.e main(), so i thought it would be nice if i had separate functions for performing specific tasks. I have coded it this time in separate functions, but i am getting segmentation error this time when i try to open FILE using fopen(). And also please tell me some way to open a website in a browser using console command. Like we have in windows (start www.facebook.com e.g). Here's the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct user_data {
char name[50];
unsigned long password;
};
struct user_data new_user; // Will hold the data of new
struct user_data data_ver; // Will hold the data read
void sign_up(void);
void sign_in(void);
int main(void) {
beginning: // Beginning label in case of invalid input
printf("\t\t\t\t WELCOME TO EASY ACCESS APPLICATION");
printf("\n\n\nIf you have an account press 1.\n\nPress 2 for sign up.");
char user_choice; // Wil hold the
// user_choice i.e whether he wants to sign up / sign in
user_choice = getchar();
if (user_choice == '1') {
sign_in(); // In case of 1 goto sign in page
}
else if (user_choice == '2') {
sign_up(); // Opening file);
// In case of 2 goto sign up page
}
else {
printf("Invalid input. Try again.\n\n");
puts("Press any key to continue...");
getchar();
system("clear");
goto beginning;
}
return 0;
}
void sign_up(void) {
FILE *data = fopen("data.txt", "a");
if (data == NULL) {
printf("Unable to open file.");
scanf("%c");
system("clear");
}
system("clear");
printf("\t\t----------------------------\n"
"\t\t| |\n"
"\t\t| SIGN UP PAGE |\n"
"\t\t| |\n"
"\t\t----------------------------");
printf("\n\nName:");
scanf("%c"); // Dummy scanf
gets(new_user.name); // Getting name into the struct
printf("\nPassword.");
scanf("%lu", &new_user.password); // Getting pass into the struct
fprintf(data, "%s %lu\n", new_user.name, new_user.password); //Feeding data into FILE
system("clear");
printf("\n\nSign up complete. :) ");
printf("\n\nYou will now be directed to the sign in page. ");
printf("\nPress any key to contine...");
scanf("%c");
system("clear");
fclose(data);
}
void sign_in(void) {
}
I am getting the error on the first line of sign_up function where i am opening FILE.
scanf("%c") expects a pointer where the read character will be stored. scanf() doesn't know if you provided the pointer, it just read the destination address from the expected stack location. Effectively scanf() takes a random address and writes the character there.
Use getchar(); or char Dummy; scanf("%c",&Dummy);.
My program is supposed to exit when the user types in exit similar to how its done in a shell. First I checked online to see if syscall could be called in a loop, but then I noticed the indices of the characters in the array are wrong. Why are these changing; when I ran the program and typed in exit I had my program shoot out the 3rd index for testing purposes and it returned 'e'. So I thought it might've been flipped and flipped all values and my exit still did not work. Any thoughts on what the underlying issue may be?
#include <stdio.h>
//Abstract: This program runs a script to emulate shell behavior
#define MAX_BIN_SIZE 100
int main() { //Memory allocation
char * entry[MAX_BIN_SIZE];
while(1)
{
printf("msh>");
fgets(entry,MAX_BIN_SIZE,stdin); //Getting user input
if(entry[0]=='t' && entry[1]=='i' && entry[2]=='x' && entry[3]=='e')
{
//printf("Exiting");
exit(0); //exit(system call)
break;
printf("Inside of exit");
}
printf("msh> you typed %s %c %c %c %c",entry,entry[3],entry[2],entry[1],entry[0]); //returning user input
}
return 0;
}
I am sorry I don't have enough reputation points to add a comment, but #lundman is correct. I don't think you need to create a pointer to entry. Also, you are checking for "exit" in the reverse order. I tried and edited the code; this seems to work:
#include <stdio.h>
//Abstract: This program runs a script to emulate shell behavior
#define MAX_BIN_SIZE 100
int main()
{ //Memory allocation
char entry[MAX_BIN_SIZE];
while(1)
{
printf("msh>");
fgets(entry,MAX_BIN_SIZE,stdin); //Getting user input
if(entry[0]=='e' && entry[1]=='x' && entry[2]=='i' && entry[3]=='t')
{
printf("Inside of exit");//printf("Exiting");
exit(0); //exit(system call)
}
printf("msh> you typed %s %c %c %c %c\n",entry,entry[3],entry[2],entry[1],entry[0]); //returning user input
}
return 0;
}
int main()
{
int t, i;
int *nums;
scanf("%d", &t);
nums = malloc(t * sizeof(int));
for(i = 0; i < t; i++)
{
scanf("%d", &nums[i]);
}
printf("hey");
}
For some reason, it hangs, waiting for more input! Any ideas?
This code is correct, except for the fact that you're not freeing your memory (not a big issue for this simple code) and you're not checking scanf for errors, which may be the cause of your problem.
A better implementation with error checking and correct memory handling is described below:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int t, i, ret;
int *nums;
ret = scanf("%d", &t);
if(ret != 1)
{
/* something wrong */
}
nums = malloc(t * sizeof(int));
if(nums==NULL)
{
/* memory error */
}
for(i = 0; i < t; i++)
{
ret = scanf("%d", &nums[i]);
if(ret != 1)
{
/* something wrong */
}
}
free(nums);
printf("hey");
return 0;
}
Just a guess here...
But I'm guessing you ran it and entered :
4
1234
For example, you put in 4 and then 1234 and it hangs. Well, that would be because 1234 is the first number and not 4 distinct numbers so its waiting for the second number. You have to press enter or some such delimiter between each number.
Try this set of inputs instead:
4
1234
29
4
5
You should get :
hey
Pro grammatically, you should be checking return values from your function calls. Make sure malloc didn't return zero. Make sure scanf returns the number of inputs you expected to read. Add in printouts to make sure the values it read in are what you expected/wanted to read in.
EDIT :
Guessing you have a typo in the program which isn't displayed here. such as :
scanf("%s", &t);
Or you are getting the 'hey' and just not seeing it.
[ov#MARVIN sotest]$ ./a.out
5 5 4 3 23 1
hey[ov#MARVIN sotest]$
See the 'hey' is sort of hidden in my prompt because you are missing the '\n' new line in the printout?
Remember to flush when you are done.
In chat, OP's comments "No... BTW, if I add a printf in the loop that prints the current input, it prints everything except from the last one...". This hinted that the issue was on the final output.
The following sends data out to be printed. But stdout is typically buffered. Actual output may not occur until sometime later. Output is flushed when 1) output contains an end-of-line '\n', 2) fflush() is called 3) the program ends. I am surprised output did not appear when the program ended, but possibly OP's true code differs from the post.
printf("hey");
Change to
printf("hey\n");
Or #Cool Guy
printf("hey");
fflush(stdout);
BTW: This is also hinted in #Diversity answer.
Note: Always a good idea to check the result of scanf()
// scanf("%d", &t)
if (1 != scanf("%d", &t)) Handle_BadInput_or_EOF();