There’s this cool new forward compatible ISA. I created an online emulator so that you can try it out!

Category: pwn

Solver: t0b1

Flag: GPNCTF{Ar3_y0u_Re4dy_for_th3_re4l_Chal1eng3?_ee9d22353e82}

Writeup

In this challenge, we are provided with a Dockerfile, an app.py, a forw binary and an instruction_list.csv. It is primarily a warm-up challenge to play with the ForwardCom ecosystem.

Overview

We first look at the Dockerfile to find out more about the setup of the challenge:

  1. It downloads https://github.com/ForwardCom/bintools/archive/779c06891cba05a97a214a23b7a63aeff25d983a.tar.gz and builds the binaries via make -f forw.make. This is where the forw binary and instruction_list.csv seem to come from.
  2. It places the flag at /flag, so we need to read that.
  3. It runs the app.py script with flask, so this is what we can interact with.

Because the app.py is what we interact with, we check this one out next. It provides an upload form and executes the upload_file function once we submit a file:

@app.route("/upload", methods=["POST"])
def upload_file():
    if "file" not in request.files:
        return redirect(url_for("upload_form"))
    file = request.files["file"]
    file.save("/tmp/binary.ex")
    data = subprocess.check_output(["/app/forw", "-emu", "/tmp/binary.ex"])
    return data[-500:]

It saves the program to /tmp/binary.ex and uses it to run /app/forw -emu /tmp/binary.ex.

So what is that forw binary doing? Enter ForwardCom.

ForwardCom ISA

According to the official website https://www.forwardcom.info/, ForwardCom is an experimental instruction set architecture (ISA) and wants to be more efficient than existing systems such as x86 and ARM.

There is the ForwardCom Manual which describes the ISA in detail. Amongst many other things it defines how the actual CPU instructions are designed and how the syntax of the assembly language looks like.

The bintools repository provides all the tools necessary to work with the ISA, most importantly for us an assembler, a linker, and an emulator. Similar to that you can’t run ARM binaries on x86, you can’t run ForwardCom binaries natively, which is what the emulator is for. The emulator is being executed when you pass the -emu flag to the forw executable, so that is how the file we upload is interpreted: It is a ForwardCom executable.

Building a ForwardCom executable

Since we can upload ForwardCom executables which are executed via the emulator, we’ll need to write one that prints us the flag from /flag.

How do we start? Luckily for us, the designers of ForwardCom provide us with a range of code-examples to get a feeling for the assembly language. Additionally, they even provide a set of libraries including a libc.li which contains some of the C standard library functions.

Looking through the available functions we find three which we can use to get the flag:

  • fopen to open a file
  • fread to read from a file
  • puts to print a string

Following the code examples we can built a small program which executes these three functions and should print the flag:

%buffersize = 0x40

const section read ip
flag:    int8 "/flag",0 
mode:    int8 "r",0 
const end

bss section datap uninitialized
int8 buf[buffersize]
bss end

code section execute

extern _puts: function
extern _fopen: function
extern _fread: function

_main function public
// fopen(flag, mode)
int64 r0 = address([flag])
int64 r1 = address([mode])
call _fopen

// fread(buf, 1, 0x40, flag_file)
int64 r3 = r0
int64 r2 = buffersize
int64 r1 = 1
int64 r0 = address([buf])
call _fread

// puts(buf)
int r0 = address([buf])
call _puts

_main end

code end

Given this code in solve.as, we can use the forw binary to assemble it into an object file:

./forw -ass solve.as

Then, we need to link it with the libc library (which we use the functions of) to produce the final executable. Since the challenge doesn’t come with the libraries included, we’ll clone them locally first.

git clone https://github.com/ForwardCom/libraries.git

The repository already contains a compiled version of the libc library libc.li so we can easily link that with our object file to produce the desired executable:

./forw -link solve.ex solve.ob libraries/libc.li

Finally, upload the solve.ex executable and get the flag :)