Codehead's Corner
Random ramblings on hacking, coding, fighting with infrastructure and general tech
sCTF 2016 – VertiNet – Crypto – 140 Points
Posted: 17 Apr 2016 at 19:28 by Codehead

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}
Categories: Hacking CTF

Site powered by Hugo.
Polymer theme by pdevty, tweaked by Codehead