Points: 80 Category: Reverse Author sheidan

## Introduction

We have an ELF binary which takes one parameter. This parameter is a secret and it is used in a cryptographic function called hash. So the goal is to find the secret. The program must return 22c15d5f23238a8fff8d299f8e5a1c62 as output.

Here, we explain two solutions to solve this challenge.

## First solution

### Static analysis

The hash function is located at `0x080484AB`. It takes our input parameter and some operations are carried out.

This part of the code, at `0x80484CC`, allows us to understand the algorithm as describe by the comments:

``````loc_80484CC:
mov     eax, [ebp+size]
sub     eax, 1
sub     eax, [ebp+i]    ; eax = strlen(*s) - 1 - i
mov     [ebp+size_1_i], eax
mov     edx, [ebp+size_1_i]
mov     eax, [ebp+s]
add     edx, eax        ; s[strlen(*s) - 1 - i]
mov     eax, [ebp+i]
mov     eax, u[eax*4]   ; u[i*4]
mov     ebx, eax
mov     ecx, [ebp+size_1_i]
mov     eax, [ebp+s]
add     eax, ecx        ; s[strlen(*s) - 1 - i]
movzx   eax, byte ptr [eax]

xoring:
movsx   eax, al
mov     eax, v[eax*4]   ; v[s[strlen(*s) - 1 - i] * 4]
xor     eax, ebx        ; v[s[strlen(*s) - 1 - i] * 4] ^ u[i*4]
mov     [edx], al       ; s[strlen(*s) - 1 - i] = eax ^ ebx
add     [ebp+i], 1      ; i++
``````

Below, we translate asm operations into C-like pseudocode. This code describes the encryption operations:

``````size_t size = strlen(s)
for (int i = 0; i < size; i++)
{
s[size - 1 - i] =  v[s[size - 1 - i] * 4] ^ u[i * 4]
}
``````

The decryption process is illustrated by the c-like pseudocode below:

``````size_t size = strlen(s)
for (int i = 0; i < size; i++)
{
s[size - 1 - i]  ^ u[i * 4] =  v[s[size - 1 - i] * 4]
}
``````

Please note that we are going to have the value which is in v and not the secret value. We must find the index of this value to retrieve the initial value.

### Retrieve the flag

We translate the decryption expression into a python script:

``````def decrypt(pKey, pCharset, pHexFinalOutput):
"""
:param pKey: seems to be the key
:param pCharset: seems to be a charset
:param pHexFinalOutput: is the program output for the flag as input
"""
# Translate hex string
finalOutput = pHexFinalOutput.decode("hex")

# Initialize the secret variable
secret = ""

for i, c in enumerate(finalOutput[::-1]):
r = ord(c) ^ pKey[i]
secret += chr(pCharset.index(r))

return secret[::-1]

"""
"""
data = []

return data

# It is the output of the program for the flag as input
hexFinalOutput = "22c15d5f23238a8fff8d299f8e5a1c62"

# hash function uses a list which is called 'u'. This list seems to be the key
key = extract_32bits(0x0804a440, 0x0804A83D)

# hash function uses a list which is called 'v'. This list seems to be a charset
charset = extract_32bits(0x0804A040, 0x0804a440)

# Let's find the secret
secret = decrypt(key, charset, hexFinalOutput)

print(secret)
# yummy_h45h_br0wn
``````

## Second solution: Patch’n flag

### Patch the binary

In fact, if we patch the binary we don’t need to know each details of the hash function because it is simple cryptographic function.

As we know, the binary is bricked. It is because strcpy function at `0x08048566` replace our string by a string equal to 0.

``````push    [ebp+src]       ; src, src=""
push    eax             ; dest, dest=<secret param>
call    _strcpy
``````

The patch consists in replacing `call _strcpy`. `EAX` is already set as we want therefore we replace original opcodes by ‘nop’ opcodes.

``````[...]
E8 F5 FD FF FF --ERASE BY--> 90 90 90 90 90
[...]
``````

After that, we run the program. We see that the output can be found by brute force because any characters will always have the same value at offset -1. At offset -2, the value is not equal to offset -1 but it is always the same as shown below:

``````./patched a
c4

./patch aa
c7c4

./patch baa
96c7c4
``````

### Retrieve the flag

Let’s find the secret by testing all printable characters.

``````hash_ = "22c15d5f23238a8fff8d299f8e5a1c62"
size = len(hash_)
flag = []

for i in range(0, size, 2):
index = size - i

# Get last hex values
check = hash_[index-2:]

# Looking for the correct character
for c in string.printable:
p = subprocess.Popen(["./patched.elf", "{}{}".format(c,"".join(flag))],
stdout=subprocess.PIPE)
stdout = p.communicate().decode("utf-8").strip()

# If output is egal to partial final hash
if stdout == check:
# Insert the character at the beginning
flag.insert(0,c)

print("".join(flag))
# yummy_h45h_br0wn
``````