Writeups

View on GitHub

Crackme 3

Category : Reversing

This was a rather interesting and slightly long challenge to solve. We are given a binary. Let’s check it out in Ghidra. The one function which looks like the main.


undefined4 FUN_00011502(void)

{
  undefined4 uVar1;
  int in_GS_OFFSET;
  int local_70;
  code *local_68 [4];
  code *local_58;
  undefined local_54 [64];
  int local_14;
  undefined *local_10;
  
  local_10 = &stack0x00000004;
  local_14 = *(int *)(in_GS_OFFSET + 0x14);
  local_68[0] = FUN_00011286;
  local_68[1] = FUN_000112bd;
  local_68[2] = FUN_000112e6;
  local_68[3] = FUN_00011392;
  local_58 = FUN_00011410;
  setvbuf(stdout,(char *)0x0,2,0);
  puts("Hi!, i am a BOMB!\nI will go boom if you don\'t give me right inputs");
  local_70 = 0;
  while (local_70 < 5) {
    printf("Enter input #%d: ",local_70);
    __isoc99_scanf(&DAT_000120b9,local_54);
    (*local_68[local_70])(local_54);
    local_70 = local_70 + 1;
  }
  FUN_0001122d();
  uVar1 = 0;
  if (local_14 != *(int *)(in_GS_OFFSET + 0x14)) {
    uVar1 = FUN_00011670();
  }
  return uVar1;
}

So, we have a array of function pointers which are called in succession if they are returned.

We need a total of 5 passwords to get the FLAG.

For the first function :


void FUN_00011286(char *param_1)

{
  int iVar1;
  
  iVar1 = FUN_000115fc();
  iVar1 = strcmp(param_1,(char *)(iVar1 + 0xd8e));
  if (iVar1 != 0) {
    FUN_00011258();
  }
  return;
}

Not much info here. Using Strace, we get that input is compared with ` CRACKME02 `

For the second password :


void FUN_000112bd(int *param_1)

{
  FUN_000115fc();
  if (*param_1 != -0x21524111) {
    FUN_00011258();
  }
  return;
}

Also, the disassembly :

                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined FUN_000112bd(undefined4 param_1)
             undefined         AL:1           <RETURN>
             undefined4        Stack[0x4]:4   param_1                                 XREF[1]:     000112d4(R)  
             undefined4        Stack[-0x10]:4 local_10                                XREF[2]:     000112cd(W), 
                                                                                                   000112d9(R)  
                             FUN_000112bd                                    XREF[4]:     FUN_00011502:00011533(*), 
                                                                                          FUN_00011502:00011539(*), 
                                                                                          000120f0, 0001220c(*)  
        000112bd 55              PUSH       EBP
        000112be 89 e5           MOV        EBP,ESP
        000112c0 83 ec 18        SUB        ESP,0x18
        000112c3 e8 34 03        CALL       FUN_000115fc                                     undefined FUN_000115fc()
                 00 00
        000112c8 05 38 2d        ADD        EAX,0x2d38
                 00 00
        000112cd c7 45 f4        MOV        dword ptr [EBP + local_10],0xdeadbeef
                 ef be ad de
        000112d4 8b 45 08        MOV        EAX,dword ptr [EBP + param_1]
        000112d7 8b 00           MOV        EAX,dword ptr [EAX]
        000112d9 39 45 f4        CMP        dword ptr [EBP + local_10],EAX
        000112dc 74 05           JZ         LAB_000112e3
        000112de e8 75 ff        CALL       FUN_00011258                                     undefined FUN_00011258()
                 ff ff
                             LAB_000112e3                                    XREF[1]:     000112dc(j)  
        000112e3 90              NOP
        000112e4 c9              LEAVE
        000112e5 c3              RET

There’s a simple compare of the input with ` 0xdeadbeef`

For the third password :

