It’s been quite a while since I’ve posted here, I hope everyone is doing well.
Been busy with school ever since it started, so I haven’t had much time to make decent writeups. Thankfully, with exams on the horizon, I’ll finally have time to write some posts.
Anyway, first things first, I think I’ll be moving away from Hugo in the upcoming months. I’ve been looking at eleventy Astro recently and it looks pretty promising. Hopefully the shift doesn’t break too many of my old posts, but if they do just know I won’t be fixing them. cuz im lazy
In terms of cybersecurity, I finally got a job! Hooray. Still looking for something for the summer but at least I get some working experience.
As for CTFs, I’ve been doing them like normal. Unfortunately I’ll probably never be able to go back and make writeups for most of them, but some fun ones I did recently include UDCTF, LakeCTF Quals, and HITCON.
At HITCON, we managed to qualify for the finals and got 2nd place! Really fun CTF even if I didn’t mess with too much of the A/D side (was farming koth xd).
I also qualified and went to CSAW Finals, but unfortunately I spent my entire time tunnel-visioned on one challenge so I didn’t do too well. Still pretty fun, and the food in NYC was great. (Unfortunately I did lose my phone on the way back, but that’s a story for another time.)
With those updates out of the way, let’s get to the teaser.
Teaser
In the upcoming months with the transition to eleventy Astro, I also plan on making a series of blog posts where I dive into different programming languages and discuss their features, mainly discussing how I would approach reversing them for CTFs.
Note that my advice may not be the best, but this is mainly more for me to force myself to learn these languages rather than as an actual guide.
As a teaser for the first post, if you played in HITCON Finals recently, you may recall the KOTH challenge expansion, where you were given 5 different “binaries” all compiled with ELVM. I’ll be going over one of the esolangs from that challenge, Befunge, so as a gift here’s a basic (and possibly slightly broken) interpreter that I’ve written.
from random import randintimport os.pathimport sys
class BefungeGrid:    grid = {}    def __init__(self):        self.grid = {}        self.row_bound = 0        self.col_bound = 0
    def __getitem__(self, key):        if type(key) == tuple:            # parse as row, col            return self.grid.get(key[0], {}).get(key[1], " ")
        return self.grid.get(key, {}) # ? may be incomplete row, due to being sparse
    def __setitem__(self, key, value):        if type(key) == tuple:            # parse as row, col            self.grid.setdefault(key[0], {})[key[1]] = value        else:            self.grid[key] = value
    def read_file(self, filename):        data = open(filename).readlines()        self.col_bound = len(data)        for row, line in enumerate(data):            line = line.strip('\n') # remove trailing newline            self.row_bound = max(self.row_bound, len(line))            for col, char in enumerate(line):                if char != ' ':                    self.grid.setdefault(row, {})[col] = char
    # for bounds, we assume only the original grid matters    # THIS IS IMPT IF YOU OVERWRITE AN AREA NEAR THE EDGE    def get_row_bound(self):        return self.row_bound
    def get_col_bound(self):        return self.col_bound
class Stack:    def __init__(self):        self.stack = []
    def pop(self, value=None):        if value:            return self.stack.pop(value) if self.stack else 0        else:            return self.stack.pop() if self.stack else 0
    def append(self, value):        self.stack.append(value)
    def __getitem__(self, key):        if not self.stack: # empty stack            return 0        return self.stack[key]
# GLOBAL VARIABLESgrid = BefungeGrid() # BEFUNGE GRIDx = 0                # X COORDINATE OF POINTERy = 0                # Y COORDINATE OF POINTERdirection = 0        # CURRENT DIRECTION OF MOTIONstack = Stack()      # STACK OF POINTERinQuotes = False     # WHETHER WE'RE IN STRING MODEglobalPC = 0         # GLOBAL PROGRAM COUNTER
def befunge_main(filename):    global grid, x, y, direction, stack, inQuotes    global globalPC, runFail, flag_i    grid = BefungeGrid()        # BEFUNGE GRID    x, y = 0, 0                 # POINTER    direction = 0               # CURRENT DIRECTION OF MOTION    stack = Stack()             # LIFO NUMBER STORAGE    inQuotes = False            # WHETHER WE'RE IN STRING MODE    globalPC = 0                # GLOBAL PROGRAM COUNTER
    grid.read_file(filename)    # printGrid(grid)
    while grid[y, x] != "@" and not runFail:        globalPC += 1        step()
