Hack This Site - Programming - Parse an XML file

Mon, Jul 05, 21

Welcome back to my walkthrough of hackthissite.org’s CTF missions. I will be going through my thought process of how I solved these missions, and therefore also giving away the solutions. If you came across this to give you hints, watch out for spoilers! Good luck, have fun.

This mission gives us 120 seconds take an XML document that describes an image, and draw said image. The image will show codes in different colours, which we are then supposed to enter on the website as the key for the mission.

The following code is what I wrote in python to solve this mission. In order to facilitate me, I used two different modules: xml.etree.ElemenTree to parse the XML, and matplotlib for drawing.

import xml.etree.ElementTree as ET
import matplotlib.pyplot as plt
from matplotlib.patches import Arc as matArc

class Arc:
    """
    Represents an Arc that must be drawn
    """

    colour = "white"

    def __init__(self, xCenter, yCenter, radius, start, extend):
        self.extend = extend
        self.xCenter = xCenter
        self.start = start
        self.yCenter = yCenter
        self.radius = radius
    
    def setColour(self, colour):
        self.colour = colour

    def draw(self, ax):
        """
        Given a subplot object, plot this Arc
        """
        diam = self.radius * 2
        ax.add_patch(matArc((self.xCenter, self.yCenter), diam, diam, theta1 = self.start, theta2= self.extend, color = self.colour))

class Line:
    """
    Represents a Line that must be drawn
    """

    colour = "white"

    def __init__(self, yStart, yEnd, xStart, xEnd):
        self.yStart = yStart
        self.yEnd = yEnd
        self.xStart = xStart
        self.xEnd = xEnd
    
    def setColour(self, colour):
        self.colour = colour

    def draw(self, ax):
        """
        Given a subplot object, plot this Line
        """
        ax.plot([self.xStart, self.xEnd], [self.yStart, self.yEnd], color = self.colour)

def extractArc(arc):
    """
    Given a XML Arc tree structure, returns an Arc object.
    """
    attr = {}
    colourSet = False
    for child in arc:
        if (child.tag == "XCenter"):
            attr["xCenter"] = float(child.text)
        elif (child.tag == "YCenter"):
            attr["yCenter"] = float(child.text)
        elif (child.tag == "Radius"):
            attr["radius"] = float(child.text)
        elif (child.tag == "ArcStart"):
            if float(child.text) < 0:
                attr["start"] = 360 + float(child.text)
            else:
                attr["start"] = float(child.text)
        elif (child.tag == "ArcExtend"):
            attr["extend"] = float(child.text)
        elif (child.tag == "Color"):
            attr['colour'] = child.text
            colourSet = True
    attr["extend"] += attr["start"]
    a = Arc(attr["xCenter"], attr["yCenter"], attr["radius"], attr["start"], attr["extend"])
    if (colourSet):
        a.setColour(attr["colour"])
    return a

def extractLine(line):
    """
    Given an XLM Line tree structure, returns a Line object.
    """
    attr = {}
    colourSet = False
    for child in line:
        if (child.tag == "YStart"):
            attr["yStart"] = float(child.text)
        elif (child.tag == "YEnd"):
            attr["yEnd"] = float(child.text)
        elif (child.tag == "XStart"):
            attr["xStart"] = float(child.text)
        elif (child.tag == "XEnd"):
            attr["xEnd"] = float(child.text)
        elif (child.tag == "Color"):
            attr["colour"] = child.text
            colourSet = True
    l = Line(attr["yStart"], attr["yEnd"], attr["xStart"], attr["xEnd"])
    if (colourSet):
        l.setColour(attr["colour"])
    return l

def parsePlotInfo():
    """
    Extracts XML plot objects and retursn an array of those objects.
    """
    tree = ET.parse('data')
    root = tree.getroot()
    plotObjects = []
    for child in root:
        if (child.tag == "Arc"):
            arc = extractArc(child)
            plotObjects.append(arc)
        elif (child.tag == "Line"):
            line = extractLine(child)
            plotObjects.append(line)
    return plotObjects

def draw(plotObjects):
    """
    Given an array of plot Objects, initiate a canvas and plot them.
    """
    # init the canvas
    fig, ax = plt.subplots()
    ax.set_facecolor("black")

    # iterate through all plotObjects & draw them
    for o in plotObjects:
        o.draw(ax)
    
    plt.show()

if __name__ == "__main__":
    plotObjects = parsePlotInfo()
    draw(plotObjects)