Zippity

EasyCTF 2018 - Prog (80 pts).

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

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

Gaz_zcta_national.txt

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 = 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

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)

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


zippity.py

FLAG

easyctf{hope_you_liked_parsing_tsvs!}

Zeecka