reklest

Reverse Engineering – 164pts

Description

In our infrastructure it works perfectly but it takes time

http://reklest.web.jctf.pro

Solution

Attached to this challenge is a executable binary.

file reklest
reklest: Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE|HAS_TLV_DESCRIPTORS>

Opening the binary in IDA and taking a look at the _main function we can find the following block of code.

Here we can see some values being XOR:ed and a base64 string is decoded. Lets find out what the contents of the string is.

__ZN7ryklest4main9OBFSTRING17hc44d85a338dd293eE dq 0A884DF8AB2FBC902h
qword_1000D4398 dq 0E0D28ACBFB46461Ah
qword_1000D43A0 dq 6178F0BE4CD508ACh
qword_1000D43A8 dq 603AD81291B66724h
qword_1000D43B0 dq 0DE5CDDE19279A148h
qword_1000D43B8 dq 70E60361F80E8EB4h

XOR:ing each part with the corresponding values from the mov rax, 0000000000000000h operation we get the string dGhpc19pc192ZXJ5X3MzY3JldF9maWxlMTMzNzEzMzcuanM= and decoding this we get the string this_is_very_s3cret_file13371337.js.

When we download this file from the URL given to us in the description we get obfuscated JavaScript.

var _0x38d9 = ['charCodeAt', '537865HVvFyd', '153402TvesmL', '637814tgMjYr', '191740qwGPgk', 'length', '21541OOTfbk', '2FaFWFo', '4DOGutk', '21qyUBwr', '500024opEyBW', '2669431PGatTv'];
var _0x2b2f = function (_0x20b4d4, _0x6e7ec) {
    _0x20b4d4 = _0x20b4d4 - 0x68;
    var _0x38d9ae = _0x38d9[_0x20b4d4];
    return _0x38d9ae;
};
(function (_0x610c0b, _0x118d97) {
    var _0xdf5613 = _0x2b2f;
    while (!![]) {
        try {
            var _0x51bf5f = parseInt(_0xdf5613(0x72)) + parseInt(_0xdf5613(0x6f)) + -parseInt(_0xdf5613(0x6d)) * -parseInt(_0xdf5613(0x73)) + parseInt(_0xdf5613(0x68)) + -parseInt(_0xdf5613(0x6e)) * -parseInt(_0xdf5613(0x6b)) + parseInt(_0xdf5613(0x6c)) * parseInt(_0xdf5613(0x69)) + -parseInt(_0xdf5613(0x70));
            if (_0x51bf5f === _0x118d97) break;
            else _0x610c0b['push'](_0x610c0b['shift']());
        } catch (_0x41e7a9) {
            _0x610c0b['push'](_0x610c0b['shift']());
        }
    }
}(_0x38d9, 0x6f429), text = '{rewJey\x00bnF\x05B_EnEC\x00RZHnSD\x06nCdbEn]\x01\x01ZBnbR\x05CHL');

function xyz(_0x4821d8, _0x1e7b78) {
    var _0x3cb5de = _0x2b2f,
        _0x342b88 = '';
    for (var _0x2e0312 = 0x0; _0x2e0312 < _0x4821d8[_0x3cb5de(0x6a)]; _0x2e0312++) {
        _0x342b88 += String['fromCharCode'](_0x4821d8[_0x3cb5de(0x71)](_0x2e0312) ^ _0x1e7b78['charCodeAt'](_0x2e0312 % _0x1e7b78[_0x3cb5de(0x6a)]));
    }
    return _0x342b88;
}

Cleaning this up we end up with the following code.

text = '{rewJey\x00bnF\x05B_EnEC\x00RZHnSD\x06nCdbEn]\x01\x01ZBnbR\x05CHL'

function decode(input, key) {
    result = '';
    for (var i = 0x0; i < input.length(); i++) {
        result += String['fromCharCode'](input.charCodeAt(i) ^ key.charCodeAt(i % key.length()));
    }
    return result;
}

Now we can try to find out the key which was used to encode the string, but XOR:ing the start of the string with justCTF doesn’t return the correct key. So we have to try the second thing of the flag that we know of, the last character. XOR:ing the last byte in the string with } gives us the result 0x31. When we XOR the string with this value we get the following JCTF{TH1S_w4snt_tr1cky_bu7_rUSt_l00ks_Sc4ry}.

justCTF{TH1S_w4snt_tr1cky_bu7_rUSt_l00ks_Sc4ry}

That’s not crypto

Reverse Engineering – 50pts

Description

This is very simple RE task, but you may need some other skills as well. 🙂

Solution

For this challenge we get an compiled python script, so we can try to decompile it into readable python code.

