angstromCTF 2019 Just Letters Writeup

I’ve encountered a lot of esolangs (esoteric languages) through CTFs. My very first one was Shakespeare Programming Language from PicoCTF 2014. MTEM 2018 CTF had an entire category dedicated to esolangs. angstromCTF 2019‘s Just Letters featured the AlphaBeta esolang:

Hope you’ve learned the alphabet!
nc 54.159.113.26 19600


Let’s dive in:

1
2
3
$ nc 54.159.113.26 19600
Welcome to the AlphaBeta interpreter! The flag is at the start of memory. You get one line:
>

Okay, straightforward enough. I’m told that the flag is at the start of memory. Just to test things out, I’ll input the Hello World program from the AlphaBeta esolang page (removing all the newlines since I’m told I only get one line):

1
2
3
4
$ nc 54.159.113.26 19600
Welcome to the AlphaBeta interpreter! The flag is at the start of memory. You get one line:
> cccCISccccCIScccCIYxSGSHaaCLgDLihhhDLDLgggDLTTGaaCLSGccbbbCLDLgggDLjggggDLSHDLTTGaaaCL
Hello World!

Alright, looks like it worked. Like all esolangs, AlphaBeta has pointers and registers and can modify memory, move data, and the like. Encountering enough esolangs, you start to get familiar with these constructs which are needed to build a language.

I didn’t want to spend too much time learning AlphaBeta so I wanted to build off of one of the three examples on the AlphaBeta esolang page. In particular, I looked at the Cat program:

1
JCLigggO

It looks like what this does is:

1
2
3
4
5
6
J     input a value from the keyboard and store it in register 1
C sets register 3 to the value of register 1
L outputs a character to the screen
i adds 10 to register 2
g adds 1 to register 2
O if register 1 does not equal register 2, goto the position at the position register

It looks like this is some kind of loop that reads input one character at a time from stdin and then outputs it to the screen. Instead of using J, I found that G might be handy:

1
G     sets register 1 to the memory at the memory pointer

So instead of reading from stdin to print, the interpreter will read from the first memory location. I’m going to try sending in the Cat program except with a G instead of a J:

1
2
3
4
5
$ nc 54.159.113.26 19600
Welcome to the AlphaBeta interpreter! The flag is at the start of memory. You get one line:
> GCLigggO
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...
aaaaaaaaaa^C

Woah there. CTRL+C IMMEDIATELY. I kept getting a bajillion a output. Since the flag format of the CTF is actf{FLAG}, I figured that what the interpreter is probably doing is continually printing the first character over and over again. After some thought, this makes sense since I didn’t bother to move the memory pointer forward by 1. I can do this right after the interpreter outputs the character to the screen with L. S is useful here:

1
S     adds 1 to the register

By the register, the page means the memory pointer. The commands S, T, U, V, W, X, Y, and Z act on either the memory pointer or the position pointer depending on which “mode” the interpreter is in. By default, the interpreter starts on the memory pointer, which is exactly what I need.

1
2
3
$ echo GCLSigggO | nc 54.159.113.26 19600
Welcome to the AlphaBeta interpreter! The flag is at the start of memory. You get one line:
> actf{esolangs_sure_are_fun!}You broke it. Are you proud?

Frankly, I don’t care that I broke it because I still got the flag: actf{esolangs_sure_are_fun!}. Easy money!

As an addendum, I think I get the You broke it. Are you proud? message because the interpreter ends up reading a memory region that it isn’t supposed to read (past the flag). I can shorten the solution even further:

1
2
3
$ echo GCLSkO | nc 54.159.113.26 19600
Welcome to the AlphaBeta interpreter! The flag is at the start of memory. You get one line:
> actf{esolangs_sure_are_fun!}You broke it. Are you proud?

The above is the shortest solution that I believe I can get. If I wanted to do things correctly, I’d use the position register to loop back to a certain point in the program (and not just the beginning) like so:

1
2
3
$ echo ZUTZiiihhGCLSP | nc 54.159.113.26 19600
Welcome to the AlphaBeta interpreter! The flag is at the start of memory. You get one line:
> actf{esolangs_sure_are_fun!}

This gives the solution with the exact characters (knowing that the flag is 28 characters) without telling me that I broke it.

Sidenote: Not sure why P is used here. I think the interpreter should be using Q instead but might have these two instructions flipped, as Q loops as long as register 1 (our indexing variable) is less than or equal to register 2 (the length of the flag).