def printGrid(grid: BefungeGrid, MAX_X=100, MAX_Y=100):    """Print the grid to the console"""    for row in range(MAX_Y):        for col in range(grid.get_row_bound()):            print(grid[row, col], end="")        print()
def step():    # print(f"{globalPC} ({y}, {x}) {grid[y, x]}")    processInstruction(grid[y, x])    move()
def processInstruction(inst: str):    global direction, inQuotes
    # IN STRING MODE    if inQuotes and inst != '"':        stack.append(ord(inst))        return
    # NOP    if inst == " ":        return
    # TOGGLE STRING MODE    elif inst == '"':        inQuotes = not inQuotes
    # MOVEMENT    elif inst in '>v<^':        direction = '>v<^'.index(inst)
    elif inst == '#': # skip        move()
    # LITERAL    elif inst.isdigit():        stack.append(int(inst))
    # ARITHMETIC    elif inst in '+-*%':        a, b = stack.pop(), stack.pop()        stack.append(eval(f'{b}{inst}{a}'))    elif inst == '/': # special case        a, b = stack.pop(), stack.pop()        stack.append(b // a)
    # BOOLEAN    elif inst == '!': # logical not        stack.append(not stack.pop())
    elif inst == '`': # greater than        a, b = stack.pop(), stack.pop()        stack.append(int(b > a))
    # RANDOM    elif inst == '?': # random direction        direction = randint(0, 3)
    # CONDITIONALS    elif inst == '_': # horizontal if        if not stack.pop():            direction = 0        else:            direction = 2
    elif inst == '|':        if not stack.pop():            direction = 1        else:            direction = 3
    # STACK OPS    elif inst == ':': # dup        stack.append(stack[-1])
    elif inst == '\\': # swap        a, b = stack.pop(), stack.pop()        stack.append(a)        stack.append(b)
    elif inst == '$': # pop        stack.pop()
    # OUTPUT    elif inst == '.': # output int        print(stack.pop(), end=" ")
    elif inst == ',': # output char        print(chr(stack.pop()), end="")
    # MODIFY    # THESE HAVE SPECIAL BEHAVIOR WHEN DATA IS NOT ASCII    elif inst == 'p': # put        y, x, v = stack.pop(), stack.pop(), stack.pop()        if 32 <= v <= 126:            grid[y, x] = chr(v)        else:            grid[y, x] = v
    elif inst == 'g': # get        y, x = stack.pop(), stack.pop()        v = grid[y, x]        if type(v) == str:            stack.append(ord(v))        else:            stack.append(v)
    # INPUT    elif inst == '&': # input int        stack.append(int(input("(n) > ")))
    elif inst == '~': # input char        stack.append(ord(input("(c) > ")))
def move():    global x, y    # right, down, left, up    dxy = [(0, 1), (1, 0), (0, -1), (-1, 0)]    dy, dx = dxy[direction]    x += dx    y += dy
    # WRAP AROUND IF NECESSARY    x %= grid.get_row_bound()    y %= grid.get_col_bound()
def main():    global globalPC    if len(sys.argv) < 2:        print("ERROR: No input file specified!")        sys.exit()
    filename = sys.argv[1]    if not os.path.isfile(filename):        print("ERROR: Specified input file does not exist!")        sys.exit()
    befunge_main(filename)
if __name__ == "__main__":    main()And of course, I can’t end the teaser without a challenge. Here’s a small Befunge program that I wrote, can you figure out what it does?
      >92+2*1+3*99*99*vv  *99               p<&\     >:00p -,  v     \  >\:|:\ +1 g00<  -  @  3  0  ^"Vmt ekg$nz("0<                 |    <          @,,"NO"<>99*g 55+::**67**+  -!^That’s all for now, see you soon!
 
 