Pentest Cyprus 3.0

In October 8, there was a PentestCyprus 3.0, a CTF competition in Larnaca, where I participated and won it.
There were total 25 tasks in 6 categories: Web, Cryptography, Forensics, Reverse Engineering, PWN and Miscellaneous. First, I will tell about tasks I’ve managed to do in 3 hours of contest. If I will have free time, I will try to solve the rest and publish solutions to them.

All puzzles are still available online, you just have to register.

This Kraftwerk concert mix helped me a lot to be concentrated:

loginat0r [Web, Easy]

We need to find a way to login to this website. It belongs to a Dark Army contact that we need to track.
Simple HTML form with only password field is not something interesting. But after looking into source code, reference to «js/login.js» script was revealed, with such code:

function login(){
    var password = document.getElementById("password").value;
	if (password == eval(unescape('%53%74%72%69%6e%67%2e%66%72%6f%6d%43%68%61%72%43%6f%64%65%28%31%30%30%2c%35%32%2c%31%31%34%2c%31%30%37%2c%39%35%2c%35%32%2c%31%31%34%2c%31%30%39%2c%31%32%31%2c%39%35%2c%31%31%39%2c%34%39%2c%31%30%38%2c%31%30%38%2c%39%35%2c%39%39%2c%34%38%2c%31%31%30%2c%31%31%35%2c%31%31%37%2c%31%30%39%2c%35%31%2c%39%35%2c%31%32%31%2c%31%31%31%2c%38%35%29'))) {
        alert('Logged In');

After executing the code eval(unescape(...)) in the JS console, we got the answer: d4rk_4rmy_w1ll_c0nsum3_yoU

th3_r3p0 [Web, Easy]

Michael Hansen maintained a website to find and date women that Elliot previously deleted. It appears the site is back up and has employed some ways to keep it up.
Visiting the URL shows such text: Even if you delete everything again I have it stored in a self hosted code repository this time.
r3p0 in the task name and self hosted code repository hints to some version control system, maybe Git? Indeed, if we open, the git repo is here. I’ve downloaded all the files, but the only one needed was COMMIT_EDITMSG with the answer: pency_3{rep0_0n_s3rver_h1story}

r3c_data [Cryptography, Easy]

We have seen this data flowing around but we do not know what is in it.

From the first sight, the file looks like Base64-encoded file. If we decode it, again it will look like Base64-file, but this time smaller. By applying base64 -d several times, we’ve got the answer: pency_3{h1d3_1n_recurs1on_of_64}

h4lf_h4lf [Forensics, Easy]

E-Corp is trying to obfuscated their communications but we know there is something valuable in there.

pcap extension means it is the tcpdump capture file. Wireshark is very convenient tool to deal with it. There are lot of ways to begin the search (I started with simple grep pency), but eventually the correct answer was found using this Wireshark filter udp.port==1921 or tcp.port==1921: pency_3{spl1t_iN_tW0_h4lv3s}

cl3ar_keys [Forensics, Easy]

We hijacked some traffic from an E-Corp employee logging in but although it is clear text something is wrong because we cannot login.

Again, we have pcap file. Inside there is only one TCP session, plaintext of which can be seen via menu Analyze → Follow → TCP Stream:

The only difficulty which remains, is that «0a» means Enter, and «7f» means delete key, so we’ve ended up with login angel@ and password p4l!@45345.

urg3nt_c4ll [Forensics, Hard]

There is some hidden communication in TCP packets that points to the FBI.

This one seems not so hard for me, but gave me crucial 300 points. Again, if we open this file with Wireshark, we can see that in some TCP packets there is highlighted field «Urgent pointer», which matches with task name:

If we collect byte values of that urgent pointer and convert them to ASCII, we receive the answer: pency_3{h1d3_in_pl41n_s1ght}

byt3cod3 [Reverse Engineering, Easy]

We have gained access to some code run by a firewall on a forgotten system on E-Corp site. Reverse it and see what is going on.

file utility tells us that the file is compiled Python 2.7 binary. We can reverse it by using, for example, zrax/pycdc. The reversed source code is follows:

def check_password(to_check):
    password = "urtwt'tqu{w$qqu uqqqtquptwuvw$qst'w$uvtzqqw$tpu{uvqqtqqrtvtwu&"
    key_ints = []
    for ch in password:
        key_ints.append(chr((ord(ch) ^ 66) & 255))

    key = ''.join(key_ints)
    print key
    if to_check == key:
        return True
    return None

The meaning is rather simple: one just XORing input bytes with 66 (0x42). It is known, that XOR operation is symmetric: A^B^B = A. Therefore, to decipher the text, we should also make XOR with 66:


Now it seems rather obvious that we should group hex-digits by two and convert them to ASCII:

    for ch in password:
        key_ints.append(chr((ord(ch) ^ 66) & 255))
        print(chr((ord(ch) ^ 66) & 255)),
    print ''.join([chr(int(i+j,16)) for i,j in zip(key_ints[::2], key_ints[1::2])])

The answer is pency_3{s3cret_1n_th3_byt3c0de}

g1deon_order [Reverse Engineering, Medium]

Access is required to Gideons PC. We know that he uses one of his favourite phrases as password but don’t know which.

I found that one easy, yet it gave 150 points. By running strings on the executable, we found list of strings which looks like passwords:


I wrote simple script which tries all of these passwords:

for PASS in $(<list.txt); do
  echo -e "$PASS\t" ; echo -ne "$PASS" | ./g1deon_order

And one of the passwords lead to segmentation fault. It is Jack_of_All_Trades_Master_of_None
Trying it remotely via nc, I’ve got the flag: pency_3{g1deon_godd4ard_1s_Nonesafe}

pr0pagand4 [Miscellaneous, Easy]

Romero might have passed away but he sent us this email before he died. Probably has some information we require.

This is the animated GIF with 5 frames. By splitting GIF into frames (for example, with ffmpeg), we can see answer on top of 3rd frame written in dark letters over black background: pency_3{d3v1l+is_in_th3_d3t4ils}

s0und_0f_s1lenc3 [Miscellaneous, Medium]

We received a new message from Darlene. Can you hear this?

At first, I opened this file with Audacity to detect something unusual in frequency patterns, but the solution was much simpler. One-liner strings s0und_0f_s1lenc3.mp3 | grep pency gives us the answer: pency_3{Mu5iK_mUs1k_3veRyWHeR3}

This amount of solved tasks was enough to get 1st place in PentestCyprus 3.0 competiton:

Below are puzzles that I solved after the competition:

f0rest [Miscellaneous, Medium]

Eliot found this code left for him from Mr. Robot. We need to discover what it means.
Hint: Huffman was lost in a forest full of trees. Some of them were binary.

Hint points to Huffman binary trees. It is depicted in the SVG file. Using it, we can make lookup table for different symbols in leaves of Huffman tree:

E - 000
0 - 001
7 - 01000
F - 01001
D - 01010
5 - 010110
B - 010111
1 - 0110
2 - 0111
9 - 100
8 - 1010
C - 10110
A - 10111
4 - 110
3 - 1110
6 - 1111

Then we can convert input binary string using simple Python script:

# contents of f0rest.txt
s = '01011011...'

lookup = {
'000': 'e',
'001': '0',
'01000': '7',
'01001': 'f',
'01010': 'd',
'010110': '5',
'010111': 'b',
'0110': '1',
'0111': '2',
'100': '9',
'1010': '8',
'10110': 'c',
'10111': 'a',
'110': '4',
'1110': '3',
'1111': '6',

word = ''
output = ''

while len(s) > 0:
    c, s = s[0], s[1:]
    word = word + c
    if word in lookup:
        output = output + lookup[word]
        word = ''


We got the string 54686520776f726c6420697473656c662773206a757374206f6e652062696720686f61782e, which means «The world itself’s just one big hoax.» when converted to ASCII. By entering this string into netcat socket, we got the answer: pency_3{such_4_hug3_t4sk_w1th_trees}

rsa_tr0ubl3s [Cryptography, Hard]

We managed to intercept the algorithm of communication of E-Corp employees with the main server. Our contacts tell us that this runs from a default user account in a forgotten server. Can you take a look?
This code utilizes some functions from pycrypto library. Sample of code to make signature using pycrypto can be found here, for example: cevaris/e003cdeac4499d225f06. So, we’re adding this code to the original file:

---	2017-10-10 20:57:31.948395491 +0300
+++	2017-10-11 11:57:18.217181622 +0300
@@ -52,6 +52,11 @@
     digest = 
+    sig = signer.sign(digest)
+    signature2 = base64.b64encode(sig)
+    print(signature2)
     if signer.verify(digest, base64.b64decode(signature)):
         return True

If we try to run this script locally, it gives us some signature, but remote system does not accept it. By looking deeper in the source code, I found this code:


Seems like process UID is used as seed for generating of RSA key. Hint in the puzzle description «default user account» points that remote process could be run with root privileges (UID 0). By running the same process locally with root privileges, we got the correct signature WtuqKJOuhn59PGGKN3yMHc3N44t3N9G3tgUH84W7WCvSp7cgmZaHxXjuERRTLwDMVx1LRNBPV1jDbytf6GqH+BHgsPLPNISnKxBqRkie6SpI14NATH6cNlb//1JzE9cmgU7NPBc0rbC1AaP3AUWqQXW8kquPfw4Qmg6j33+f+SOGVIRXqLYcoK5dHyadcbs+KLOeyROixX+45l/xbTmM+/TkeF929wVZx6k27qVoaW7Y5eigHPBgbk9zysBnjc4c and the flag from remote system: pency_3{r4nd0mness_sh0uld_b3_s3cure}

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *