Zeecka zeecka

Zippity

EasyCTF 2018 - Prog (80 pts)

EasyCTF 2018: Zippity

EventChallengeCategoryPointsSolves
EasyCTF 2018ZippityDivers80?

Description

I heard you liked zip codes! Connect via nc c1.easyctf.com 12483 to prove your zip code knowledge.

TL;DR

Dans cette épreuve, il fallait se connecter à c1.easyctf.com et répondre à 50 questions au sujet des codes postaux, comme la superficie en eau, en moins de 30 secondes.
D’abord, il m’a fallu trouver la bonne base de données des codes postaux américains sur census.gov.
Ensuite, il fallait programmer le bot pour répondre aux questions en moins de 30 secondes.

Comprendre le challenge

Pour résoudre le challenge, il fallait répondre à 50 questions en 30 secondes à travers une connexion tcp.
Pour chaque code postal fourni, il y avait l’une des questions suivantes :

  • Superficie terrestre (en m²)
  • Superficie en eau (en m²)
  • Longitude (avec 6 chiffres)
  • Latitude (avec 6 chiffres)

Trouver la bonne base de données de codes postaux

Pour répondre aux questions, il me fallait trouver la bonne base de données.
Au début, j’ai essayé de récupérer des informations depuis différents sites web.
La plupart étaient incomplètes ou partiellement erronées.
Puis j’ai découvert le site census.gov qui stocke des données sur les ZIP Code Tabulation Areas :
https://www.census.gov/geo/maps-data/data/gazetteer2010.html

![fig1](/files/easyctf_2018/zippity/database.png)
GEOIDALANDAWATERINTPTLATINTPTLONG
0060116665978979929618.180555-66.749961
0060279288158444627318.362268-67.176130

Gaz_zcta_national.txt

Le site stocke les différentes versions de la base de données (1 par an).
Après quelques tests, la bonne était celle de 2010.

Place au script

Pour finir, il fallait scripter en raison des 30 secondes imparties.
Un script commenté vaut mieux qu’un long texte, voici donc le script que j’ai réalisé (en 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](/files/easyctf_2018/zippity/zippity1.png)
![fig3](/files/easyctf_2018/zippity/zippity2.png)

FLAG

easyctf{hope_you_liked_parsing_tsvs!}

Zeecka