Skip to content

Instantly share code, notes, and snippets.

@ArmindoFlores
Last active December 19, 2020 00:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ArmindoFlores/21bea2dd3e75040115498754f42864c6 to your computer and use it in GitHub Desktop.
Save ArmindoFlores/21bea2dd3e75040115498754f42864c6 to your computer and use it in GitHub Desktop.
Santa's ELF holomorphing machine Writeup

X-MAS CTF 2020

Category: Programming Points: 500

Description: We have intercepted the blueprints and a memory dump for another of Santa's wicked contraptions. What is the old man hiding this time around?

Author: PinkiePie1189


Write-up

This challenge provided a pdf file with a mock scientific paper talking about "Santa's ELF holomorphing machine". It described a process in which n imaginary numbers zi are morphed into fi(z). It also mentioned that in this machine, only the real or imaginary components of f were ever stored at one point in time.

First Impressions

After examining the data.txt file, we could see that we were being provided with lots of functions, u or v, which were probably the real and imaginary parts of a complex function fi(z) = u + iv. In each line, we were also given a complex number z.

Recovering fi(z)

Because f is a holomorphic function, we know that u and v must be harmonic conjugates and satisfy the Cauchy-Riemann conditions.

We can write this as a system of equations and solve for either u or v, for any u or v such that u(x, y) = αx + βy (we can see that this is the format they have in data.txt)

From here we can primitive v with respect to either x or y. Let's choose the latter:

And we can now substitute in the partial derivative of v with respect to x with the expression we just calculated:

Doing the same for u(x, y) we get that for u(x, y) = αx + βy then v(x, y) = αy - βx and for v(x, y) = αx + βy then u(x, y) = βx - αy

Plotting

Now we can write some python code to recover every function from the data.txt file

with open("data.txt", "r") as file:
    lines = file.read().split("\n")[:-1]

lines[:] = map(lambda i: i.split("; "), lines)

for (func, point) in lines:
    # Calculate f(x, y) based on u or v
    if func.startswith("u"):
        a, b = re.findall("(-?[0-9]+) \* x \+ (-?[0-9]+) \* y", func.split(" = ")[-1])[0]
        expr = f"{a} * x + {b} * y + 1j * ({a} * y - {b} * x)"
    elif func.startswith("v"):
        a, b = re.findall("(-?[0-9]+) \* x \+ (-?[0-9]+) \* y", func.split(" = ")[-1])[0]
        expr = f"{b} * x - {a} * y + 1j * ({b} * y + {a} * x)"

There are probably many other (better) ways of extracting a and b from the data, but we're not really interested in how we extract them, just that we do. When we run this, expr is a python expression equivelent to our fi(z), and can be evaluated at any point of our choosing.

We can try to evaluate each function at the given point

# Get point
x, y = re.findall("(-?[0-9]+(?:\.[0-9]+)?) \+ (-?[0-9]+(?:\.[0-9]+)?) \* i", point.split(" = ")[-1])[0]
x, y = float(x), float(y)
result = eval(expr)

and plot it using the real and imaginary components as our x's and y's.

import re
import pygame

pygame.init()
surface = pygame.Surface([305, 20])
surface.fill([255, 255, 255])

with open("data.txt", "r") as file:
    lines = file.read().split("\n")[:-1]

lines[:] = map(lambda i: i.split("; "), lines)

for (func, point) in lines:
    # Calculate f(x, y) based on u or v
    if func.startswith("u"):
        a, b = re.findall("(-?[0-9]+) \* x \+ (-?[0-9]+) \* y", func.split(" = ")[-1])[0]
        expr = f"{a} * x + {b} * y + 1j * ({a} * y - {b} * x)"
    elif func.startswith("v"):
        a, b = re.findall("(-?[0-9]+) \* x \+ (-?[0-9]+) \* y", func.split(" = ")[-1])[0]
        expr = f"{b} * x - {a} * y + 1j * ({b} * y + {a} * x)"

    # Get point
    x, y = re.findall("(-?[0-9]+(?:\.[0-9]+)?) \+ (-?[0-9]+(?:\.[0-9]+)?) \* i", point.split(" = ")[-1])[0]
    x, y = float(x), float(y)
    result = eval(expr)
    surface.set_at([round(result.real), round(result.imag)], [0, 0, 0])
pygame.image.save(surface, "flag.png")

And we get our result:

X-MAS{C4uchy_4nd_Ri3m4nn_ar3_c0ming_t0_t0wn}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment