All writeups. Or maybe just CrackMe0x03?

This is a walkthrough for the CrackMe0x04 that was part of the Rensselaer Polytechnic Institute’s Binary Exploitation course in Spring 2015. You can follow along by downloading the challenges here. (mirror 1, mirror 2)

As usual let’s start by running the binary.

Damn they changed the password 🙁 But yeah, modified welcome message, but no other difference in terms of what we are used to.

Time for another gdb assembly dump.

Again, no more cmp – but we have another ‘suspicious’ function at <main+80>. Let’s disassemble it.

Now that is nasty – we have not one, but two cmp statements – one at <check+31> and another at <check+82>. Easiest way to figure out what’s what is to look at jump statements and write some pseudocode. Here is a rough guess of what I think is happening in this function. Remember that you can use radare2 to show you visually hardcoded strings.

function check() {
    start:
    //<check+26>,<check+31>
    if(strlen() comparison - if ebp-0xc >= eax){
        //Exits program by exiting check function via return statement
        //This is incorrect password
        return;
    } else {
        //<check+82>
        if(ebp-0x8 != 15){
            GOTO start:
        } else {
            //Correct password would come here!
            //<check+107>
            exit();
        }
    }
}

Notice that we have a call to strlen() – is our input being interpreted as an integer or string? It seems to be a string, but we could potentially be finding the length of hard coded strings in the program. Let’s confirm this by setting a breakpoint at the main() function when scanf is being called.

Perfect – it’s ‘%s’ which means it’s being read in as a string. Now time to check what the strlen comparison is doing. As usual, this means we make a breakpoint up until the instruction that we are checking, then print out the contents of any memory addresses that seem interesting.

Seems like the ‘eax’ register is holding the strlen() of our input at line 31. There also seems to be a number at ‘ebp-0xc’ that is an index of some sort and is being incremented, probably at <check+115>. With this information, we can update our guess of the code.

function check(char *input) {
    int someNumber = 0;
    start:
    //<check+26>,<check+31>
    if(someNumber > strlen(input)){
        //Exits program by exiting check function via return statement
        //This is incorrect password
        return;
    } else {
        //<check+82>
        if(ebp-0x8 != 15){
            //<check+115>
            someNumber++;
            GOTO start:
        } else {
            //Correct password would come here!
            //<check+107>
            exit();
        }
    }
}

Since we’ve figured out our first cmp instruction, let’s debug the next.

Huh that’s weird – seems like if we express ‘ebp-0x8’ as a byte, it just increments by 64 each time. Obviously that’s never going to equal 0xf (15). Now we could continue guessing or we could look at the assembly of <check> in depth.

   0x080484c9 <+69>:	call   0x80483a4 <sscanf@plt>
   0x080484ce <+74>:	mov    edx,DWORD PTR [ebp-0x4]
   0x080484d1 <+77>:	lea    eax,[ebp-0x8]
   0x080484d4 <+80>:	add    DWORD PTR [eax],edx
   0x080484d6 <+82>:	cmp    DWORD PTR [ebp-0x8],0xf

So at <check+74>, it is moving the value of ‘ebp-0x4’ to ‘edx’. At <check+77> we are changing the ‘eax’ to point at ‘ebp-0x8’. We then add ‘edx’ (which is equal to ‘ebp-0x4’) to ‘eax’ (pointing at ‘ebp-0x8’ at <check+80>. So let’s check ‘ebp-0x4’ – we should expect it to equal 64 with our same input of ‘abcde’.

As we expected.

Now we saw a call to the function ‘sscanf’ before – if you google ‘man sscanf’ you should find out that it dissects an existing string into further parts. So we are breaking down our input of ‘abcde’ into smaller parts but no matter what, it returns a value of 64?? Sounds like something wrong is happening as no matter how many times you add 64, you will never get 15… Might be something wrong with the input – let’s try some numbers.

We got it!!!! Seems like it’s scanning for a single digit, storing it in ‘ebp-0x4’, with the variable at ‘ebp-0x8’ storing the sum of all the digits. Do your own testing, but the password follows a rule of required numbers only – as long as the digit sum (left to right) is exactly 15 at some point, it is a correct password.

Well that was a major hassle – wasn’t it satisfying though? Let me know if you think of a more efficient method to solve this CrackMe 🙂

I hope you’ve brushed up on your bitwise operations as it’s time for CrackMe0x05.