**Tags:** s1c88 rev

Rating: 5.0

In short the check_flag function does the following:

1. XOR user input with a magic string

2. Convert the result to decimal and produce a large digit array that is interpreted as pairs of coordinates: [x0,y0,x1,y1,...,xn,yn]

3. Neighboring coordinates can’t share values x[i] != x[i+2] and y[i] != y[i+2]

4. Each consecutive pair of coordinates x1,y1 and x2,y2 specifies a line from x1,y1 to x2,y1 to x2,y2. Horizontal edges in the line are stored as value 5 in a path array while vertical edges are stored as 6. Corners in this path are stored as 1-4 depending on the orientation.

5. If any component of the path is self-intersecting, the check fails.

6. The path is validated using Masyu rules. Specifically there is a specified set of corner points (black dots) and edge points (white dots). Black dots must lie on a corner, white dots must lie on an edge and neighbor a corner:

![sol](https://ctf.harrisongreen.me/code/2021/plaidctf/sol.png)

We encode the solution digit array into our flag input:

```py

magic = bytes([

15,57,42,9,53,58,

0,59,51,10,33,3,

58,58,17,12,60,60,

13,60,13,0,9,54])

charset = b'\

ABCDEFGHIJKLMNOPQRSTUVWXYZ\

abcdefghijklmnopqrstuvwxyz\

0123456789{}'

def decode(arr):

d_str = ''.join([str(x) for x in arr])

d = int(d_str[::-1])

parts = [0] * 24

for i in range(24):

parts[i] = d & 0x3f

d >>= 6

parts = parts[::-1]

out = bytes([a^b for a,b in zip(parts, magic)])

a_out = bytes([charset[x] for x in out])

return a_out

decode([

1,4, 0,0, 2,2, 3,6, 4,2, 5,6,

6,2, 8,1, 3,0, 9,5, 8,3, 7,6,

9,9, 8,7, 6,8, 7,9, 2,8, 5,7,

1,9, 0,6, 2,3])

```

PCTF{5EEth4tFURR3Tw4lcc}

Original writeup (https://ctf.harrisongreen.me/2021/plaidctf/pokemini/).