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

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

fig1

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

zippity.py

fig2
fig3

FLAG

easyctf{hope_you_liked_parsing_tsvs!}

Zeecka