Rating:
Start: Sat, Feb 8 2020, 10:00 AM EST
End: Tue, Feb 11 2020, 7:00 PM EST
This weekend I played in NeverlanCTF as the solo team bosh
. The challenges were alright, although many of them were just guessing.
I didn't like how they did not announce challenge drops before they actually released them, and how the platform went down after the last wave of challenge releases.
Once we unzip with 7z we end up with two files:
description.MD
Adobe_Employee_Payroll.exe
description.MD
hints towards a software called DotPeek.
DotPeek decompiles (read: translates to semi human readable code) .NET files, such as our .exe file. After we open Adobe_Employee_Payroll.exe
up, we can explore the files:
Double clicking on something seems like a good idea. Now we can see the decompiled code for something that looks important:
As you can see,
r1
, r2
, r3
and so (till r38
) on seem to be holding integers. They seem like they're ASCII values... and they are!
Without even looking at the rest of the program, we can find the flag by converting all the values from r1
through r38
to letters.
The "encrypted" encrypted_db
is really just a bunch of base64 strings, which are then encoded using hex.
We can decode by using this script:
from base64 import b64decode
f = open("encrypted_db").read().strip().replace("\n", "").decode("hex")
f = b64decode(f.strip())
print(re.findall(r'flag{.+?}', f))
Running the script gives the flag.
Let's open it up in Ghidra.
We scroll until we find a cool looking function called print
. It seems to be building a string from hex values.
Converting all those from hex to ASCII gives the flag.
Basic substitution cipher, using the pigpen cipher alphabet.
Decrypting gives the flag.
As from the title, the data is not in base 64. We play around with the different encodings in cyberchef.
Noticing that there are only capital letters / symbols in the plaintext, we can probably guess that the base will be relatively small. We try to decode it as a base 32 string, and it works.
Decoding gives the flag.
Another basic substitution cipher, using the Knights Templar Code cipher. Decode.f<span>r</span> has a nice solver.
Decrypting gives the flag.
Yet another basic substitution cipher, using the Arthurs and the Invisibles alphabet. Decode.f<span>r</span> has a nice solver.
Decrypting gives the flag.
Googling Cupid cipher
gives us some results about how James Madison hid his plaintexts in some text using numbers.
When we count the amount of numbers in the ciphertext at the top of the file, we find that it is equal to the amount of rows there are, and the highest number in the ciphertext does not exceed the number of columns :eyes:
We then guess that each row corresponds to a character of the plaintext, and each number in the ciphertext is the corresponding column to pick from.
For example:
The first number in the ciphertext is 6
. The character at the first row, 6th column is V
.
Then, the second number in the ciphertext is 12
. The character at the second row, 12th column is E
.
Continue to get the flag.
We are presented with 16 5x5 grids, each with a single box blacked out. Shot in the dark. We reason that since it is 5x5, there are 25 choices which is close enough to 26 (letters of the alphabet).
We assume the top left represents the letter A, and the next one to the right represents B, and so on.
Doing so, we get MHBDI...
, until we reach the 12th box. There is no marking here! Another shot in the dark. We assume that no marking represents the letter A
.
Thus, our previously transcribed "plaintext" has to be Caesar shifted by 1 to get the flag, easy enough.
Questionable RSA. I didn't know what to do with the numbers since they were spaced out. I finally guessed they were individual characters of the flag and successfully decrypted them as such.
Using factordb, we can factor n
into 17 * 149
, obviously the p and q for this challenge.
Now, using modified code from a StackExchange article, we can decrypt the flag character by character.
# Function from Geeks for Geeks
def modInverse(a, m):
m0 = m, y = 0, x = 1
if (m == 1):
return 0
while (a > 1) :
q = a // m
t = m
m = a % m
a = t
t = y
y = x - q * y
x = t
if (x < 0):
x += m0
return x
def decrypt(ct):
p = 17
q = 149
e = 569
# compute n
n = p * q
# Compute phi(n)
phi = (p - 1) * (q - 1)
# Compute mult mod inv of e
d = modInverse(e, phi)
# Decrypt ciphertext
pt = pow(ct, d, n)
print(chr(pt), end="")
chall = "2193 1745 2164 970 1466 2495 1438 1412 1745 1745 2302 1163 2181 1613 1438 884 2495 2302 2164 2181 884 2302 1703 1924 2302 1801 1412 2495 53 1337 2217".split()
# this is probably bad practice but it works
list(map(lambda x: decrypt(int(x)), chall))
Basically just a bunch of ciphers. Each level has a chal.txt which contains an encrypted password, and a password-protected zip file for the next layer.
Here is the order:
Layer 1 -A ffine Cipher here 3
:
AfvqPZW0bDMB&HTfzo
Layer 2 - Two is better than one
NEVERLANCTF
PASSWORDV78DTNRI6KBD3SDFQXXXXXXXX
V78DTNRI6KBD3SDFQ
Layer 3 - I'm on the fence with this one
password:·VSEAS5aevg8Bwlovr
Layer 4 - Salad Time
neverLANCTF
0
gTLvCGk$HyRVSssXVaSX
Layer 5 - ROTten
13
e1Ydr*zxOOybF6RR%h5f
Layer 6 - Vigenere Equivent E
22
fI7BPZL#ZN5PI!&pbTXc
Layer 7 - Easy one
vxw@Ztet#ZfBnYVxJ1IM
Layer 8 - Message indigestion
password23
Layer 9 - For SHA dude
applez14
Layer 10 - ONE more TIME
This is our world now...
from chal.txt
This is our world now... the world of the electron and the switch, the beauty of the baud. We make use of a service already existing without paying for what could be
We get download the png image. In it is a funky lookin dog with no flag :(
We guess it is LSB encrypted since Binwalk doesn't return anything useful.
We plug it into stylesuxx's LSB tool and we decode.
We get some base64, which we now play with a bunch in CyberChef.
After we base64 decode it twice, we get a bunch of:
lspv wwat kl rljvzfciggvnclzv
Now we guess again and decrypt it using the Variant Beaufort Vigenere cipher
(found on Cryptii's Vigenere tool) and key NeverLANCTF
. The plaintext gives the flag.
You don't even need Wireshark, just use strings mysite.pcap | grep flag
You don't even need Wireshark, just use strings mysite2.pcap | grep flag
You don't even need Wireshark, just use strings ftp.pcap | grep flag
If you want to, you can right click on any ftp packet and follow the tcp stream. If there's no flag, then move on to the next stream.
You don't even need Wireshark, just use strings telnet.pcap | grep flag
You don't even need Wireshark, just use strings telnet.pcap | grep flag
When we listen to the mp3 initially, we can hear a faint beeping in the background. This sounds like Morse code, so let's find an easy way to transcribe it to text dits and dahs (radio speak for dots and dashes).
We open it up in Audacity, and notice there are two tracks. Let's switch to spectrogram view. We can do this by clicking on the arrow pointing downwards next to the track name, then clicking Spectrogram
:
If we zoom in on the beginning of the track, we can see that the Morse code is in the second track:
One huge issue right now is that the Morse code is "covered" by the actual vocals of the track. I was stuck on this portion for a while.
Let's split the tracks to mono using the track settings.
Then, we subtract the original track from the track with morse code. After that, we'll be able to clearly see the morse code in spectrogram view.
First, we select one track, and invert it (Effect > Invert
). Then, we select both tracks and mix them together (Tracks > Mix > Mix and Render
).
It's still a bit hard to see, so let's change the coloring.
We open up track settings and then select Spectrogram Settings
. We change the color range to 20 dB instead of 80 dB (decibels).
The result is morse code. Now all we have to do is open up a text editor, copy the morse code down, and convert it to text using an online tool (:
The short ones are dits and the long ones are dahs. I usually represent the short ones with .
and the long ones with -
, which is a format most online morse-to-text tools use as well.
That would be the first letter in the text.
The image says something is unzipped...
Let's try binwalk
.
Command: binwalk -e openbackpack.jpg
Binwalk extracts two files, a zip and a file called flag.png
, which has the flag of course.
We download and unzip it. It seems they just compressed a system's directories from / and gave it to us...
We cd
into the home directory for the user (/home/User/
). Nothing seems interesting except for a .bash_history
file, which reveals that they encrypted a flag using a concatenation of 3 passwords. We have to find the 3 passwords to decrypt the encrypted flag.
Password 1:
It's in an image in ~/Pictures
. We use strings and find the signature for steghide
. We can use steghide extract -sf doggo.jpeg
. It takes a bit more guesswork to guess that there is no password. The password is in the extracted text file.
Password 2:
The password is the password to the user named user
. We read /etc/shadow/
, and find the password.
Password 3:
We first uncompress the table.db.tar.gz
inside /opt
.
Let's get everything from table.db
: sqlite3 table.db "SELECT * FROM passwords"
. This gives us the third password.
Now that we have all 3 passwords, we can decrypt the encrypted text file using openssl enc -aes-256-cbc -d -in flag.txt.enc -out file.txt
. We supply the concatenation of the 3 passwords, and we read file.txt
for the decrypted flag.
We want to find the 10947th prime number. We are given the following algorithm:
import math
def main():
primes = []
count = 2
index = 0
while True:
isprime = False
for x in range(2, int(math.sqrt(count) + 1)):
if count % x == 0:
isprime = True
continue
if isprime:
primes.append(count)
print(index, primes[index])
index += 1
count += 1
if __name__ == "__main__":
main()
This algorithm seems kind of slow...
We can write a faster script such as this one:
from math import sqrt
def is_prime(n):
if (n <= 1):
return False
if (n == 2):
return True
if (n % 2 == 0):
return False
i = 3
while i <= sqrt(n):
if n % i == 0:
return False
i = i + 2
return True
def prime_generator():
n = 1
while True:
n += 1
if is_prime(n):
yield n
generator = prime_generator()
x = []
for i in range(10948):
x.append(next(generator))
We access the 10497th element of x
to get the flag (x[10496]).
Simple MD5 brute force. I got the author names from the Discord server.
We just have to convert 5 base64 values to ASCII.
I used pwntools, a pretty neat library for tasks like these.
from pwn import *
import base64
conn = remote("challenges.neverlanctf.com", 1120)
for i in range(5):
print(conn.recvuntil("decrypt: "))
x = conn.recv().strip()
print(x)
y = base64.b64decode(x)
print(y)
conn.send(y)
print(conn.recvline())
print(conn.recv())
https://challenges.neverlanctf.com:1150
This site gives an svg which we can download. Quite obviously, the colors represent 0
and 1
in binary (gray is 1, green is 0).
We find out that we can download the svg information directly from /svg.php
, which makes it much easier for a script.
We parse the image, using regex to remove all different attributes such as x, y, width, and height for each <rect>
in the svg. Then, we simply just use str.replace()
in Python to get the binary string.
Then we convert that binary string into text.
However, most of the time the server will return an svg that doesn't have the flag. Instead, it will return some time hash information which is useless to us.
We can repeatedly query the server for an svg until it gives us a flag svg.
from __future__ import print_function
import requests
while True:
f = requests.get("https://challenges.neverlanctf.com:1150/svg.php").text.decode()
f = f[336:-9]
f= f.strip()
import re
s = re.compile(r"\sid='\d*'")
a = re.compile(r"\sx='\d*'")
b = re.compile(r"\sy='\d*'")
c = re.compile(r"width='\d*' ")
d = re.compile(r"height='\d*' ")
f = s.sub("", f)
f = a.sub("", f)
f = b.sub("", f)
f = c.sub("", f)
f = d.sub("", f)
#print(f)
f = f.replace("<rect style='fill:#333136'/>", "1")
f = f.replace("<rect style='fill:#00ff00'/>", "0")
f = [f[i:i+8] for i in range(0, len(f), 8)]
#print(f)
x = "".join([chr(int(i, 2)) for i in f])
if not "time hash:" in x:
print(x)
ssh neverlan@medusa.neverlanctf.com -p 3333 password: eyesofstone
We initially find an intel.txt, giving us information. We have to ssh onto evil@victim
.
Using Medusa (an ssh password cracker), we can bruteforce the password easily. It is 0024
.
Once ssh'd, we find a zip file with some base64 as its name. It's password protected, so we try decoding the name.
Decoded, the name of the zip file is stonecold
, which is used to unzip the zip file.
The content of the zip file is the flag.
The "front page of the Internet" is Reddit.
The author is ZestyFE
, so we guess that he has a Reddit account under the same name.
We navigate to /u/ZestyFE
on Reddit, and find the flag in one of ZestyFE's comments.
We search up SaintCon keynotes and find that NeverLAN keynoted in 2018
Unfortunately the SaintCon site is not 100% functional so we're stuck...
Then we guses that keynoting a conference is pretty cool and they must have posted something to commemorate the event on their Twitter.
They actually link us their slides
The flag is right next to a picture of Rick Astley :p
During the competition there were streams for music and the like. If we go under their music tab and select track #2 we see a YouTube video.
Exploring the comments reveals a flag that someone commented.
We Google for 01 September 2017 | 14:01 phreak
.
We find the first Darknet Diaries episode.
By some stroke of pure geniosity we right click to view the source code of the site and the flag is at the bottom.
https://challenges.neverlanctf.com:1110
The title hints that it has something to do with cookies.
When we visit the site, it says He's my favorite Red guy
. We guess this to be Elmo
from Sesame Street.
We look at the cookies, and find a cookie Red_Guy's_Name: NameGoesHere
. We replace NameGoesHere
with elmo
.
We get the flag by refreshing the tab.
https://challenges.neverlanctf.com:1140
The site looks pretty boring, so let's take a look at /robots.txt
, which is hinted at by the title:
User-agent: *
Disallow: /
Disallow: flag.txt
We navigate to /flag.txt
for the flag.
https://challenges.neverlanctf.com:1160/
Simple SQL injection in the login page. Note that the password does not matter, only the username is vulnerable.
The goal is to log in as an admin.
Payload:
Username: ' OR 1=1;--
Password: asdf
Return to the home page for the flag.
https://challenges.neverlanctf.com:1165/
Simple SQL injection in the login page. Note that the password does not matter, only the username is vulnerable.
The goal is to log in as an admin.
This time, there seems to be multiple accounts, and the previous payload logs us in as John
, who is not an admin. We have to skip over John's account using SQL's LIMIT
to log in as admin.
Payload:
Username: ' OR 1=1, LIMIT 1;--
Password: asdf
Return to the home page for the flag.
https://7aimehagbl.neverlanctf.com
This website redirects so many times your browser just gives up. We can use Python's requests
module and the follow_redirects=False
option:
import requests
p = requests.get("https://7aimehagbl.neverlanctf.com", allow_redirects=False)
On the first visit (using Python), the page states where it's redirecting. How convenient. How about we just follow the trail?
import requests
url = "https://7aimehagbl.neverlanctf.com"
while True:
p = requests.get(url, allow_redirects=False)
print(p.text)
url = "https://" + p.text.split()[-1]
The flag is in one of the sites that we get redirected to.
https://challenges.neverlanctf.com:1130
When we try to visit the site normally, it says that the site is only for commodo 64
browsers.
We guess that the server tells what browser we are using based on the User-Agent header of the request.
When we Google for Commodo 64 browsers, we end up with a browser named Contiki
. We search for the Contiki User-Agent.
We find a really long list of User-Agents that ever downloaded something from PyPI on GitHub Gists, and we Ctrl-F for Contiki.
We find the User-Agent for Contiki as Contiki/1.0 (Commodore 64; http://dunkels.com/adam/contiki/)
.
We set that as our User-Agent using Python's requests
, and request the home page, which gives us the flag.
We basically have to ssh onto a server and retrieve the flag from it. We start from Chicken Little 1. We use the flag from Chicken Little 1 as the password for the ssh onto Chicken Little 2, etc.
Use an ls
and find Welcome.txt
.
Read the file for the flag.
Use an ls -a
(-a flag to show hidden files) and find .chicken.txt
.
Read the file for the flag.
We find BAWK.txt
with a bunch of "BAWK"s in it. Knowing the password format we guess that this password also has a -
in it, so we grep for -
in the file for the flag.
We find a binary file with the flag presumably hidden in it. We can use strings
to first extract the printable strings, then grep for -
in it, which gives the flag.
We can use binwalk -e
to extract files from the file, giving us a file with the flag.
We can use scp
to transfer the file to our local machine since curl
was removed.
scp -P 3333 level5@44.233.149.141:~/chicken-little.png .
The flag is visible in the image.
We are told we need to find the password to the user level7
on the system. We read /etc/shadow
for the level7
password hash.
We generate a wordlist of all possible 4-character combinations using crunch 1 4 > pass.txt
.
We can use hashcat -m 1800 -a 0 h.hash pass.txt
to eventually break the hash (it was supposed to take ~15 minutes).
I used a brute-force script on a remote server because my 2011 mac really did not like running SHA512 a lot of times.
Trivia Question: a reliable mechanism for websites to remember stateful information. Yummy!
It's talking about cookies, which is the flag.
The process of attempting to gain Unauthorized access to restricted systems using common passwords or algorithms that guess passwords
Google the description.
An article defines the description for the term "password cracking", which is the flag.
A group of binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation
Radix-64
basically tells us that the flag is base64.
This CVE reminds me of some old school exploits. If flag is enabled in sudoers
We Google If flag is enabled in sudoers cve
and find this site, which has the flag in it.
This CVE Proof of concept Shows NSA.go<span>v</span> playing "Never Gonna Give You Up," by 1980s heart-throb Rick Astley. Use the CVE ID for the flag. flag{CVE-?????????}
I remember seeing this as a meme on Reddit :laughing: Googling the description gives news articles detailing the correct CVE ID for the flag.