This challenge was a TCP based image sending system. The server, upon a new connection, would send a Base64 encoded image and then prompt the user what quadrant an image of Dora was in (1-4 counterclockwise starting in the upper-right corner). The image would look something like this:
![](https://rgwv.team/writeups/956/dora.png)
There are multiple images of Dora used (but only one in each image sent to the client), and could be in grayscale or color. In addition, parts of the Dora were transparent, which allowed the background to bleed through.
The key to solving this challenge was realizing that while Dora's image changes, the images of Dora's friends didn't. This means that you can use "template matching" to find exact copies of Dora's friends, remove them from the image, and then take the average location of all the remaining pixels. Once you have the average location, you can find the quadrant based on the image dimensions (720x720).
Here's what the final (admittedly rough) python script looked like:
```pythonfrom pwn import *import osimport pyautoguiimport cv2import numpy as npfrom os import listdirfrom os.path import isfile, joinfrom matplotlib import pyplot
import base64
doras = [    {        "h": 15,        "w": 10,        "pl": 53, #Padding left        "pr": 14, #Padding right        "pt": 15, #Padding top        "pb": 19, #Padding bottom        "img": cv2.imread("swiper.png", 0) #The actual template image    },    {        "h": 32,        "w": 45,        "pl": 10,        "pr": 9,        "pt": 27,        "pb": 19,        "img": cv2.imread("backpack.png", 0)    },    {        "h": 46,        "w": 12,        "pl": 31,        "pr": 29,        "pt": 19,        "pb": 12,        "img": cv2.imread("boots.png", 0)    },    {        "h": 41,        "w": 19,        "pl": 26,        "pr": 19,        "pt": 15,        "pb": 21,        "img": cv2.imread("cow.png", 0)    },    {        "h": 45,        "w": 15,        "pl": 17,        "pr": 36,        "pt": 14,        "pb": 18,        "img": cv2.imread("dino.png", 0)    },]
while True:    r = remote("misc.ctf.nullcon.net", "8000")    c = 0 #Count    while True:        c += 1        print(c)        print(r.recvline()) #There's a blank line before each image.        string = r.recvline()        print(string[:1000])        if(not string.startswith("No flag")):            string = base64.b64decode(str(string))            with open("output.png", "wb") as file:                file.write(string) #Save the received image
            # Do openCV stuff            img_g = cv2.imread('output.png', 0)            bg = img_g[0][0]
            for i in doras: #Iterate through Dora's friends.                res = cv2.matchTemplate(img_g, i['img'], cv2.TM_SQDIFF_NORMED) #Match the template image                min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
                # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum                top_left = (min_loc[0]-i['pl'] - 5, min_loc[1] - i['pt'] - 5) #Get the top left of the image (with a bit of padding)                bottom_right = (                    int(min_loc[0] + i['w'] + i['pr'] + 5), int(min_loc[1] + i['h'] + i['pb'] + 5)) #Get the bottom right of the image (with a bit of padding)                img_g = cv2.rectangle(                    img_g, top_left, bottom_right, int(img_g[0][0]), -1) #Fill that area with the background.            match_found = False
            points = []            for y in range(len(img_g)):                for x in range(len(img_g[y])):                    if(img_g[y][x] != bg):                        points.append((y, x)) #Get every non-background point.
            center = list(np.mean(np.array(points), 0)) #Get the mean point.            x = int(center[1])            y = int(center[0])
            cv2.circle(img_g, (x, y), 5, 0, -1) #Draw a circle for where Dora is.
            print(x)            print(y)            print(img_g[x][y])            match_found = True            if(x <= 360):                if(y <= 360):                    r.send("2\n")                else:                    r.send("3\n")            else:                if(y <= 360):                    r.send("1\n")                else:                    r.send("4\n")
        else:            with open("failedfile.png", "wb") as file: #If it fails, find why.                file.write(string)            break```
The 801st output image was the following:![](https://rgwv.team/writeups/956/flag.png)