passcode

Mommy told me to make a passcode based login system.
My initial C code was compiled without any error!
Well, there was some compiler warning, but who cares about that?

ssh passcode@pwnable.kr -p2222 (pw:guest)

What is given?

We get a binary passcode, and the source it is compiled from passcode.c. There is a file called flag in the same directory, but we can't read it (the passcode binary can!).

Here the full source from the passcode.c file:

#include <stdio.h>
#include <stdlib.h>

void login(){
    int passcode1;
    int passcode2;

    printf("enter passcode1 : ");
    scanf("%d", passcode1);
    fflush(stdin);

    // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
    printf("enter passcode2 : ");
        scanf("%d", passcode2);

    printf("checking...\n");
    if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
    } else{
        printf("Login Failed!\n");
        exit(0);
    }
}

void welcome(){
    char name[100];
    printf("enter you name : ");
    scanf("%100s", name);
    printf("Welcome %s!\n", name);
}

int main(){
    printf("Toddler's Secure Login System 1.0 beta.\n");

    welcome();
    login();

    // something after login...
    printf("Now I can safely trust you that you have credential :)\n");
    return 0;
}

Understanding the source

I won't go over every line of this, but will describe this on a more high level:

We've got three functions: the main function doesn't do much except for calling the welcome and login function, so let's look at them:

The welcome function

...is fairly short:

void welcome(){
    char name[100];
    printf("enter you name : ");
    scanf("%100s", name);
    printf("Welcome %s!\n", name);
}

It defines a 100 bytes big char buffer, takes some input from stdin and writes it into the buffer and prints the content of the buffer (until the nullbyte defining the end of the string).

Now the rollercoaster of emotions: scanf itself does not check if the buffer it writes into can handle all the input, so with the right format string, we could overflow the buffer. The problem: the provided format %100s string works as a filter for our input making it impossible to overflow the buffer.

The login function

...is a bit longer:

void login(){
    int passcode1;
    int passcode2;

    printf("enter passcode1 : ");
    scanf("%d", passcode1);
    fflush(stdin);

    // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
    printf("enter passcode2 : ");
        scanf("%d", passcode2);

    printf("checking...\n");
    if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
    } else{
        printf("Login Failed!\n");
        exit(0);
    }
}

Let's go over the contents of the function to understand what is going on here:

void login(){

The function is called login, doesn't take any arguments and doesn't return anything, nothing special here.

    int passcode1;
    int passcode2;

Two local variables are defined, used later on.

    printf("enter passcode1 : ");
    scanf("%d", passcode1);
    fflush(stdin);

    // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
    printf("enter passcode2 : ");
    scanf("%d", passcode2);

We read two passcode values, using scanf which again is vulnerable, as there are no bound checks.

    printf("checking...\n");
    if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
    } else{
        printf("Login Failed!\n");
        exit(0);
    }
}

Exploiting