From aldeid
Jump to navigation Jump to search
You are here


The challenge(r100) is worth 100 points. We have to deal with a 64-bit ELF.

MD5 7f24336a9475b4a6a79086f29ec0949a
SHA1 6a9331b8d452459a481c5946d727939945cc83a9
SHA256 8c481c589e9f95acbfdc20b54f5965017604a4c149dd72ec6bde55a5ea2a11bc
File ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/, for GNU/Linux 2.6.24, BuildID[sha1]=0f464824cc8ee321ef9a80a799c70b1b6aec8168, stripped

Running the binary

The binary doesn't expect any parameter. The password is prompted at runtime:

$ ./r100 
Enter the password: 123456
Incorrect password!



The main function is straightforward to analyze.

.text:00000000004007E8 ; int __cdecl main(int, char **, char **)
.text:00000000004007E8 main            proc near
.text:00000000004007E8 my_password     = byte ptr -110h
.text:00000000004007E8 var_8           = qword ptr -8
.text:00000000004007E8                 push    rbp
.text:00000000004007E9                 mov     rbp, rsp
.text:00000000004007EC                 sub     rsp, 110h
.text:00000000004007F3                 mov     rax, fs:28h
.text:00000000004007FC                 mov     [rbp+var_8], rax
.text:0000000000400800                 xor     eax, eax
.text:0000000000400802                 mov     edi, offset format ; "Enter the password: "
.text:0000000000400807                 mov     eax, 0
.text:000000000040080C                 call    _printf
.text:0000000000400811                 mov     rdx, cs:stdin   ; stream
.text:0000000000400818                 lea     rax, [rbp+my_password]
.text:000000000040081F                 mov     esi, 0FFh       ; n
.text:0000000000400824                 mov     rdi, rax        ; s
.text:0000000000400827                 call    _fgets
.text:000000000040082C                 test    rax, rax
.text:000000000040082F                 jz      short loc_400866
.text:0000000000400831                 lea     rax, [rbp+my_password]
.text:0000000000400838                 mov     rdi, rax
.text:000000000040083B                 call    check_password
.text:0000000000400840                 test    eax, eax
.text:0000000000400842                 jnz     short fail
.text:0000000000400844                 mov     edi, offset s   ; "Nice!"
.text:0000000000400849                 call    _puts
.text:000000000040084E                 mov     eax, 0
.text:0000000000400853                 jmp     short loc_40086B
.text:0000000000400855 ; ---------------------------------------------------------------------------
.text:0000000000400855 fail:
.text:0000000000400855                 mov     edi, offset aIncorrectPassw ; "Incorrect password!"
.text:000000000040085A                 call    _puts
.text:000000000040085F                 mov     eax, 1
.text:0000000000400864                 jmp     short loc_40086B
.text:0000000000400866 ; ---------------------------------------------------------------------------

At offset 0x400827, the user password is asked (call to _fgets) and passed to the sub_4006FD function (renamed check_password) at offset 0x40083B. If this function returns a non zero value, the password is invalid and the program will output the string Incorrect password!. Otherwise, it will display Nice!.


