Monday, July 24, 2017

Palo Alto Labyrenth Threat 03 Writeup

Labyrenth 2017 Threat 03

Threat 03 is different from all other challenges (except random 6) as it presents us with a website instead of a download

First step I took was to visit the website

and check the source for each page I would find

the source for the main site is given above and contains a suspicious comment


Next steps I took were to try multiple decodings for that string and use all kinds of steg tools on the images which turned out to be a dead end. If you look at the given source you can see a copyright by s. williams.
Next thing I did was a whois on which returned
I googled the email address and found a password dump, so I tried to login into the email account with the given password which obviously didn't work out (I realized it wouldn't make much sense as in everyone could just overtake the account).
I tried other hits and found a linkedin profile that looked promising

The profile contained many hints referring to PAN or labyrinth and also a link to a stackoverflow user which asked one specific question

Having a look at the given python code immediately raised some suspicions. The code contained weird and obvious errors. I cleaned the code and tried the given test parameters

def encrypt(varAble1, varAble2):
    varAble1_size = len(varAble1)/float(len(varAble2))
    if str(varAble1_size).split(".")[1] == "0":
        while str(varAble1_size).split(".")[1] != "0":
            varAble1 += "@"
            varAble1_size = len(varAble1)/float(len(varAble2))
    code = []
    varAble1 = list(varAble1)
    varAble2 = list(varAble2)
    multiply_size = int(str((varAble1_size)).split(".")[0]) * 8
    while varAble1 != []:
        p_varAble1 = varAble1[0:8]
        p_varAble2 = varAble2[0:8]
        temp_list = []
        for i in xrange(0,8):
            if type(p_varAble2[i]) == type(int):
                new_ct = (ord(chr(p_varAble2[i])) ^ ord(p_varAble1[0]))
                    new_ct = (ord(p_varAble2[i]) ^ ord(p_varAble1[0]))
                    new_ct = ((p_varAble2[i]) ^ ord(p_varAble1[0]))
            varAble2 = temp_list
    #varAble1 = code.reverse()
    code_text = []
    for i in code:
        hex_value = hex(i)
        if len(hex_value) != 4:
            code_text.append("0" + hex(i)[2:])
    code_text = "".join(code_text).upper()
    return code_text
I realized that the password parameter is only important for the first 8 bytes of the output, afterwards the result of the last xor calculation is used as the password for the next 8 byte chunk. To revert the operation one can simply xor the last two chunks of the encoded output with each other and repeat that process. To decode the last chunk the user supplied password is required. If n is the last chunk the decryption algorithm is to xor chunk[n] ^ chunk[n-1], chunk[n-1] ^ chuck[n-2] and concatenate the results. Running the following code with the comment from the website and without supplying a password

def decryptor(encoded_text,password=''):
    chunks = [encoded_text[i:i+2] for i in range(0, len(encoded_text), 2)]
    x = len(chunks)
    p_1 = ''
    p_2 = ''
    while(x > 8):
        p_1 = chunks[x-8:x]
        p_2 = chunks[x-16:x-8][::-1]
        temp = ''
        for i in range(0,8):
    if len(password) == 8:
        x = len(chunks)
        p_1 = chunks[x-8:x][::-1]
        temp = ''
        for i in range(0,8):
        res = [temp]+res
    print ''.join(res)



which looks promising. We know that the flag has to start with PAN{ so I calculated the first 4 chars of the password to be baby. I remembered the username of the stackoverflow account was babytoby, calling the function using the password babytoby gives us the flag

No comments:

Post a Comment