Hack In Paris Challenge 1¶
The challenge began on Friday December, 18th 2015, with a tweet:
#HIPChall Number 1 : http://bit.ly/1YpnZnB
A Throwing Star LAN Tap and Two #HIPGoldenTickets to win!
Be the first, Be Fair play, Have Fun!
This tweet indicates a web site, https://hackinparis.com/data/chall2016/, which only contains a PNG image, https://hackinparis.com/data/chall2016/chall1.png:

Wireshark reveals an unknown section named vGNr
, containing:
ixeas://yddotyprujw.nzm/udue/nsaco2016/ef7118o5-p1au-49g0-84f7-3850h4n21210.mie
This looks like an URL encrypted using a Vigenère cipher.
By supposing the URL to begin with https://hackinparis.com/
, it is very easy to find the encryption key.
This can be accomplished for example with such a Python script.
#!/usr/bin/env python3
# Encrypted data from the PNG image
TEXT = b'ixeas://yddotyprujw.nzm/udue/nsaco2016/ef7118o5-p1au-49g0-84f7-3850h4n21210.mie'
# Begin of the clear text
BEGIN = b'httpshackinpariscom'
STRIPPEDTEXT = [c for c in TEXT if ord('a') <= c <= ord('z')]
KEY = [(STRIPPEDTEXT[i] - BEGIN[i] + 26) % 26 for i in range(len(BEGIN))]
# Show key: bellardbellardbella -> bellard
print('Key is: ' + ''.join(chr(ord('a') + k) for k in KEY))
KEY = KEY[:len('bellard')]
decrypted = []
pos = 0
for c in TEXT:
if ord('a') <= c <= ord('z'):
d = ((c - ord('a') - KEY[pos % len(KEY)] + 260) % 26) + ord('a')
pos += 1
else:
d = c
decrypted.append(d)
print('decrypted: ' + ''.join(chr(x) for x in decrypted))
The encryption key is bellard
and the decrypted URL https://hackinparis.com/data/chall2016/db7118d5-e1ad-49d0-84e7-3850d4c21210.bin.
Here is the output of some commands:
$ file db7118d5-e1ad-49d0-84e7-3850d4c21210.bin
db7118d5-e1ad-49d0-84e7-3850d4c21210.bin: BPG (Better Portable Graphics)
$ strings -tx -7 db7118d5-e1ad-49d0-84e7-3850d4c21210.bin
151 RUItUEMtQ0lEQ0JFiesabi46
222 __main__s
24e structR
28e __name__t
29b decodet
2ac raw_inputt
2cb encode(
2ee <module>
85e #Fr 3/J
922 %%o\;Sb
So the file is a BPG image with some Python code embedded. Using the specification (http://bellard.org/bpg/bpg_spec.txt), here is the decode header:
Offset Hex data Field name Description
------ ---------- -------------------------- ------------
0 425047fb file_magic "BPG\xfb"
4 20 pixel_format (3 bits) 1: 4:2:0. Chroma at position (0.5, 0.5) (JPEG chroma position)
alpha1_flag (1) 0: no alpha plane
bit_depth_minus_8 (4) 0: bit depth is 8
5 08 color_space (4) 0
extension_present_flag (1) 1: there is extension data
alpha2_flag (1) 0
limited_range_flag (1) 0
animation_flag (1) 0
6 8310 picture_width Width 0x190 = 400
8 8240 picture_height Height 0x140 = 320
a 00 picture_data_length
b 8616 extension_data_length Extension data Length = 0x316
d 00 first extension_tag
e 8613 first extension_tag_length First tag length = 0x313 = 787
Let’s extract the extension tag, which is 787 bytes from offset 0x10:
$ dd if=db7118d5-e1ad-49d0-84e7-3850d4c21210.bin of=bpgdata.bin skip=16 count=787 bs=1
787+0 records in
787+0 records out
787 bytes copied, 0.00316447 s, 249 kB/s
$ file bpgdata.bin
bpgdata.bin: python 2.7 byte-compiled
Using uncompyle2 (https://github.com/wibiti/uncompyle2) leads to the following Python code:
#Embedded file name: _.py
import sys
from struct import pack
A = 'RUItUEMtQ0lEQ0JF'
B = 1650553701
C = 13876
D = '\xd5\x81\xd4m\x84\xf3\x84\x99\xf4\xf3\x82m\xf7\x99\xf4\x94\xa2m\x99\x85\x88\xa3\xf0\x95\xc1'
E = '\xc3\x96\x95\x87\x99\x81\xa3\xa9k@\x95\x96\xa6@\xa2\x85\x95\x84@\xa3\x88\x89\xa2@\x97\x81\xa2\xa2\xa6\x96\x99\x84@\xa3\x96z@\x94\x85\x99\x85\x95\xa6\x85\x95@`\x81\xa3`@\x88\x81\x83\x92\x89\x95\x97\x81\x99\x89\xa2@`\x84\x96\xa3`@\x83\x96\x94@O'
F = '\xd5\x96\x97\x85'
G = 'LLL@\xc8\x81\x83\x92\xc9\x95\xd7\x81\x99\x89\xa2@\xf2\xf0\xf1\xf6@`@\xc3\x88\x81\x93\x93@\xf1@nnn'
H = '\xc5\x95\xa3\x85\x99@\x97\x81\xa2\xa2\xa6\x96\x99\x84z@'
if __name__ == '__main__':
I = A.decode(pack('>IH', B, C))[::-1]
print G.decode(I)
print ''
code = raw_input(H.decode(I))
if len(code) > 0:
if code.encode(I) == D[::-1]:
print E.decode(I)
else:
print F.decode(I)
Adding some print statements allows to quickly discover the content of variables:
pack('>IH', B, C) = 'base64'
I = 'EBCDIC-CP-BE'
G.decode(I) = '<<< HackInParis 2016 - Chall 1 >>>'
H.decode(I) = 'Enter password: '
E.decode(I) = 'Congratz, now send this password to: merenwen -at- hackinparis -dot- com !'
F.decode(I) = 'Nope'
D[::-1].decode(I) = 'An0ther_sm4r7_b34rd3d_MaN'
The flag of the first challenge is thus: An0ther_sm4r7_b34rd3d_MaN