EasyCTF 2018: Zippity
Event | Challenge | Category | Points | Solves |
---|---|---|---|---|
EasyCTF 2018 | Zippity | Miscellaneous | 80 | ? |
Description
I heard you liked zip codes! Connect via nc c1.easyctf.com 12483 to prove your zip code knowledge.
TL;DR
In this task we had to connect to c1.easyctf.com and answer 50 questions about zipcode such as water area size, in less than 30 seconds.
First, I had to find the right US zipcode database on census.gov.
Then I had to program the bot to answer the questions in less than 30 seconds.
Understanding the challenge
To solve the challenge we had to answer 50 questions in 30 seconds through a tcp connection.
For each given zipcode, there was one of the following questions:
- Land area size (in m²)
- Water area size (in m²)
- Longitude (with 6 digits)
- Latitude (with 6 digits)
Find the right Zipcode database
To answer the questions, I had to find the right database.
At the beginning I tried to recover informations from different websites.
Most of them were incomplete or partially wrong.
Then I discovered the census.gov website which store data about ZIP Code Tabulation Areas:
https://www.census.gov/geo/maps-data/data/gazetteer2010.html
GEOID | ALAND | AWATER | INTPTLAT | INTPTLONG |
---|---|---|---|---|
00601 | 166659789 | 799296 | 18.180555 | -66.749961 |
00602 | 79288158 | 4446273 | 18.362268 | -67.176130 |
… | … | … | … | … |
The website store the different versions of database (1 for each year).
After a few tests, the right one was the one of 2010.
Time to script
To finish, I had to script due to the 30 seconds expected.
A commented script is better than a long text, so here is the script I made (in python3).
import socket
import requests
# Socket connection
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('c1.easyctf.com', 12483))
# Making dictionary from file "ZIP Code Tabulation Area"
# https://www.census.gov/geo/maps-data/data/gazetteer2010.html
with open("Gaz_zcta_national.txt","r") as f:
l = f.readlines()
l = l[1:] # Remove first line (header)
dico = {} # dico[zipcode] = [Land Area, Water Area, Latitude, Longitude]
for elt in l:
elt = elt.replace(" ","")
elt = elt.replace("\r","")
elt = elt.replace("\n","")
m = elt.split("\t")
dico[m[0]] = [m[3],m[4],m[7],m[8]] # Land Area, Water Area, Latitude, Longitude
# Dictionary ready :)
rec = ""
while "easyctf" not in rec: # Keep answering until we get the flag
rec = s.recv(2048).decode("utf-8") # Get response from server
print(rec)
rep = None # Set client response to None
if "Round" in rec: # Get zipcode from servers response
zipcode = rec[-7:-2]
print("Zipcode: "+zipcode)
# Answering questions:
if " land area (m^2)" in rec:
rep = dico[zipcode][0] # Land Area
print("Land Area of "+zipcode+" is "+rep+"m².")
elif " water area (m^2)" in rec:
rep = dico[zipcode][1] # Water Area
print("Water Area of "+zipcode+" is "+rep+"m².")
elif " latitude (degrees)" in rec:
rep = dico[zipcode][2] # Latitude
print("Latitude of "+zipcode+" is "+rep+".")
elif " longitude (degrees)" in rec:
rep = dico[zipcode][3] # Longitude
print("Longitude of "+zipcode+" is "+rep+".")
if rep is not None: # If there is a response to send
s.send((rep+"\r\n").encode("utf-8")) # Send it
FLAG
easyctf{hope_you_liked_parsing_tsvs!}
Zeecka