4 min read

PicoCTF nice netcat write-up

PicoCTF nice netcat write-up

Ever wanted to learn how to break into things?

Say you're locked out of your house and you needed to get back in, but you left your keys on the table right next to the door... would you just break down your door to get your keys? Or... would there be a better way? Could you just emulate your keys and pick the lock on your door?

Both models of breaking down your door and understanding how lockpicking works require basis knowledge of how the door is keeping you outside of your home, but this is just for example.

Let's take a peek at a legal environment for us to break into... PicoCTF. In the "General Skills" category one of the challenges is to translate a random set of numbers into a message. Similar to how Caesar had to do this way back in the day, we have a pretty beginner challenge that's worth writing up for.

This post assumes you have access to a linux machine (osx or linux) or WSL2 for windows. We'll be using python and the program netcat.

The challenge

The challenge is located at https://play.picoctf.org/practice/challenge/156. The description reads:

There is a nice program that you can talk to by using this command in a shell: $ nc mercury.picoctf.net 43239, but it doesn't speak English...

Alright, so we don't have any crazy vulnerabilities to run (although I run everything in a container that has no access to my main machine or I launch a tiny working container in the cloud), let's connect to the server using nc (netcat) and see what it returns to us:

nc mercury.picoctf.net 43239

connection

Hmm... well the hint was right here... we're not talking to a server that writes English, but can we make something out of the response we do get back?

They are integers that's for sure. Well... if we look at the integers themselves, there aren't any crazy big ones, nor are there any really small ones. If you're not familiar with ascii, it's a character encoding for numbers to represent characters in the alphabet. Let's assume for a moment our suspicions are right... that this server we've connected through netcat.

It just spits out a bunch of numbers separated by newlines (\n). Cool. Let's see if our intuition is correct by grabbing the list of numbers and converting them. I'll use this website and paste the numbers into the input.

To ascii

Neat. We're right. There's our flag. That's 10 points for us.

Extra mile

Alright, so we've got ourselves a working copy to get the flag, but rather than needing to do the work of converting the numbers into a list. Let's whip up a python program to do this for us.

The 3 things we need to do in our program is:

  1. Fetch the numbers
  2. Clean the data
  3. Convert to ascii (and print it out)

Since number 1 is the most difficult, let's implement this at the end. We can hardcode some numbers we'll use.

touch chars.py

In our chars.py file, let's hardcode some numbers in a binary format with newlines and spaces:

hexchars = b"10
65
65
65
10"

Let's convert this to utf-8 and remove the newlines and spaces to convert it to a list in python:

hexchars = hexchars.decode("utf-8").strip().split("\n")

Sweet. With our hexchars variabiel, we can now convert it into a list of integers (there are no decimal points, so integers will do just fine):

hexchars = hexchars.decode("utf-8").strip().split("\n")
hexchars = [int(n.strip()) for n in hexchars]

Now all we need to do is convert each number into an ascii character representation:

flag = ""
for num in hexchars:
    flag += chr(num)

print(flag)

Now we have a way to programmatically convert our numbers into ascii characters. Let's replicate our call to netcat. Since netcat is literally just a socket client. We can open the same socket, receive the some characters and then close it right back up again. In Python, that looks like this:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("mercury.picoctf.net", 43239))
hexchars = s.recv(1024)
s.close()

Putting this all together, our final script for this challenge:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("mercury.picoctf.net", 43239))
hexchars = s.recv(1024)
s.close()

hexchars = hexchars.decode("utf-8").strip().split("\n")

hexchars = [int(n.strip()) for n in hexchars]

flag = ""
for num in hexchars:
    flag += chr(num)

print(flag)

Hope ya learned something new. We'll continue these challenges as we go forward through picoCTF.

Mind sparing a moment?

Is this post confusing? Did I make a mistake? Let me know if you have any feedback and suggestions!