1

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.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
ernieg92
  • 11
  • 1
  • I've added some more notes in my answer to address what I believe is the actual intent of the assignment. Hope that helps. – Aenimated1 Apr 11 '16 at 12:55

3 Answers3

0

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.

Aenimated1
  • 1,594
  • 1
  • 9
  • 10
  • It's my choice what to do with the overflow. The assignment is supposed to simulate something useful (ATM was example) and overflow yield something unintended (free money). I chose to simulate privileged access, but accessing another site may work as well. This is supposed to run in a 32-bit Kali Linux environment. I can't get it to crash there (only on Ubuntu) so I suspect there are some extra stack protections (canary, etc.) in place on Kali. I think it's a terrible assignment as well. – ernieg92 Apr 12 '16 at 00:40
  • Is my buffer statement wrong? My desire was to enter an account number too long which would overwrite an area that can be accessed with custom code. But I think either the OS is protecting itself well or I'm misunderstanding how the buffer flows. – ernieg92 Apr 12 '16 at 00:46
  • There's nothing wrong with the code you posted per se. But it's not enough to just smash the stack with an overrun of arbitrary data. You'll need to really know the contents of the stack so you know what you're overwriting. In particular, if you want to leverage the vulnerability to launch other code, you need to know exactly where the return address is stored on the stack frame, and you need to carefully construct an "account number" that overwrites the return address. – Aenimated1 Apr 12 '16 at 01:13
0

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");
}
eoD .J
  • 302
  • 2
  • 5
  • I compiled this (w/32-bit switch) and it produced a segmentation fault after printing 'hello world!' -- is that the expected outcome? If so, then I need to have some mathematical calculation that exceeds the buffer, I think. – ernieg92 Apr 12 '16 at 01:07
  • Yes, that's what I meant by, "will then promptly crash". – eoD .J Apr 12 '16 at 02:28
0

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");
}
eoD .J
  • 302
  • 2
  • 5
  • So this one did not crash, but it only printed "main" (I'm executing on Linux and have to replace "stadafx.h" with "stdio.h" so that could be why). Neither of your examples required input, but I think I'm seeing how it works. I need to have some variable repeat enough times to push the stack down. – ernieg92 Apr 12 '16 at 03:54