2011/01/17

[Write-Up] Security By Default CTF : Bin01 (reversing)

Ce week end avaient lieu le CTF "Security By Default" auquel nous avons participé.
Simultanément avait aussi lieu le Padocon qui lui aussi semblait vraiment simpa bien que d'un niveau bien hard ;-) .
Bref , concentrons-nous sur le sujet de ce billet , a savoir : le Bin01 du CTF "Security By Default".
La premiere chose que l'on remarque dessuite via l'utilitaire "file" : ce binaire est du type elf32 , non stippé .
    Ainsi j'ai pu facilement commencer dans un premier temp une rapide analyse a l'aide d'Hexrays  afin de réaliser un arbre des appels de fonctions ainsi que des dumps ASM puis C pour bien cerner la bête et voir comment agir.
(Les parties du code ne nous intérréssant pas on bien sur été supprimées)
         ...
        mov    edx, offset format ; "\n--- Welcome to '%s' systems.\n"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        lea    eax, [esp+6Bh]
        mov    [esp], eax
        call    tor
        mov    edx, offset aS    ; "%s"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        mov    eax, ds:stdin@@GLIBC_2_0
        mov    [esp], eax    ; stream
        call    _fflush
        lea    eax, [esp+1894h]
        mov    [esp], eax    ; s
        call    _gets
        lea    eax, [esp+58h]
        mov    [esp], eax
        call    tor
        mov    edx, offset aS    ; "%s"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        mov    eax, ds:stdin@@GLIBC_2_0
        mov    [esp], eax    ; stream
        call    _fflush
        lea    eax, [esp+10C4h]
        mov    [esp], eax    ; s
        call    _gets
        lea    eax, [esp+4Bh]
        mov    [esp], eax
        call    tor
        mov    edx, offset aS    ; "%s"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        mov    eax, ds:stdin@@GLIBC_2_0
        mov    [esp], eax    ; stream
        call    _fflush
        mov    eax, [esp+2068h]
        mov    [esp], eax    ; s
        call    _gets
        lea    eax, [esp+39h]
        mov    [esp], eax
        call    tor
        mov    edx, offset aS    ; "%s"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        mov    eax, ds:stdin@@GLIBC_2_0
        mov    [esp], eax    ; stream
        call    _fflush
        lea    eax, [esp+8F4h]
        mov    [esp], eax    ; s
        call    _gets
        lea    eax, [esp+1Bh]
        mov    [esp], eax    ; s
        call    untrash
        lea    eax, [esp+1Bh]
        mov    [esp], eax
        call    tor
        mov    edx, offset aS    ; "%s"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        mov    eax, ds:stdin@@GLIBC_2_0
        mov    [esp], eax    ; stream
        call    _fflush
        lea    eax, [esp+124h]
        mov    [esp], eax    ; s
        call    _gets
        mov    dword ptr [esp+2064h],
        jmp    short loc_8048A47
; ---------------------------------------------------------------------------

loc_8048A0D:               
        mov    eax, [esp+206Ch]
        mov    eax, [eax]
        cmp    eax, [esp+2064h]
        jnz    short loc_8048A3F
        lea    eax, [esp+9Bh]
        mov    [esp], eax
        call    tor
        mov    edx, offset aAlertS ; "ALERT: %s\n"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf

loc_8048A3F:               
        add    dword ptr [esp+2064h], 1

loc_8048A47:               
        cmp    dword ptr [esp+2064h], 9
        jle    short loc_8048A0D
        mov    eax, [esp+206Ch]
        mov    eax, [eax]
        test    eax, eax
        jz    short loc_8048AA9
        lea    eax, [esp+0B0h]
        mov    [esp], eax    ; s
        call    untrash
        lea    eax, [esp+0B0h]
        mov    [esp], eax
        call    tor
        mov    ebx, eax
        lea    eax, [esp+0F9h]
        mov    [esp], eax
        call    tor
        mov    edx, offset aSS    ; "%s %s\n"
        mov    [esp+8], ebx
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        mov    eax, 0
        jmp    short loc_8048AF0
; ---------------------------------------------------------------------------

