Challenge:
Welcome to Vertinet.
This problem follows the same specifications as the previous Verticode problem, except that you have to solve many of them by developing a client to communicate with the server available at problems1.2016q1.sctf.io:50000. Good luck.
Solution:
This challenge was a follow on from VertiCode, I’d already got some Python to decode the images, so it was just a case of adapting that code to read from the server.
A test connection to the server resulted in a short chunk of HTML with base64 encoded image data:
<html><img src=‘data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAAFoCAIAAABMtifjAAA……
Viewing the URL in a browser shows the code image:
The image is shorter that the VertiCode challenge, but the code still works.
I hadn’t encountered reading images from an encoded stream before. Google Fu suggested BytesIO(base64.b64decode(base64_data)) would do the trick.
The only real modification to the VertiCode script was to strip off the HTML tags and feed the image stream into the decoder:
import PIL.Image, sys, base64
from telnetlib import Telnet
from io import BytesIO
tn = Telnet('problems1.2016q1.sctf.io', 50000)
def main():
global tn
for i in range(0, 500):
print i
puzData = getImage()
decodeText = decode(puzData)
print decodeText
tn.write(decodeText)
tn.close()
def getImage():
global tn
print tn.read_until("png;base64,", 0.2) # Read past HTML preamble
imgData = tn.read_until("WordsWeNeverSee", 0.2) # Grab image data
imgData = imgData.replace("\'></img>", "") # Strip trailing HTML tags
return PIL.Image.open(BytesIO(base64.b64decode(imgData)))
def decode(puzl):
px = 2
py = 2
offset = 0
byteBits = 0
decodeString = ""
pDat = puzl.load()
for ln in range(0, puzl.size[1]/12):
px = 2
colRGB = pDat[px,py] # Get colour value
if colRGB == (128, 0, 128): # Purple (1)
offset = 1
elif colRGB == (0, 0, 255): # Blue (2)
offset = 2
elif colRGB == (0, 128, 0): # Green (3)
offset = 3
elif colRGB == (255, 255, 0): # Yellow (4)
offset = 4
elif colRGB == (255, 165, 0): # Orange (5)
offset = 5
else:
offset = 0 # red (0)
# Jump across to bit data
px = 85
byteBits = 0
for b in range(0,7):
byteBits <<= 1
if pDat[px,py][0] == 0:
byteBits +=1
px += 12 # Next bit square
decodeString += chr(int(byteBits - offset))
py += 12 # next row
return decodeString
if __name__ == '__main__':
main()
The output from the code is a sequence of 200 images and decodes:
0 <html><img src='data:image/png;base64, AFfKszFjMElFMVcMXwoYJnqZBWPSpC 1 <html><img src='data:image/png;base64, OlSdwrCVQnlGfyfEbiUOxaFXhzZshL 2 <html><img src='data:image/png;base64, adZrdaxxuZCClgjavYDUhNuHKYOOzD 3 <html><img src='data:image/png;base64, bJNIfcGIKAQUVScuDTHPpBdQdscmAV 4 <html><img src='data:image/png;base64, zpYmyUYGAaANbwQFMqckpLkzMZrnJx ... 197 <html><img src='data:image/png;base64, uROLVRCsoOQZWQoBbsWEUlEJjwmFKs 198 <html><img src='data:image/png;base64, hrBJXiFxwKuWKdnlOccrmyJTFPLAYe 199 <html><img src='data:image/png;base64, PFURJgUXjzZEjnBHfpHAtHitHhJomD 200 FLAG: sctf{y0ub34tth3v3rt1c0d3}