# uncompyle6 version 3.7.4
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.8.6 (default, Sep 25 2020, 09:36:53) 
# [GCC 10.2.0]
# Embedded file name: checker.py
# Compiled at: 2021-01-30 16:41:40
# Size of source mod 2**32: 50109 bytes
from random import randint

def make_correct_array(s):
    from itertools import accumulate
    s = map(ord, s)
    s = accumulate(s)
    return [x * 69684751861829721459380039 for x in s]


def validate(a, flag):

    def poly(a, x):
        value = 0
        for ai in a:
            value *= x
            value += ai

        return value

    if len(a) != len(flag) + 1:
        return False
    else:
        for x in flag:
            value = poly(a, x)
            if value != 24196561:
                return False

        return True


if __name__ == '__main__':
    a = [1,
     -12036995612853156936286011036665,
     70761097437137270936102167471287642036368358112612482078746420,
    <REMOVED>     -558796808323730669319556209635783295834885620059919926374094337704783159717074271411836333134523665196320389949347494772111894391675686207325966425834299960704067893587399438455588798256988677645323754039263287748208073986571463630315463528160656994318592529984130595009567451280996658400048531364622161695493916339147237654817684252769754893117909700442127196991419507042220993245901638767780155169618789002876156225189025005435074977599662688324284914356331507363920217213649363265471629867298901042969782051702048331205489077043036293034833278445116394956666071142647788227115267116515688528503660439942039494813585601143257498959633094600747201884245253213502219269954196213677360969825422781823842862748418879041080125872976097659234935939843831969071868329828198543934025101026210448471222980313395095525993255690522050851267688859400798423662402460712473293804031118694749895794657538247539078212884158148374742509871449405839026122122675224588400629340169111504042885900750205878286033379426390866888430718628034165311726393903801759108001438550475452538760373040235963885593125407487287825497248553858899433281347776274390966255070668382409772465963176385751904286316639716489828285928978635855355970747105034388038350319447352538261087880109718552603329805296866567042793649019459534848470724032360639799964633748905196867853384109201940701530483598626465550495679048159865753998874913787925000267970891083136549937685688617570022717038125536572098179693557126646776084768401508922196353445609647520847478177415121380238111178597227153627832257799928795216823511402005832836435952524795942215581962882377976384250201837108076812047801647103999999999995081]
    a = [ai * 4919 for ai in a]
    flag_str = input('flag: ').strip()
    flag = make_correct_array(flag_str)
    if validate(a, flag):
        print('Yes, this is the flag!')
        print(flag_str)
    else:
        print('Incorrect, sorry. :(')
# okay decompiling checker.pyc

So the code does some computations for each character in the input and compares the result with a static value. We should be able to create a script to brute force the correct flag using the algorithm and values.

#!/usr/bin/env python3

a = [1,
     -12036995612853156936286011036665,
     70761097437137270936102167471287642036368358112612482078746420,
     <REMOVED>    -558796808323730669319556209635783295834885620059919926374094337704783159717074271411836333134523665196320389949347494772111894391675686207325966425834299960704067893587399438455588798256988677645323754039263287748208073986571463630315463528160656994318592529984130595009567451280996658400048531364622161695493916339147237654817684252769754893117909700442127196991419507042220993245901638767780155169618789002876156225189025005435074977599662688324284914356331507363920217213649363265471629867298901042969782051702048331205489077043036293034833278445116394956666071142647788227115267116515688528503660439942039494813585601143257498959633094600747201884245253213502219269954196213677360969825422781823842862748418879041080125872976097659234935939843831969071868329828198543934025101026210448471222980313395095525993255690522050851267688859400798423662402460712473293804031118694749895794657538247539078212884158148374742509871449405839026122122675224588400629340169111504042885900750205878286033379426390866888430718628034165311726393903801759108001438550475452538760373040235963885593125407487287825497248553858899433281347776274390966255070668382409772465963176385751904286316639716489828285928978635855355970747105034388038350319447352538261087880109718552603329805296866567042793649019459534848470724032360639799964633748905196867853384109201940701530483598626465550495679048159865753998874913787925000267970891083136549937685688617570022717038125536572098179693557126646776084768401508922196353445609647520847478177415121380238111178597227153627832257799928795216823511402005832836435952524795942215581962882377976384250201837108076812047801647103999999999995081]
a = [ai * 4919 for ai in a]

flag = []

def poly(a, x):
    value = 0
    for ai in a:
        value *= x
        value += ai

    return value == 24196561

acc = 0
for i in range(0, 57):
    c = 0x30
    while(poly(a, ((c + acc) * 69684751861829721459380039)) != True):
        c += 1
    flag.append(chr(c))
    acc += c

print(''.join(flag))

When we run this script we get the flag.

justCTF{this_is_very_simple_flag_afer_so_big_polynomails}