Ritsec 2019
Crypto
pre-legend - 100 points
9EEADi^^8:E9F3]4@>^4=2J32==^D@>6E9:?8\FD67F=\C:ED64
This is a ROT47 encoded string, just decode it to get the flag:
$ tr '\!-~' 'P-~\!-O' <<< "9EEADi^^8:E9F3]4@>^4=2J32==^D@>6E9:?8\FD67F=\C:ED64"
https://github.com/clayball/something-useful-ritsec
At first, I went to the repository to find what's in it, but then I read in the discord group that the flag was the link itself.
shiny - 100 points
.‡8]5);483‡5;
gold-bug.jfif
This challenge is a quote to The Gold Bug, a short story by Edgar Allan Poe, in which a substitution cipher lead the protagonist to an adventure. We can use dcode.fr to decode the given string.
Flag
RITSEC{POEWASTHEGOAT}
Stego
HD Pepe - 300 points
Pepe is alpha tier
Running exiftool on the image gives us some interesting information: {{< highlight text "hl_lines=22 28" >}} $ exiftool ctf_pepe.png ExifTool Version Number : 11.75 File Name : ctf_pepe.png Directory : . File Size : 10 MB File Modification Date/Time : 2019:11:18 06:47:33-08:00 File Access Date/Time : 2019:11:18 06:48:12-08:00 File Inode Change Date/Time : 2019:11:18 06:47:39-08:00 File Permissions : rw-r--r-- File Type : PNG File Type Extension : png MIME Type : image/png Image Width : 4500 Image Height : 4334 Bit Depth : 8 Color Type : RGB with Alpha Compression : Deflate/Inflate Filter : Adaptive Interlace : Noninterlaced Warning : [minor] Text chunk(s) found after PNG IDAT (may be ignored by some readers) Exif Byte Order : Big-endian (Motorola, MM) Image Description : gh:cyberme69420/hdpepe Resolution Unit : inches Artist : degenerat3 Y Cb Cr Positioning : Centered Exif Version : 0231 Components Configuration : Y, Cb, Cr, - User Comment : version control hehe Flashpix Version : 0100 GPS Latitude Ref : North GPS Longitude Ref : East Image Size : 4500x4334 Megapixels : 19.5 GPS Latitude : 39 deg 1' 10.11" N GPS Longitude : 125 deg 45' 12.20" E GPS Position : 39 deg 1' 10.11" N, 125 deg 45' 12.20" E {{< /highlight >}}
The User Comment field says something about version control, and the Image Description field looks like a Github repository, which indeed it is. It contains a python script that uses the alpha channel of an image to encode data in it, these are the functions:
def readBin(fname):
f = open(fname, "rb")
fstr = base64.b64encode(f.read())
fdec = fstr.decode('utf-8')
return fdec
def generateAValues(b64str):
numArr = []
for ch in b64str:
val = ord(ch)
n = 255 - val
numArr.append(n)
return numArr
def readImage(inputImg, encFile, outputImg):
im = Image.open(inputImg) # Can be many different formats.
pix = im.load()
print("[+] Reading image...")
x_size, y_size = im.size # Get the width and hight of the image for iterating over
sizeTup = (x_size, y_size)
newImg = Image.new('RGBA', sizeTup)
newPix = newImg.load()
counter = 0
print("[+] Reading target file...")
binStr = readBin(encFile)
print("[+] Generating new alpha values...")
aVals = generateAValues(binStr)
print("[+] Writing new image...")
for x in range(x_size):
for y in range(y_size):
try:
r, g, b, a = pix[x, y]
except:
r, g, b = pix[x, y]
a = 255
if counter >= len(binStr):
newA = a
else:
newA = aVals[counter]
counter += 1
newPix[x, y] = (r, g, b, newA)
print("[+] Saving new image...")
newImg.save(outputImg)
The file that the script embeds in the image is read as a binary file, encoded
in base64 and then every character of the result string gets subtracted from the
value 255
. The resulting list of integers gets used as the value of the alpha
channel of each pixel.
Luckily, the repository contains a script called examiner.py
, which opens an
image and prints the RGBA values of each pixel. We can use it as a foundation
to write a script that decodes the hidden content in an image:
def decodeAValues(num_array):
s = ''
for num in num_array:
val = 255 - num
s += chr(val)
return s
def examine(fname, maxpix):
im = Image.open(fname) # Can be many different formats.
pix = im.load()
x_size, y_size = im.size # Get the width and hight of the image for iterating over
print("X-axis size: " + str(x_size))
print("Y-axis size: " + str(y_size))
num_array = []
counter = 0
for x in range(x_size):
for y in range(y_size):
if str(counter) == maxpix:
return num_array
try:
r, g, b, a = pix[x, y]
except:
r, g, b = pix[x, y]
a = 255
num_array.append(a)
# print("r: {}, g: {}, b: {}, a: {}".format(r, g, b, a))
counter += 1
Simply running it against the given image, gives us the flag:
$ python examiner.py ctf_pepe.png 100
X-axis size: 4500
Y-axis size: 4334
b'RITSEC{M3M3S_CAN_B3_M4LICIOUS}'
Web
misdirection - 100 points
Looks like someone gave you the wrong directions!
http://ctfchallenges.ritsec.club:5000/
Visiting the link with a browser will end up in an infinite redirection. Analyzing the requests with Burp we can read a well defined string by concatenating the paths that we get redirected to:
Flag
RS{4!way5_Ke3p-m0v1ng}
Forensics
Take it to the Cleaners - 100 points
People hide things in images all the time! See if you can find what the artist forgot to take out in this one!
ritsec_logo2.png
With exiftool we can read a base64 encoded string in the User Comment field: {{< highlight text "hl_lines=30" >}} $ exiftool ritsec_logo2.png ExifTool Version Number : 11.75 File Name : ritsec_logo2.png Directory : . File Size : 4.3 kB File Modification Date/Time : 2019:11:18 07:33:08-08:00 File Access Date/Time : 2019:11:18 07:33:09-08:00 File Inode Change Date/Time : 2019:11:18 07:33:08-08:00 File Permissions : rw-r--r-- File Type : PNG File Type Extension : png MIME Type : image/png Image Width : 328 Image Height : 154 Bit Depth : 8 Color Type : Palette Compression : Deflate/Inflate Filter : Adaptive Interlace : Noninterlaced Palette : (Binary data 129 bytes, use -b option to extract) Warning : [minor] Text chunk(s) found after PNG IDAT (may be ignored by some readers) Exif Byte Order : Big-endian (Motorola, MM) Image Description : Hi there! Looks like youre trying to solve the forensic_fails challenge! Good luck! Resolution Unit : inches Artist : Impos73r Y Cb Cr Positioning : Centered Copyright : RITSEC 2018 Exif Version : 0231 Components Configuration : Y, Cb, Cr, - User Comment : RVZHRlJQe1NCRVJBRlZQRl9TTlZZRl9KQkFHX1VSWUNfTEJIX1VSRVJ9 Flashpix Version : 0100 GPS Latitude Ref : North GPS Longitude Ref : West Image Size : 328x154 Megapixels : 0.051 {{< /highlight >}}
Decoding it gives us a string with the same format as the flag:
$ echo RVZHRlJQe1NCRVJBRlZQRl9TTlZZRl9KQkFHX1VSWUNfTEJIX1VSRVJ9 | base64 -d
EVGFRP{SBERAFVPF_SNVYF_JBAG_URYC_LBH_URER}
We can use tr
to perform a rot13 decoding, which is just a Caesar cipher
with 13
as the key:
$ tr 'A-Z' 'N-ZA-M' <<< EVGFRP{SBERAFVPF_SNVYF_JBAG_URYC_LBH_URER}
RITSEC{FORENSICS_FAILS_WONT_HELP_YOU_HERE}
Long Gone - 100 points
That data? No it's long gone. It's basically history
http://us-central-1.ritsec.club/l/chromebin
After downloading the given archive and extracting it with tar -xvf chromebin.tar
, we can see that it's a backup of the user data of the Chrome
browser. Because the challenge description was talking about history, the
immediate thing that came to my mind is to search in the browser history. We can
do so by querying a sqlite3 database:
$ sqlite3 Chrome/User\ Data/Default/History "SELECT * FROM urls WHERE url LIKE '%ritsec%'"
76|https://www.google.com/search?hl=en&biw=673&bih=492&ei=BRnPXf76EKHI_Qb03bqQCg&q=us-central-1.ritsec.club%2Fl%2Frelaxfizzblur&oq=us-central-1.ritsec.club%2Fl%2Frelaxfizzblur&gs_l=psy-ab.3...12572.24888..69087...2.1..1.298.3372.37j4j1......0....1..gws-wiz.......0i71j0i273i70i249j0i273j0j0i67j0i131j38j0i30j0i5i30j0i8i30j0i8i10i30.xUoJ6M10dd8&ved=0ahUKEwi-kaP8lO3lAhUhZN8KHfSuDqIQ4dUDCAs&uact=
5|us-central-1.ritsec.club/l/relaxfizzblur - Google Search|3|0|13218330713643332|0
The second link looks promising, and infact, visiting it, gives us the flag.
Flag
RITSEC{SP00KY_BR0WS3R_H1ST0RY}
Vacation - 100 points
These are my favorite places to visit
http://us-central-1.ritsec.club/l/chromebin
This challenge uses the same archive as before. This time the challenge
description seems to be referring to bookmarks. Chrome stores bookmarks in
Chrome/User Data/Default/Bookmarks
. We can open the file with any editor and
find out that every bookmark has a letter as name and that's the flag, but
that's time consuming and not much efficient. We can instead use jq to parse
the json and get the flag straight:
$ jq -r '.roots.other.children[].name' Bookmarks
R
I
T
S
E
C
{
C
H
R
0
M
3
_
B
M
_
F
T
W
}
findme - 400 points
Find me! Challenge created by Security Risk Advisors for RITSEC CTF
findme.pcap
By analyzing the pcap file with Wireshark, we can see that there are two main streams of data. The interesing one is the number 1, let's check it: It looks like there are two base64 encoded strings. The first one decodes to a link to the Rickroll song, a recurrent thing in this CTF. The second one is where the juice is. It is a gzip archive, so after writing the string in a file let's decode and extract it:
$ base64 -d data | gunzip
flag0000664000175000017500000000006213561713423011345 0ustar ubuntuubuntuRITSEC{pcaps_0r_it_didnt_h@ppen}
CTRL-c to close
And there's our flag!
Misc
Crack me If You Can - 400 points
Rev up your GPUs... nc ctfchallenges.ritsec.club 8080
This was to my surprise, a very easy challenge. After connecting with netcat to
the given host, it gives us NTLM and sha256crypt hashes. It also
suggests three wordlists for cracking the hashes, so I've merged them and piped
into sort -u
to remove duplicates and then we can use hashcat with -m 1000
for NTLM hashes and with -m 1800
for the sha256crypt ones.
$ nc ctfchallenges.ritsec.club 8080
Some moron just breached Meme Corp and decided to dump their passwords...
In the meantime, prepare your GPUs, and get Ready... Set.... and go CRACK!
However... We have a theory that the passwords might come from 500-worst-passwords.txt, darkweb2017-top10000.txt or probable-v2-top12000.txt
$6$yD1KHtTQ1vVU96je$Ff37nC1Xtg5FJcKhlhxQl4IXYdt0gHg8GWyNiyxHht5aYO.r4QG807DAo7PijwQSJIuclPniZ20b3dxAUitga/
energy
Good job.
ade09dd439a3676c6fd07b7e0007d50a
iamthebest
Good job.
$6$A23tnWFnWkfdc..8$/EAkiqPPh3BiP4qoqhBbd36iMNe7iKQzXDT5Q3k/VH2CBlu0tAfeNC1/zGNoCtaqjYblnzSS2Uf3Ff6bTJu8b.
council
Good job.
NICE JOB. FLAG:RS{H@$HM31FY0UCAN}
AlPhAbEtIcAl Challenge - 300 points
59:87:57:51:85:80{:40:50:56:08:82:58:81:08:18:85:57:87:48:85:88:40:50:56:59:15:56:11:18:85:59:51:}
This looks like a substitution cipher, in which every letter gets replaced by another one. There are a plethora of tools to crack them based on dictionaries and letters frequencies, but we need to convert the two digits to a single characters for this tools to work. So I wrote a python script:
import string
alphabet = string.ascii_letters + string.digits
s = '59 87 57 51 85 80 40 50 56 08 82 58 81 08 18 85 57 87 48 85 88 40 50 56 59 15 56 11 18 85 59 51'
converted = ''
d = {}
for symbol in s.split(' '):
if not symbol in d:
d[symbol] = alphabet[len(d)]
converted += d[symbol]
print(converted)
Running it gives us this string abcdefghijklmjnecboepghiaqirnead
which we can
use on quipqiup and set abcdef=ritsec
:
And there's the flag!