Wednesday, September 25, 2019

InCTF 2019 - s3cur3-r3v

Description

Hello, can you reverse this object code for me ??? I would be thankfull to you.

challenge.html

s3cur3-r3v.png

Solution

After googling some of the code, we learned that it corresponds to a series of PHP opcodes for some program. We tried to understand it by rewriting the original program with help from an online PHP shell. The shell we used from 3v4l.org provides VLD output (the PHP disassembly for our code), so we realized we could use it to prototype our code and compare the opcodes to the original program.

After some time, our code looked like this:

<?php
function printflag($input) {
    $success = "Yayyyy, Here's your flag:";
    $fail = "Naay try harder !!!";
    
    global $flag;
    
    $alphabet = "";
    for ($i = 32; $i < 97; $i++) {
        $alphabet .= chr($i);
    }

    echo "Alphabet| " . $alphabet . "\n";

    if (strlen($input) % 4 != 0) {
        exit("BAD INPUT\n");
    }
    
    $aux = strlen($input)*3/4;
    if (0 < strrpos($input, "`")) {
        $idx = strlen($input) - strrpos($input, "`");
    } else {
        $idx = 0;
    }

    $code = array();
    $code[0] = $aux - $idx;
    
    $input_arr = str_split($input);

    for ($i = 0, $x = 0, $pos = array(); $i < count($input_arr); $i += 4) {
        $pos[0] = strpos($alphabet, $input_arr[$i]);
        $pos[1] = strpos($alphabet, $input_arr[$i+1]);
        $pos[2] = strpos($alphabet, $input_arr[$i+2]);
        $pos[3] = strpos($alphabet, $input_arr[$i+3]);

        $code[$x++] = ($pos[0] << 2) | ($pos[1] >> 4);
        if ($pos[2] < 64) {
            $code[$x++] = ($pos[1] << 4) | ($pos[2] >> 2);
            if ($pos[3] < 64) {
                $code[$x++] = ($pos[2] << 6) | $pos[3];
            }
        }
    }

    $encoded_input = '';
    for ($i = 0; $i < count($code); $i++) {
        $encoded_input .= chr($code[$i]);
    }
    
    $encoded_answer = 'YtPEU%10E%24%19%5DV%11UE%92E%04%D8%5De%99%5D5RQ%25SAU%98YuVU%16%10e%85%D1I%96%13Y%96%17M%85%D6E%85%D6Q%04V';
    echo $encoded_input . "\n";

    if ($encoded_input === $encoded_answer) {
        echo $success . $flag . "\n";
    } else {
        echo $fail . "\n";
    }
}

if (isset($_GET['flag']))
    printflag($_GET['flag']);
?>

Although parts of it seemed weird (such as lines 20 to 27), the main loop gave us many insights about what was going on there. For each block of 4 bytes (a,b,c,d) of input, the code encodes the bytes as their indexes in the alphabet, which are numbers from 0 to 63, and then stores each index in $code. The trick is that, since numbers from 0 to 63 take up 6 bits only, (a,b,c,d) can be stored in 24 bits (3 bytes), and that’s exactly what the code does, storing each block of 4 bytes in 3 bytes of $code using some bit magic. It’s a very basic encoding scheme which looks a lot like base64 with a custom alphabet.

To decode it we wrote this script:

from binascii import hexlify

k = "YtPEU\x10E\x24\x19\x5DV\x11UE\x92E\x04\xD8\x5De\x99\x5D5RQ\x25SAU\x98YuVU\x16\x10e\x85\xD1I\x96\x13Y\x96\x17M\x85\xD6E\x85\xD6Q\x04V"
b = bin(int(hexlify(k), 16))[2:]
if len(b) % 8 != 0:
    b = '0' * (8 - (len(b) % 8)) + b

alpha = [chr(i) for i in range(32, 98)]

s = ''
for x in range(6, len(b)+1, 6):
    bp = b[x-6:x]
    s += alpha[int(bp, 2)]

print(s)

The code outputs 671015401209758154621038766973524253056867565180987129836987387618764016, which is a very suspicious value, because all characters are numbers, which is unlikely to happen at random (although we didn’t realize this at first).

Then we opened http://3.15.186.35/?flag=671015401209758154621038766973524253056867565180987129836987387618764016 and our flag was at the bottom of the page: inctf{d1d_y0u_n0t_f1nd_th3_b453_64_3ncrypt10n_s000000_3asy}

Special thanks to Diogenes “diofeher”, Alisson “Infektion” and Daniel “dapolinario” for all their work =)

Capture the Flag , Reverse Engineering , Web , Writeup