This function is manipulating the user input (password) and compares it to the result of a rather complex computation based on 3 strings (Dufhbmf, pG`imos, ewUglpt):

.text:00000000004006FD check_password  proc near
.text:00000000004006FD my_password     = qword ptr -38h
.text:00000000004006FD count_i         = dword ptr -24h
.text:00000000004006FD var_20          = qword ptr -20h
.text:00000000004006FD var_18          = qword ptr -18h
.text:00000000004006FD var_10          = qword ptr -10h
.text:00000000004006FD                 push    rbp
.text:00000000004006FE                 mov     rbp, rsp
.text:0000000000400701                 mov     [rbp+my_password], rdi
.text:0000000000400705                 mov     [rbp+count_i], 0
.text:000000000040070C                 mov     [rbp+var_20], offset aDufhbmf ; "Dufhbmf"
.text:0000000000400714                 mov     [rbp+var_18], offset aPgImos ; "pG`imos"
.text:000000000040071C                 mov     [rbp+var_10], offset aEwuglpt ; "ewUglpt"
.text:0000000000400724                 mov     [rbp+count_i], 0 ; i = 0
.text:000000000040072B                 jmp     short loc_40079B
.text:000000000040072D ; ---------------------------------------------------------------------------
.text:000000000040072D loc_40072D:
.text:000000000040072D                 mov     ecx, [rbp+count_i]
.text:0000000000400730                 mov     edx, 55555556h
.text:0000000000400735                 mov     eax, ecx
.text:0000000000400737                 imul    edx
.text:0000000000400739                 mov     eax, ecx
.text:000000000040073B                 sar     eax, 1Fh
.text:000000000040073E                 sub     edx, eax
.text:0000000000400740                 mov     eax, edx
.text:0000000000400742                 add     eax, eax
.text:0000000000400744                 add     eax, edx
.text:0000000000400746                 sub     ecx, eax
.text:0000000000400748                 mov     edx, ecx
.text:000000000040074A                 movsxd  rax, edx
.text:000000000040074D                 mov     rsi, [rbp+rax*8+var_20] ; var_20 = 'Dufhbmf'
.text:0000000000400752                 mov     ecx, [rbp+count_i] ; ecx = i
.text:0000000000400755                 mov     edx, 55555556h
.text:000000000040075A                 mov     eax, ecx
.text:000000000040075C                 imul    edx
.text:000000000040075E                 mov     eax, ecx
.text:0000000000400760                 sar     eax, 1Fh
.text:0000000000400763                 sub     edx, eax
.text:0000000000400765                 mov     eax, edx
.text:0000000000400767                 add     eax, eax
.text:0000000000400769                 cdqe
.text:000000000040076B                 add     rax, rsi
.text:000000000040076E                 movzx   eax, byte ptr [rax]
.text:0000000000400771                 movsx   edx, al
.text:0000000000400774                 mov     eax, [rbp+count_i]
.text:0000000000400777                 movsxd  rcx, eax
.text:000000000040077A                 mov     rax, [rbp+my_password]
.text:000000000040077E                 add     rax, rcx
.text:0000000000400781                 movzx   eax, byte ptr [rax]
.text:0000000000400784                 movsx   eax, al
.text:0000000000400787                 sub     edx, eax
.text:0000000000400789                 mov     eax, edx
.text:000000000040078B                 cmp     eax, 1
.text:000000000040078E                 jz      short loop_next
.text:0000000000400790                 mov     eax, 1
.text:0000000000400795                 jmp     short loc_4007A6
.text:0000000000400797 ; ---------------------------------------------------------------------------
.text:0000000000400797 loop_next:
.text:0000000000400797                 add     [rbp+count_i], 1
.text:000000000040079B loc_40079B:
.text:000000000040079B                 cmp     [rbp+count_i], 0Bh ; while i<11
.text:000000000040079F                 jle     short loc_40072D
.text:00000000004007A1                 mov     eax, 0
.text:00000000004007A6 loc_4007A6:
.text:00000000004007A6                 pop     rbp
.text:00000000004007A7                 retn
.text:00000000004007A7 check_password  endp

Using the pseudo-code plugin (press F5) really helps. It produces the following code:

signed __int64 __fastcall check_password(__int64 a1)
  signed int count_i; // [sp+14h] [bp-24h]@1
  const char *v3; // [sp+18h] [bp-20h]@1
  const char *v4; // [sp+20h] [bp-18h]@1
  const char *v5; // [sp+28h] [bp-10h]@1

  v3 = "Dufhbmf";
  v4 = "pG`imos";
  v5 = "ewUglpt";
  for ( count_i = 0; count_i <= 11; ++count_i )
    if ( (&v3)[8 * (count_i % 3)][2 * (count_i / 3)] - *(_BYTE *)(count_i + a1) != 1 )
      return 1LL;
  return 0LL;

It is now trivial to understand what the function does. It actually rotates between characters of the 3 strings (modulo the counter) to compute the expected characters of the password. We can write a script to display the expected password (notice that the 3 strings have been converted to hex values).


The following script:

#!/usr/bin/env python3
s = [[0x44, 0x75, 0x66, 0x68, 0x62, 0x6D, 0x66],
    [0x70, 0x47, 0x60, 0x69, 0x6D, 0x6F, 0x73],
    [0x65, 0x77, 0x55, 0x67, 0x6C, 0x70, 0x74]]
flag = []
for i in range(12):
print(''.join([chr(i) for i in flag]))

will output the following flag:


We can validate this flag:

$ ./r100 
Enter the password: Code_Talkers


blog comments powered by Disqus

Keywords: defcamp dctf-2015 ctf challenge reversing