GreHack-2015/50-EasyRE

From aldeid
Jump to navigation Jump to search
You are here:
50-EasyRE

Description

We have to deal with a 64-bit ELF:

$ file re50 
re50: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=f41797f7bb4823df72478c166b1ee316ef38b6f2, not stripped

The program is expecting an argument and returns Bad boy ! when the one provided is not the expected one:

$ ./re50 
Usage : ./re50 password
$ ./re50 aldeid
Bad boy !

Analysis

Graph overview

The code layout is as follows:

Initiailization

Starting from offset 0x4005AE, the code is building an encryption key and checks that an argument is passed to the program at offset 0x4005DB. If no argument is passed, the code will jump to 0x4005E1 (Usage).

.text:0000000000400596 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000400596                 public main
.text:0000000000400596 main            proc near
.text:0000000000400596
.text:0000000000400596 var_70          = qword ptr -70h
.text:0000000000400596 num_args        = dword ptr -64h
.text:0000000000400596 s               = byte ptr -60h
.text:0000000000400596 counter_i       = dword ptr -24h
.text:0000000000400596
.text:0000000000400596                 push    rbp
.text:0000000000400597                 mov     rbp, rsp
.text:000000000040059A                 push    r13
.text:000000000040059C                 push    r12
.text:000000000040059E                 push    rbx
.text:000000000040059F                 sub     rsp, 58h
.text:00000000004005A3                 mov     [rbp+num_args], edi
.text:00000000004005A6                 mov     [rbp+var_70], rsi
.text:00000000004005AA                 lea     rax, [rbp+s]                   ; encryption key
.text:00000000004005AE                 mov     rcx, 5D5445565B415E4Bh         ; 0x4B, 0x5E, 0x41, 0x5B, 0x56, 0x45, 0x54, 0x5D
.text:00000000004005B8                 mov     [rax], rcx
.text:00000000004005BB                 mov     rsi, 554356415256445Ch         ; 0x5C, 0x44, 0x56, 0x52, 0x41, 0x56, 0x43, 0x55
.text:00000000004005C5                 mov     [rax+8], rsi
.text:00000000004005C9                 mov     dword ptr [rax+10h], 525E415Eh ; 0x5E, 0x41, 0x5E, 0x52
.text:00000000004005D0                 mov     byte ptr [rax+14h], 0
.text:00000000004005D4                 mov     [rbp+counter_i], 0
.text:00000000004005DB                 cmp     [rbp+num_args], 1
.text:00000000004005DF                 jg      short loc_4005FF

Encryption

At offset 0x400651, the code is XORing each character of the user input (password) with the rolling encryption key.

.text:00000000004005FF loc_4005FF:
.text:00000000004005FF                 mov     [rbp+counter_i], 0
.text:0000000000400606                 jmp     short loc_400660
.text:0000000000400608 ; ---------------------------------------------------------------------------
.text:0000000000400608
.text:0000000000400608 loc_400608:
.text:0000000000400608                 mov     eax, [rbp+counter_i]
.text:000000000040060B                 cdqe
.text:000000000040060D                 movzx   r12d, [rbp+rax+s]
.text:0000000000400613                 mov     rax, [rbp+var_70]
.text:0000000000400617                 add     rax, 8
.text:000000000040061B                 mov     r13, [rax]
.text:000000000040061E                 mov     eax, [rbp+counter_i]
.text:0000000000400621                 movsxd  rbx, eax
.text:0000000000400624                 mov     rax, [rbp+var_70]
.text:0000000000400628                 add     rax, 8
.text:000000000040062C                 mov     rax, [rax]
.text:000000000040062F                 mov     rdi, rax        ; s
.text:0000000000400632                 call    _strlen
.text:0000000000400637                 mov     rcx, rax
.text:000000000040063A                 mov     rax, rbx
.text:000000000040063D                 mov     edx, 0
.text:0000000000400642                 div     rcx
.text:0000000000400645                 mov     rax, rdx
.text:0000000000400648                 add     rax, r13
.text:000000000040064B                 movzx   eax, byte ptr [rax]
.text:000000000040064E                 mov     edx, r12d
.text:0000000000400651                 xor     edx, eax        ; password[i] ^ encryption_key[i]
.text:0000000000400653                 mov     eax, [rbp+counter_i]
.text:0000000000400656                 cdqe
.text:0000000000400658                 mov     [rbp+rax+s], dl
.text:000000000040065C                 add     [rbp+counter_i], 1
.text:0000000000400660
.text:0000000000400660 loc_400660:
.text:0000000000400660                 mov     eax, [rbp+counter_i]
.text:0000000000400663                 movsxd  rbx, eax
.text:0000000000400666                 lea     rax, [rbp+s]
.text:000000000040066A                 mov     rdi, rax        ; s
.text:000000000040066D                 call    _strlen
.text:0000000000400672                 cmp     rbx, rax
.text:0000000000400675                 jb      short loc_400608

Verification

The code then checks whether the encrypted password results in the following string: xorhavenosecretforme:

.text:0000000000400677                 lea     rax, [rbp+s]
.text:000000000040067B                 mov     esi, offset s2  ; "xorhavenosecretforme"
.text:0000000000400680                 mov     rdi, rax        ; s1
.text:0000000000400683                 call    _strcmp
.text:0000000000400688                 test    eax, eax
.text:000000000040068A                 jnz     short loc_40069D
.text:000000000040068C                 mov     edi, offset aGoodBoy ; "Good boy !"
.text:0000000000400691                 mov     eax, 0
.text:0000000000400696                 call    _printf
.text:000000000040069B                 jmp     short loc_4006AC
.text:000000000040069D ; ---------------------------------------------------------------------------
.text:000000000040069D
.text:000000000040069D loc_40069D:
.text:000000000040069D                 mov     edi, offset aBadBoy ; "Bad boy !"
.text:00000000004006A2                 mov     eax, 0
.text:00000000004006A7                 call    _printf

Solution

The solution can be scripted in python:

#!/usr/bin/env python

p = []
x = [0x4B, 0x5E, 0x41, 0x5B, 0x56,
     0x45, 0x54, 0x5D, 0x5C, 0x44,
     0x56, 0x52, 0x41, 0x56, 0x43,
     0x55, 0x5E, 0x41, 0x5E, 0x52]
s = "xorhavenosecretforme"
for (c, i) in enumerate(s):
    p.append(ord(i) ^ x[c])
print(''.join([chr(i) for i in p]))

Let's run the script:

$ ./solution_re50.py 
31337313373133731337

We can confirm that this is the correct password:

$ ./re50 31337313373133731337
Good boy !

Comments

Keywords: grehack-2015 assembly reverse-engineering crackme