Tags: misc python parsing 

Rating:

First, just run the service a couple of times and see what would happen.
```
$ nc c1.easyctf.com 12483
c1.easyctf.com [165.227.110.243] 12483 (?) open
+======================================================================+
| Welcome to Zippy! We love US zip codes, so we'll be asking you some |
| simple facts about them, based on the 2010 Census. Only the |
| brightest zip-code fanatics among you will be able to succeed! |
| You'll have 30 seconds to answer 50 questions correctly. |
+======================================================================+

3... 2... 1... Go!

Round 1 / 50
What is the longitude (degrees) of the zip code 60549? ^C
$ nc c1.easyctf.com 12483

[OMITTED...]

Round 1 / 50
What is the latitude (degrees) of the zip code 36858? ^C
$ nc c1.easyctf.com 12483

[OMITTED...]

Round 1 / 50
What is the latitude (degrees) of the zip code 72473? ^C
$ nc c1.easyctf.com 12483

[OMITTED...]

Round 1 / 50
What is the longitude (degrees) of the zip code 46239? ^C
$ nc c1.easyctf.com 12483

[OMITTED...]

Round 1 / 50
What is the water area (m^2) of the zip code 77650? ^C
$ nc c1.easyctf.com 12483

[OMITTED...]

Round 1 / 50
What is the water area (m^2) of the zip code 14480? ^C
```

It ask us 50 questions about land area, water area, latitude and longtitude of the zip code, base on the 2010 Census.

After some Google searching, I have found `Gaz_zcta_national.txt` that meet our need. You can Google search that filename and have the file.

Finally, we have this code:
```python
#!/usr/bin/env python
import time
import csv
import socket
import telnetlib

def myconnect(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
return sock

def recvuntil(s, pattern):
buf = ''
while pattern not in buf:
buf += s.recv(1)
return buf

def telnet(s):
print('[*] Telneting to socket ...')
t = telnetlib.Telnet()
t.sock = s
t.interact()

data = dict()
DATA_FILE='Gaz_zcta_national.txt'
with open(DATA_FILE, 'rb') as csvfile:
zippy_reader = csv.reader(csvfile, delimiter='\t')
start = time.time()
for row in zippy_reader:
data[row[0]] = row[1:]
end = time.time()

print("Parsing data time: %r"%(end-start))

POPULATION = 0 # 2010 Census population count.
HOUSING = 1 # 2010 Census housing unit count.
LAND_AREA = 2 # Land Area (square meters) - Created for statistical purposes only
WATER_AREA = 3 # Water Area (square meters) - Created for statistical purposes only
LAND_AREA_SMILE = 4 # Land Area (square miles) - Created for statistical purposes only
WATER_AREA_SMILE = 5 # Water Area (square miles) - Created for statistical purposes only
LATITUDE = 6 # Latitude (decimal degrees) First character is blank or "-" denoting North or South latitude respectively
LONGITUDE = 7 # Longitude (decimal degrees) First character is blank or "-" denoting East or West longitude respectively

service = myconnect('c1.easyctf.com', 12483)

for x in range(50):
print(recvuntil(service, ' / 50'))
recvuntil(service, 'What is the ')
datatype = recvuntil(service, ' ')[:-1]
zipcode = recvuntil(service, '? ')[-7:-2] # 5 in zipcode; 2 in '? '
print("Round: %r, %r, %r"%(x+1,datatype, zipcode))

if datatype == 'land':
lvalue = int(data[zipcode][LAND_AREA])
elif datatype == 'water':
lvalue = int(data[zipcode][WATER_AREA])
elif datatype == 'latitude':
lvalue = float(data[zipcode][LATITUDE])
elif datatype == 'longitude':
lvalue = float(data[zipcode][LONGITUDE])
else:
raise ValueError("What is this ???")
service.send("%r\n"%lvalue)

telnet(service)
'''
Round 50 / 50
Round: 50, 'water', '15364'
[*] Telneting to socket ...

That's correct!

You succeeded! Here's the flag:
easyctf{hope_you_liked_parsing_tsvs!}
'''
```