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 | $ nc 54.159.113.26 19600 |
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 | $ nc 54.159.113.26 19600 |
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 | J input a value from the keyboard and store it in register 1 |
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 | $ nc 54.159.113.26 19600 |
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 | $ echo GCLSigggO | nc 54.159.113.26 19600 |
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 | $ echo GCLSkO | nc 54.159.113.26 19600 |
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 | $ echo ZUTZiiihhGCLSP | nc 54.159.113.26 19600 |
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).