Solution-rezk2ll-BeatME

From aldeid
Jump to navigation Jump to search

Description

Here is my write-up for the rezk2ll BeatME crackme, available here.

MD5 7f3007983ee8717dc0bbc377fe5a741d BeatMe
SHA1 9408039d46e0ffdaa0d4c124823ad078fdc22277 BeatMe
SHA256 783c1be3b242f0cd6fa7f80fd47d370ba06387fa588f73327229a4dfa6f59cbe
File ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped

What does it look like?

When we start the program, it displays a banner and asks for a username and a password. If we don't provide the expected password, it displays a failure message:

$ ./BeatMe 
 ____             _   __  __
| __ )  ___  __ _| |_|  \/  | ___
|  _ \ / _ \/ _` | __| |\/| |/ _ \
| |_) |  __/ (_| | |_| |  | |  __/
|____/ \___|\__,_|\__|_|  |_|\___| | ReZK2LL

USERNAME : aldeid
PASSWORD : aldeid
NOPE , YOU LOSE 

Analysis

Obfuscated strings

Strings are obfuscated as depicted below:

.data:080492F0 44 50 53 53 46 44 55 21 2D 21+aDpssfduZpvXjo  db 'DPSSFDU!-!ZPV!XJO!',0Bh,0
.data:080492F0 5A 50 56 21 58 4A 4F 21 0B 00                                         ; DATA XREF: f_check+9A�o
.data:080492F0                                                                       ; f_check+AE�o
.data:080492F0                                                                       ; CORRECT , YOU WIN
.data:08049304 4F 50 51 46 21 2D 21 5A 50 56+aOpqfZpvMptf    db 'OPQF!-!ZPV!MPTF!',0Bh,0
.data:08049304 21 4D 50 54 46 21 0B 00                                               ; DATA XREF: f_check:loc_80482C5�o
.data:08049304                                                                       ; f_check+F5�o
.data:08049304                                                                       ; NOPE , YOU LOSE
.data:08049304                                                                       ;
.data:08049316 56 54 46 53 4F 42 4E 46 21 3B+aVtfsobnf       db 'VTFSOBNF!;!',0      ; DATA XREF: start+5�o
.data:08049316 21 00                                                                 ; start+19�o
.data:08049316                                                                       ; USERNAME
.data:08049322 51 42 54 54 58 50 53 45 21 3B+aQbttxpse       db 'QBTTXPSE!;!',0      ; DATA XREF: start+59�o
.data:08049322 21 00                                                                 ; start+6D�o
.data:08049322                                                                       ; PASSWORD :
.data:0804932E 21 60 60 60 60 21 21 21 21 21+asc_804932E     db '!````!!!!!!!!!!!!!`!!!``!!``',0Bh,0
.data:0804932E 21 21 21 21 21 21 21 21 60 21+                                        ; DATA XREF: sub_8048132�o
.data:0804932E 21 21 60 60 21 21 60 60 0B 00                                         ; sub_8048132+14�o
.data:0804932E                                                                       ;  ____             _   __  __
.data:0804932E                                                                       ;
.data:0804934C 7D 21 60 60 21 2A 21 21 60 60+a0              db '}!``!*!!```!!``!`}!}`}!!]0!!}!```',0Bh,0
.data:0804934C 60 21 21 60 60 21 60 7D 21 7D+                                        ; DATA XREF: sub_8048132+20�o
.data:0804934C 60 7D 21 21 5D 30 21 21 7D 21+                                        ; sub_8048132+34�o
.data:0804936F 7D 21 21 60 21 5D 21 30 21 60+a00A00          db '}!!`!]!0!`!]0!`a!}!``}!}]0}!}0!`!]',0Bh,0
.data:0804936F 21 5D 30 21 60 61 21 7D 21 60+                                        ; DATA XREF: sub_8048132+40�o
.data:0804936F 60 7D 21 7D 5D 30 7D 21 7D 30+                                        ; sub_8048132+54�o
.data:08049393 7D 21 7D 60 2A 21 7D 21 21 60+a00             db '}!}`*!}!!``0!)`}!}!}`}!}!!}!}!!``0',0Bh,0
.data:08049393 60 30 21 29 60 7D 21 7D 21 7D+                                        ; DATA XREF: sub_8048132+60�o
.data:08049393 60 7D 21 7D 21 21 7D 21 7D 21+                                        ; sub_8048132+74�o
.data:080493B7 7D 60 60 60 60 30 21 5D 60 60+a0SfL3mm        db '}````0!]```}]``-`}]``}`}!!}`}]```}!}!Sf[L3MM',0Bh,0Bh,0
.data:080493B7 60 7D 5D 60 60 2D 60 7D 5D 60+                                        ; DATA XREF: sub_8048132+80�o
.data:080493B7 60 7D 60 7D 21 21 7D 60 7D 5D+                                        ; sub_8048132+94�o

