duksctf

Bunch of sec. enthusiasts who sometimes play CTF

AlexCTF 2017 - Catalyst System

Elf binary asking for username/password, the username is used to compute a seed to srand, which then get use to substract rand() with every 4 bytes of the password.

Description

CEO of catalyst systems decided to build his own log in system from scratch, he thought that it is so safe that no one can fool around with him!

Details

Points: 150

Category: reverse

Validations: 201

Solution

We were given a binary file catalyst. Some recon:

-> $ file catalyst 
catalyst: 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]=3c4646c45da147f57cfa3fe0b9f1022d84fbe85f, stripped

-> $ strings catalyst 
REDACTED
/lib64/ld-linux-x86-64.so.2
libc.so.6
fflush
puts
time
putchar
printf
strlen
your flag is: ALEXCTF{
invalid username or password

Runing the binary shows that some delay has been added during the beginning:

We patched the jmp short loc_400EA5 and the jmp short loc_400F5E to jump after the boring sleep function using keypatch whic is a plugin to patch binary directly in IDA using real assembly language and not opcode:

Here is the graph of the patched binary without the pesky sleep function:

After removing the function we started looking at the username parsing. It do some calcuation on the bytes in order to validate it, this looks like a perfect case for enhancing our skills with angr which is a symbolic execution framework.

Here is the python script to retrieve the username:

import angr
import sys
p = angr.Project('./catalyst',  load_options={'auto_load_libs': False})
main = 0x400D93

init = p.factory.blank_state(addr=main)

def hook_printf(state):
    pass

p.hook(0x00400DCD, hook_printf,length=5)
p.hook(0x00400DD7, hook_printf,length=5)
p.hook(0x00400DE1, hook_printf,length=5)
p.hook(0x00400DEB, hook_printf,length=5)
p.hook(0x00400DF5, hook_printf,length=5)
p.hook(0x00400DFF, hook_printf,length=5)
p.hook(0x00400E09, hook_printf,length=5)
p.hook(0x00400E13, hook_printf,length=5)
p.hook(0x00400E1D, hook_printf,length=5)
p.hook(0x00400e27, hook_printf,length=5)
p.hook(0x00400e31, hook_printf,length=5)
p.hook(0x00400e3b, hook_printf,length=5)


pg = p.factory.path_group(init, threads=8)
ex = pg.explore(find=(0x00400D92, ), avoid=(0x00400D7C, 0x00400C83))

if ex.found:
    print ex.found[0].state.posix.dumps(0)

We hooked the puts function because it looks like angr’s implement was buggy. Running our script gave us the username:

-> $ ./get_username.py  
catalyst_ceoÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ`ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ

So the username was catalyst_ceo.

Now we need to find the password. Looking again in the binary, the function sub_400977 use srand which is seeded by the sum of the three first bytes of the username.

After the srand, several rand() was substracted to some constants. We wrote a simple C program in order to get the value for srand() the we added the value with constants to generate the password:

#include <stdio.h>
#include <stdlib.h>


int main()
{
    srand(1162690094);
    printf("rand0: %d\n", rand());
    printf("rand1: %d\n", rand());
    printf("rand2: %d\n", rand());
    printf("rand3: %d\n", rand());
    printf("rand4: %d\n", rand());
    printf("rand5: %d\n", rand());
    printf("rand6: %d\n", rand());
    printf("rand7: %d\n", rand());

    printf("rand8: %d\n", rand());
    printf("rand9: %d\n", rand());
}

And the python script to get the flag:

#!/usr/bin/env python2
from struct import pack

password = ""

password += pack('<I', (6833993 + 0x55EB052A) & 0xffffffff)
password += pack('<I', (1732044087 + 0x0EF76C39)& 0xffffffff)
password += pack('<I', (2068121063 + 0xCC1E2D64)& 0xffffffff)
password += pack('<I', (1889579618 + 0xC7B6C6F5)& 0xffffffff)
password += pack('<I', (869606716 + 0x26941BFA)& 0xffffffff)
password += pack('<I', (1364883061 + 0x260CF0F3)& 0xffffffff)
password += pack('<I', (1500347741 + 0x10D4CAEF)& 0xffffffff)
password += pack('<I', (2094174281 + 0x0C666E824)& 0xffffffff)
password += pack('<I', (1508322742 + 0x0FC89459C)& 0xffffffff)
password += pack('<I', (1179934733 + 0x2413073A)& 0xffffffff)
print password

Using the username and password gave us the flag:

-> $ ./catalyst
 ▄▄▄▄▄▄▄▄▄▄▄  ▄            ▄▄▄▄▄▄▄▄▄▄▄  ▄       ▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄ 
▐░░░░░░░░░░░▌▐░▌          ▐░░░░░░░░░░░▌▐░▌     ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌
▐░█▀▀▀▀▀▀▀█░▌▐░▌          ▐░█▀▀▀▀▀▀▀▀▀  ▐░▌   ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀  ▀▀▀▀█░█▀▀▀▀ ▐░█▀▀▀▀▀▀▀▀▀ 
▐░▌       ▐░▌▐░▌          ▐░▌            ▐░▌ ▐░▌  ▐░▌               ▐░▌     ▐░▌          
▐░█▄▄▄▄▄▄▄█░▌▐░▌          ▐░█▄▄▄▄▄▄▄▄▄    ▐░▐░▌   ▐░▌               ▐░▌     ▐░█▄▄▄▄▄▄▄▄▄ 
▐░░░░░░░░░░░▌▐░▌          ▐░░░░░░░░░░░▌    ▐░▌    ▐░▌               ▐░▌     ▐░░░░░░░░░░░▌
▐░█▀▀▀▀▀▀▀█░▌▐░▌          ▐░█▀▀▀▀▀▀▀▀▀    ▐░▌░▌   ▐░▌               ▐░▌     ▐░█▀▀▀▀▀▀▀▀▀ 
▐░▌       ▐░▌▐░▌          ▐░▌            ▐░▌ ▐░▌  ▐░▌               ▐░▌     ▐░▌          
▐░▌       ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄▄▄  ▐░▌   ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄      ▐░▌     ▐░▌          
▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌     ▐░▌▐░░░░░░░░░░░▌     ▐░▌     ▐░▌          
 ▀         ▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀       ▀  ▀▀▀▀▀▀▀▀▀▀▀       ▀       ▀           
Welcome to Catalyst systems
Loading
Username: catalyst_ceo
Password: sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj
Logging in
your flag is: ALEXCTF{1_t41d_y0u_y0u_ar3__gr34t__reverser__s33}

The flag was: ALEXCTF{1_t41d_y0u_y0u_ar3__gr34t__reverser__s33}

Challenges resources are available in the resources folder

Written on February 4, 2017