1

I want to solve this very basic crackme using angr:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    char buffer[64];
    printf("Mot de passe:\n");
    scanf("%64s",buffer);
    if (strcmp(buffer,"super!")==0)
    {
        printf("Bravo!\n");
    }
    else
    {
        printf("Perdu1!\n");
    }
    return 0;
}

It works fine with this python script:

import angr
from angr.state_plugins import SimSystemPosix

p = angr.Project('./a.out', load_options={'auto_load_libs': False})

sm = p.factory.simulation_manager()
sm.explore(find= 0x400000+0x0000119f, avoid= 0x400000+ 0x000011ad)

print(sm.found[0].posix.dumps(0))

But, if I change "super!" password in my crackme with a password that contains spaces, angr doesn't find any solutions.

Using fgets instead of scanf gets the same result; If the password contains a space, angr does not found any password.

Of course, i have updated find and avoid addresses each time i recompile my c program.

2

That's because by doing so, you accidentally make the crackme unsolvable. Due to how scanf works with %s.

As per the C reference sheet, documentation and multiple sources (seriously, google is full of scanf documentation pages describing that):

%s : Scan a character string. The scan terminates at whitespace. A null character is stored at the end of the string, which means that the buffer supplied must be at least one character longer than the specified input length.

scanf will immediately stop reading characters into a string denoted with %s once a whitespace character (space included, obviously) is encountered. Even if you manually enter the correct password by hand into your newly created executable you'll get the error message instead of the success.

Additionally, gets behaves the same when it comes to whitespaces.

But you can solve the crackme by hand, it appears

Although this appears not to be the behavior you experience in your program, for some unknown reason, this is still the behavior angr assumes when handling scanf and scanf-like library functions. It is perhaps not widely known that angr, to avoid path explosion at the first encounter of a string library function, does not "natively" handle those functions like any other encountered function. In favor of efficiency and speed, angr "cheats" around library functions, format string functions included.

For that purpose angr has its own scanf function implementation in python, and that implementation follows the standard. You can see that scanf delimiters are defined and used to delimit scanfs possible output. Issues with scanf are even documented in angr's gotchas page:

For example, our scanf implementation is not complete, but if you just need to support a single, known format string, you can write a hook to do exactly that.

One way to avoid that is to modify the scanf implementation to something that does not consider whitespaces as delimiters. Another option is to disable that behavior by passing exclude_sim_procedures_list=['scanf'] as argument to your Project. You could also, as the gotcha's page suggest, implement something specific for your scenario.

  • This is strange because i can solve the crackme by hand by launching the executable and typing the password... – Bob5421 Aug 28 '18 at 6:53
  • @Bob5421 That's all fine and well, but angr still assumes the correct behavior ;) see my edit for more details about angr. – NirIzr Aug 28 '18 at 16:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.