AlexCTF 2017
We solved 9 challenges in this CTF.
- RE1: Gifted
- CR1: Ultracoded
- CR2: Many time secrets
- Fore1: Hit the core
- SC1: Math bot
- TR1: Hello there
- TR2: SSL 0day
- TR3: CA
- TR4: Doesn’t our logo look cool
Gifted
The challenge is simply a link to an ELF binary. After downloading the binary, I ran strings
to look for anything interesting.
$ strings gifted
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
exit
...
[^_]
AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}
Enter the flag:
You got it right dude!
Try harder!
;*2$"
...
The flag is quickly found as a plaintext string in the binary. For further investigation, I disassembled the binary in radare2. The flag is being pushed as a string onto the stack just before the call to strcmp
.
The flag is AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}.
Ultracoded
Fady didn’t understand well the difference between encryption and encoding, so instead of encrypting some secret message to pass to his friend, he encoded it!
Hint: Fady’s encoding doens’t handly any special character
zero_one
zero_one
is a text file containing only the words ZERO
and ONE
in some kind of repeating pattern. I figured this must be converted into a binary representation, so I wrote a small python script.
#!/usr/bin/python2.7
import binascii
import base64
data = open("zero_one").read()
dataArr = data.split()
binaryBuffer = ""
for w in dataArr:
if "ZERO" in w:
binaryBuffer += "0"
if "ONE" in w:
binaryBuffer += "1"
I converted the buffer string to an integer and used binascii.unhexlify
to return the ASCII plaintext.
n = int(binaryBuffer, 2)
binDecoded = binascii.unhexlify('%x' % n)
Printing binDecoded
reveals a base64-encoded string.
Li0gLi0uLiAuIC0uLi0gLS4tLiAtIC4uLS4gLSAuLi4uIC4tLS0tIC4uLi4uIC0tLSAuLS0tLSAuLi4gLS0tIC4uLi4uIC4uLSAuLS0uIC4uLi0tIC4tLiAtLS0gLi4uLi4gLiAtLi0uIC4tLiAuLi4tLSAtIC0tLSAtIC0uLi0gLQ==
Let’s decode it!
base64Decoded = base64.b64decode(binDecoded)
Printing this output produces something resembling morse code.
.- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -
I couldn’t find a library to decode morse code, so I built the decoded string from a python dictionary.
CODE = {'.-': 'A', '-...': 'B', '-.-.': 'C',
'-..': 'D', '.': 'E', '..-.': 'F',
'--.': 'G', '....': 'H', '..': 'I',
'.---': 'J', '-.-': 'K', '.-..': 'L',
'--': 'M', '-.': 'N', '---': 'O',
'.--.': 'P', '--.-': 'Q', '.-.': 'R',
'...': 'S', '-': 'T', '..-': 'U',
'...-': 'V', '.--': 'W', '-..-': 'X',
'-.--': 'Y', '--..': 'Z',
'-----': '0', '.----': '1', '..---': '2',
'...--': '3', '....-': '4', '.....': '5',
'-....': '6', '--...': '7', '---..': '8',
'----.': '9'
}
morseDecoded = ''.join(CODE.get(i) for i in base64Decoded.split())
Printing this output gave me something closely resembling the flag format.
ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT
The hint in the challenge description mentioned that special characters weren’t handled. After some experimentation, I determined that the O’s were underscores and that the curly brackets were simply missing. Here’s the final part of the python script.
morseList = list(morseDecoded.lower())
alexCTF = ''.join(morseList[0:7])
flag = ""
for l in morseList[7:]:
if "o" in l:
flag += "_"
else:
flag += l
print "The flag is: " + alexCTF + "{" + flag + "}"
This yields the flag.
The flag is: alexctf{th15_1s_5up3r_5ecr3t_txt}
Many time secrets
This time Fady learned from his old mistake and decided to use onetime pad as his encryption technique, but he never knew why people call it one time pad!
msg
The challenge description states that Fady is using OTP encryption. As the name implies, the secret key in OTP encryption can only be used once, otherwise the complete key and plaintext can be recovered using a many time pad attack (aka crib drag). Assuming that each line in the msg
file is a line of text encrypted with the same OTP key, we can begin the crib drag by xor-ing 2 lines together and guessing possible letters.
I used the cribdrag tool from SpiderLabs to recover the plaintext.
$ python xorstrings.py 0529242a631234122d2b36697f13272c207f2021283a6b0c7908 2f28202a302029142c653f3c7f2a2636273e3f2d653e25217908
2a01040053321d06014e09550039011a07411f0c4d044e2d0000
$ python cribdrag.py 2a01040053321d06014e09550039011a07411f0c4d044e2d0000
Your message is currently:
0 __________________________
Your key is currently:
0 __________________________
Please enter your crib:
After a couple dozen guesses, I was able to decrypt the message as such.
Your message is currently:
0 Dear Friend, This time I u
Your key is currently:
0 nderstood my mistake and u
Please enter your crib:
Now that we have some plaintext, we can recover the key by simply xoring a plaintext string together with it’s corresponding ciphertext. This can be done by modifying xorstrings.py
slightly.
s1 = "0529242a631234122d2b36697f13272c207f2021283a6b0c7908".decode('hex')
s2 = "Dear Friend, This time I u"
s3 = sxor(s1, s2)
print s3
Running the modified xorstring.py
script produces the flag: ALEXCTF{HERE_GOES_THE_KEY}.
Hit the core
Running the ‘strings’ command against the downloaded file gives a bunch of random-looking output, but one line in particular stands out.
$ strings fore1.core
CORE
code
./code
...
AWAVA
AUATL
[]A\A]A^A_
cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmkogooyf0vbnk0ii87Drfgh_n kiwutfb0ghk9ro987k5tfb_hjiouo087ptfcv}
;*3$"
(q9e
...
Judging by the curly brackets in one of the lines, I figured the flag might be extracted from this. Upon closer inspection it becomes clear that every fifth character starting from the first A spells ALEXCTF, perhaps this correlation continues throughout? I wrote a python script to check.
#!/usr/bin/python2.7
data = "cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmkogooyf0vbnk0ii87Drfgh_n kiwutfb0ghk9ro987k5tfb_hjiouo087ptfcv}"
flag = ""
for i in range(len(data)):
if (i-3)%5 == 0:
flag += data[i]
else:
continue
print flag
Sure enough the flag is returned: ALEXCTF{K33P_7H3_g00D_w0rk_up}.
Math bot
It is well known that computers can do tedious math faster than humans.
nc 195.154.53.62 1337
$ nc 195.154.53.62 1337
__________
______/ ________ \______
_/ ____________ \_
_/____________ ____________\_
/ ___________ \ / ___________ \
/ /XXXXXXXXXXX\ \/ /XXXXXXXXXXX\ \
/ /############/ \############\ \
| \XXXXXXXXXXX/ _ _ \XXXXXXXXXXX/ |
__|\_____ ___ // \\ ___ _____/|__
[_ \ \ X X / / _]
__| \ \ / / |__
[____ \ \ \ ____________ / / / ____]
\ \ \ \/||.||.||.||.||\/ / / /
\_ \ \ ||.||.||.||.|| / / _/
\ \ ||.||.||.||.|| / /
\_ ||_||_||_||_|| _/
\ ........ /
\________________/
Our system system has detected human traffic from your IP!
Please prove you are a bot
Question 1 :
50489238639188063698070072981610 * 1364107478925961178712787264169 =
I reconnected a few times to confirm that the server handed out random equations to be solved. After solving one manually, I was prompted with a new math problem. At this point, I wrote a python script to automate the process.
#!/usr/bin/python2.7
import socket
host = '195.154.53.62'
port = 1337
bot = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bot.connect((host,port))
while True:
data = bot.recv(1024)
if "=" in str.split(data)[-1]:
equation = str.split(data)[-4] + " " + str.split(data)[-3] + " " + str.split(data)[-2]
print "Solving equation..."
print equation
result = repr(eval(equation))
print "Sending result..."
bot.send(result + "\n")
else:
print data
break
Running the script returns the flag after a few seconds.
Solving equation...
77570593763924035994006787070091 * 156048715378978225422935000952364
Sending result...
Well no human got time to solve 500 ridiculous math challenges
Congrats MR bot!
Tell your human operator flag is: ALEXCTF{1_4M_l33t_b0t}
Hello there
Why not drop us a few lines and say hi :).
Upon connecting to the AlexCTF IRC channel, the banner displayed the flag in plaintext.
The flag is ALEXCTF{W3_w15h_y0u_g00d_luck}.
SSL 0day
It lead to memory leakage between servers and clients rending large number of private keys accessible. (one word)
The answer is the Heartbleed vulnerability (CVE-2014-0160).
The flag is Heartbleed.
CA
What is the CA that issued Alexctf https certificate (flag is lowercase with no spaces)
Inspect the CA certificate in Firefox.
The flag is letsencrypt.
Doesn’t our logo look cool
Doesn’t our logo look cool?
Take a closer look at the logo of AlexCTF on the front page.
The flag is hidden in plain sight.
It would be possible to use a python script or even sed
to extract the flag, but you can also do it by hand.
The flag is ALEXCTF{0UR_L0G0_R0CKS}.