CSAW 2013 Quals - Misc 50/50/300: Life

Published September 22, 2013

Misc 50 / 50

While the first ‘misc 50’ challenge from this year’s CSAW CTF qualification round was PCAP file, thus hinting that Wireshark or other tools might be necessary, a simple grep like the following was enough and presented you the flag on a silver platter.

grep -aE 'flag|key' networking.pcap

then gives you the following

[some protocol data] flag{d316759c281bf925d600be698a4973d5} [more protocol data] 

For the second misc challenge, the same method works and it gives you the flag repeated a few times:

[some data] flag{f9b43c9e9c05be5e08ea163007af5144}.exe [more data] 

Misc 300: Life

Misc 300 was one of the more straight-forward challenges and very close in spirit to the OMGACM challenges from this year’s DEFCON quals. Upon connecting to the server at 128.238.66.216:45678, you were shown something similar to the following:

##### Round 1: 25 Generations #####
#######################
#           *         #
#*         *          #
# *                 * #
# * **        *    ***#
# **  *      **       #
#**    *       *      #
# *             *     #
#      *        *     #
#     *    * *   *    #
#  * *                #
# *              *    #
#     *           *   #
#       *             #
#           **        #
#      *              #
#                     #
#                *    #
#         **          #
#        *     *     *#
#       *    *  **  * #
#######################

If you take the name of the challenge “Life” as a hint and if you have seen Conway’s Game of Life in your life before, the challenge becomes pretty straightforward and the only thing you need to be aware of is that the boundary of the world does not wrap but is constant instead (a simple parameter change for linear convolution in line 23). A last thing to keep in mind is that had to respond quickly or the connection was terminated for being ‘Too slow!’, you were given only a few seconds per round to parse the output and send the world advanced by the given number of generations back.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = "cao"
__description__ = "csaw2013q: misc300/life; game of life solver"
__version__ = "1.0-cleanedup"


from re import compile
from socket import socket
from time import sleep

from numpy import array, int8
from scipy.ndimage.filters import convolve


weights = array([[1, 1, 1], [1, 10, 1], [1, 1, 1]])
re_round_generations = compile("##### Round (?P<round>[0-9]+): "
                                "(?P<generations>[0-9]+) Generations #####")


def step(world):
    # alternative method is: wrap 
    conv = convolve(world, weights, mode="constant")
    return int8((conv == 3) | (conv == 12) | (conv == 13))


def _decode(i):
    if i == "*":
        return 1
    else:
        return 0


def _encode(i):
    if i:
        return "*"
    else:
        return " "

# ==================================

s = socket()
s.connect(("128.238.66.216", 45678))

f = s.makefile()

for _round in range(1, 101):
    print("Round: {}\r".format(_round), end="")
    f.readline()    # Read the one empty line
    match = re_round_generations.match(f.readline())
    generations = int(match.group("generations"))

    border = f.readline().strip()
    width = len(border)

    # read in world and convert to numbers
    world = []
    while True:
        ls = f.readline().strip()
        if ls.startswith("##"):
            break

        ls = ls[1:-1]
        world.append([_decode(l) for l in ls])

    for i in range(generations):
        world = step(world)

    solution = ["".join(_encode(i) for i in b) for b in world]
    game = "\n".join("#{}#".format(i) for i in solution)
    total = "{0}\n{1}\n{0}\n".format(border, game)
    s.send(bytes(total, "ascii"))

# give them a second to catch up, we got big internet tubes
sleep(1)

print(str(s.recv(4096)).strip())

After we empirically tested how many rounds we actually needed to simulate, we ran a less clean version of the same code on the game server and got the key!

Congratulations!You made it!Here's your prize: key{that comp sci assignment was useful after all}