The function at offset 0x080481D3 decrypts these strings by substracting 1 to each character of the string as shown below:

The following python script helps decrypting the strings. Just place your cursor on the string to decrypt and call the script:

start = ScreenEA()

go = True
i = 0
tmp = []

while go:
    b = Byte(start+i)
    if b == 0:
        go = False
    else:
        tmp.append(b - 1)
        i += 1

MakeRptCmt(start, ''.join([chr(i) for i in tmp]))

Username input

The programs starts by displaying a banner (BeatMe in ASCII art) and prompting for a USERNAME using sysread (with EAX set to 0x3 for read). The username is saved to memory location 0x80493EC:

.text:08048080 public start
.text:08048080 start proc near
.text:08048080 call    f_display_banner
.text:08048085 mov     esi, offset aVtfsobnf ; USERNAME
.text:0804808A call    f_decrypt_message
.text:0804808F mov     eax, 4          ; EAX = 4 (sys_write)
.text:08048094 mov     ebx, 1          ; fd
.text:08048099 mov     ecx, offset aVtfsobnf ; USERNAME
.text:0804809E mov     edx, 0Ch        ; len
.text:080480A3 int     80h             ; LINUX - sys_write
.text:080480A5 mov     eax, 3          ; EAX = 3 (sys_read)
.text:080480AA xor     ebx, ebx        ; fd
.text:080480AC mov     ecx, offset my_username

The length of the username should be between 3 and 9 characters (don't forget that strings end with a trailing 0x0 to indicate the end of the string):

.text:080480B8 83 F8 03                                      cmp     eax, 3          ; \ if len(my_username) <= 3
.text:080480BB 0F 8E DF 01 00 00                             jle     goto_LOOSE      ; / goto LOOSE
.text:080480C1 83 F8 0A                                      cmp     eax, 10         ; len(username) < 10
.text:080480C4 7C 0C                                         jl      short loc_80480D2

Password input

If the length of the user input was correct, the password is then prompted, using the same syscall:

Expected password

First character

The sub_80481E4 function is then called. This is where the expected password will be built and compared to the password provided by the user.

The first character of the expected password corresponds to the length of the user input:

.text:080481E4 f_check proc near
.text:080481E4 mov     esi, offset my_password
.text:080481E9 mov     bl, [esi]       ; BL = my_password[0]
.text:080481EB sub     bl, 48          ; BL = ord(my_password[0]) - 48
.text:080481EB                         ; -48 used to transform ascii char to num
.text:080481EE mov     al, ds:len_username
.text:080481F3 cmp     al, bl          ; my_password[0] should be equal to
.text:080481F3                         ; len(user_name) + 48
.text:080481F5 jnz     goto

-48 is actually substracted from the 1st character to do the conversion between the string value and the numeric one. The below example depicts it in python, for a length of 6:

>>> len_str = "6"
>>> ord(len_str)
54
>>> ord(len_str) - 48
6

Second character

The second character of the expected password corresponds to the 3rd character of the username:

.text:0804822E loc_804822E:
.text:0804822E popa
.text:0804822F inc     esi
.text:08048230 mov     bl, [esi]       ; BL = my_password[1]
.text:08048232 mov     al, ds:byte_80493EE ; AL = my_username[2]
.text:08048237 cmp     bl, al          ; my_password[1] should be equal
.text:08048237                         ; to my_username[2]
.text:08048239 jnz     short goto_LOOSE

Remaining characters

Each of the remaining characters of the expected password correspond to the characters of the username + the length of the username divided by 2 (shr 1) + 1:

Keygen

Below is my keygen as well as a demo of it in action:

#!/usr/bin/env python
import sys

def keygen(my_username):
    my_password = []
    
    # 1st char of password is username length
    my_password.append(str(len(my_username)))
    
    # 2nd char of password is 3rd char of username
    my_password.append(my_username[2])
    
    # Remaining chars of password are username[i] + len(username)>>1 + 1
    for i in my_username:
        my_password.append(chr( ord(i) + (len(my_username)>>1) + 1 ))
    
    return ''.join(my_password)


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print "Usage: %s <username>" % sys.argv[0]
        sys.exit(1)
    
    my_username = sys.argv[1]
    if len(my_username) <= 2 or len(my_username) >= 9:
        print "Username should have between 3 and 9 characters"
        sys.exit(2)
    
    print "USERNAME: %s" % my_username
    print "PASSWORD: %s" % keygen(my_username)

Here is the keygen in action:

$ ./keygen.py 
Usage: ./keygen.py <username>
$ ./keygen.py aldeid
USERNAME: aldeid
PASSWORD: 6dephimh

Comments

Keywords: assembly elf reverse-engineering crackme rezk2ll beatme