/* WARNING: Function: __i686.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void FUN_000112e6(int param_1)

{
  size_t sVar1;
  int in_GS_OFFSET;
  uint local_2c;
  undefined4 local_25;
  undefined4 local_21;
  undefined4 local_1d;
  undefined4 local_19;
  undefined4 local_15;
  undefined local_11;
  int local_10;
  
  local_10 = *(int *)(in_GS_OFFSET + 0x14);
  local_25 = 0x7479585a;
  local_21 = 0x66396255;
  local_1d = 0x6538376c;
  local_19 = 0x794a6776;
  local_15 = 0x4e4a4b33;
  local_11 = 0;
  local_2c = 0;
  while( true ) {
    sVar1 = strlen((char *)&local_25);
    if (sVar1 <= local_2c) break;
    if (*(char *)((int)&local_25 + local_2c) != *(char *)(param_1 + local_2c)) {
      FUN_00011258();
    }
    local_2c = local_2c + 1;
  }
  if (local_10 != *(int *)(in_GS_OFFSET + 0x14)) {
    FUN_00011670();
  }
  return;
}

We have a simple compare of the string with a hardcoded value.

For the fourth password :


void FUN_00011392(char *param_1)

{
  size_t sVar1;
  int iVar2;
  
  sVar1 = strlen(param_1);
  if (3 < sVar1) {
    FUN_00011258();
  }
  iVar2 = atoi(param_1);
  if ((iVar2 * iVar2 * 2 - iVar2) * 2 + -3 + iVar2 * iVar2 * iVar2 == 0) {
    puts("SUBSCRIBE TO PEWDIEPIE");
  }
  else {
    FUN_00011258();
  }
  return;
}

Here the input is converted to a int and then passed on to solved a quadratic equation.

The equation has a root 1.36, since it is an int, we can pass “1” to get to the next stage

For the last part :


/* WARNING: Function: __i686.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void FUN_00011410(char *param_1)

{
  int in_GS_OFFSET;
  char local_1a;
  char local_19;
  char local_18;
  char local_17;
  char local_16;
  char local_15;
  char local_14;
  char local_13;
  char local_12;
  int local_10;
  
  local_10 = *(int *)(in_GS_OFFSET + 0x14);
  strncpy(&local_1a,param_1,10);
  puts("Validating Input 4");
  if ((int)local_12 + (int)local_1a == 0xd5) {
    if ((int)local_13 + (int)local_19 == 0xce) {
      if ((int)local_14 + (int)local_18 == 0xe7) {
        if ((int)local_15 + (int)local_17 == 0xc9) {
          if (local_16 == 'i') {
            puts("you earned it");
          }
        }
        else {
          FUN_00011258();
        }
      }
      else {
        FUN_00011258();
      }
    }
    else {
      FUN_00011258();
    }
  }
  else {
    FUN_00011258();
  }
  if (local_10 != *(int *)(in_GS_OFFSET + 0x14)) {
    FUN_00011670();
  }
  return;
}

10 chars to input are copied to range of chars. A easy buffer overflow. Then the sums of first and last value is added and compared to a constant. Since the constant is > 256. we have to divide the val by two and pass values accordingly.

The final exploit

from pwn import *
print('CRACKME02\n' + p32(0xdeadbeef)+'\n'+p32(0x7479585a)+''+p32(0x66396255)+''+p32(0x6538376c)+''+p32(0x794a6776)+''+p32(0x4e4a4b33)+'\n'+'1\n'+'\x6b\x67\x74\x65i\x64\x73\x67\x6A\n')

We get the flag

vipul@ubuntu:~$ cat reverse | nc 104.154.106.182 7777
Hi!, i am a BOMB!
I will go boom if you don't give me right inputs
Enter input #0: Enter input #1: Enter input #2: Enter input #3: SUBSCRIBE TO PEWDIEPIE
Enter input #4: Validating Input 4
you earned it
encryptCTF{B0mB_D!ffu53d}