ISH (1) (pwn)

Shell(a.k.a sh) is a text-based interface where users can type commands to interact with the operating system. I'm trying to implement a shell using ISA, I call it ISH.

This is an interesting pwn challenge because we are given a custom instruction set (known as the Bauhinia ISA). We need to understand the given instruction set and the provided assembly, before finding vulnerabilities in the code. Below is the assembly code of the vulnerable binary.

The challenge description also tells us that we will get the flag just by executing the flag1 binary in the remote host. The instruction set documentation can be found here and the ISA interpreter source code can be found here.

To summarise, the program has several commands:

  1. help - Shows a list of available commands

  2. ls - Lists all available files

  3. curl - Retrieves a file from online

  4. head - Reads the first 500 bytes from a file to stdout.

  5. game - Executes a binary called game.

Let's first look through the syscalls invoked when curl is used:

MOV R8, 0;
SYSCALL; <- read 0x64 bytes into buffer as the input to curl after https:// at address 0xffffff08
...
MOV R8, 6;
SYSCALL; <- actually downloads the file as `downloaded_file`
  1. We use a read syscall with R8 set to 0, and with R1 set to 0xffffff08 and R2 set to 0x64. This means we read up to 0x64 bytes into 0xffffff08. On inspecting the memory we observer that at 0xffffff00 is the string https://, which prefixes the URL we provide.

  2. Then, we use a download syscall with R8 set to 6, with R2 set to 0xffffff00 and R1 set to 0xfffffef0. R2 is the start of the URL we just entered, and R1 is a pointer to the string "downloaded_file". This causes the file to be downloaded with the name "downloaded_file".

Now we inspect the syscalls when game is called:

MOV R8, 5;
SYSCALL; <- execute ./game

We use the exec syscall wherein R8 is set to 5. In the exec syscall, R1 should point to the filename to be executed. Notice that R1 is 0xffffff64, which is a pointer to the string "game".

Here we notice a problem: In the curl command, 0x64 bytes are written to 0xffffff08. In the game command, the string "game" is at 0xffffff64. This means that if our URL sent is too long (exceeds 0x5c bytes), we overflow the game string and can overwrite up to 8 bytes.

Therefore the solution is to call the curl command, then input some valid URL. Then, add null bytes (0x00) until we reach 0xffffff64. Then, overwrite the game string with the string flag1. After sending this payload, when we use the game command, the flag1 binary will be executed.

Below is an example of how I generated the hex payload to curl using Python:

pl = b'file.io/bV6LUgd9sMWH'.hex()
pl += (0x5c - len(pl) // 2) * '00'
pl += b'flag1'.hex()

Last updated