loc_8048AA9:               
        mov    dword ptr [esp+4], offset s2 ; "admin_r00t"
        lea    eax, [esp+124h]
        mov    [esp], eax    ; s1
        call    _strcmp
        test    eax, eax
        jnz    short loc_8048AEB
        lea    eax, [esp+112h]
        mov    [esp], eax
        call    tor
        mov    edx, offset aS_0 ; "%s :)\n"
        mov    [esp+4], eax
        mov    [esp], edx    ; format
        call    _printf
        mov    eax, 45h
        jmp    short loc_8048AF0
; ---------------------------------------------------------------------------

loc_8048AEB:               
        mov    eax, 45h

loc_8048AF0:               
        add    esp, 2074h
        pop    ebx
        pop    esi
        pop    edi
        mov    esp, ebp
        pop    ebp
        retn
main        endp

; ---------------------------------------------------------------------------
       ...
  Dans cet extrait du code assembleur , ces fonctions semblent etre celles qui nous intéressent  , a partir de la on réalise un désassemblage qui donne : 




J'ai ensuite étudié l'algo un peu plus en profondeur via un dump C d'Hexrays qui s'avéra trés  instructif quand au fonctionnement ducrackme.
  ...
  printf("\n--- Welcome to '%s' systems.\n", v0);
  v1 = tor(&v34);
  printf("%s", v1);
  fflush(stdin);
  gets(&v70);
  v2 = tor(&v28);
  printf("%s", v2);
  fflush(stdin);
  gets(&v69);
  v3 = tor(&v24);
  printf("%s", v3);
  fflush(stdin);
  gets((char *)v72);
  v4 = tor(&v19);
  printf("%s", v4);
  fflush(stdin);
  gets(&v68);
  untrash((const char *)&v11);
  v5 = tor(&v11);
  printf("%s", v5);
  fflush(stdin);
  gets(&v67);
  for ( i = -5; i <= 9; ++i )
  {
    if ( *(_DWORD *)v73 == i )
    {
      v6 = tor(&v47);
      printf("ALERT: %s\n", v6);
    }
  }
  if ( *(_DWORD *)v73 )
  {
    untrash(&v53);
    v8 = tor((int *)&v53);
    v9 = tor(&v55);
    printf("%s %s\n", v9, v8);
    result = 0;
  }
  else
  {
    if ( strcmp(&v67, "admin_r00t") )
    {
      result = 69;
    }
    else
    {
      v10 = tor(&v62);
      printf("%s :)\n", v10);
      result = 69;
    }
  }
  return result;
  ...
    Voila , nous somme au coeur du problème a présent, j'me suis donc dit que j'allais travailler ça de façon a patcher le binaire pour luifaire cracher son flag et ne plus avoir  d'outputs frustrants comme  les :
ALERT: You are not welcome.
ou encore
It's not so easy Dude ! (aprés patching de plusieurs sauts conditionels/call par exemple).

Le but recherché étant d'obtenir le flag de validation  , j'ai fait ça de façon rapide mais absolument pas esthétique , puristes s'abstenir !
 
   Pour y parvenir il ne me resta plus qu'a rechercher certaines fonctions (dont celle qui construisent et donne le précieux sésame) puis a patcher afin de jumper au bon endroit.

 Voici quelques une des modifs ainsi effectuées :
Parti de cette instruction    jmp   loc_8048a47  , on jump en 0x8048a47 et on apporte les modifs adéquates.

La capture suivante propose 2 vues a savoir a gauche le binaire dans sa version originale , a droite sa version patchée .




La chaine contenue dans  strz__s__s__8048bed  se trouvait donc etre "admin_r00t %s %s\n\0" :-^ .
Voila , restait alors qu'a chopper le flag et a valider :

sh-3.2$ ./copie\ de\ n00b-login

--- Welcome to 'Epicness Security' systems.
Insert name: kmkz
Insert last name: sec0d
Insert sex: Faible(:P)
Inserd birthday: 1337
Insert passwd: pawned!
Damn it! SYSTEM FAILURE: iTSeeMsThaTWeAreNotEpicnessAtAlL