# BROP - Blind Return Oriented Programming {{#include ../../banners/hacktricks-training.md}} ## Basic Information The goal of this attack is to be able to **abuse a ROP via a buffer overflow without any information about the vulnerable binary**.\ This attack is based on the following scenario: - A stack vulnerability and knowledge of how to trigger it. - A server application that restarts after a crash. ## Attack ### **1. Find vulnerable offset** sending one more character until a malfunction of the server is detected ### **2. Brute-force canary** to leak it ### **3. Brute-force stored RBP and RIP** addresses in the stack to leak them You can find more information about these processes [here (BF Forked & Threaded Stack Canaries)](../common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md) and [here (BF Addresses in the Stack)](../common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md). ### **4. Find the stop gadget** This gadget basically allows to confirm that something interesting was executed by the ROP gadget because the execution didn't crash. Usually, this gadget is going to be something that **stops the execution** and it's positioned at the end of the ROP chain when looking for ROP gadgets to confirm a specific ROP gadget was executed ### **5. Find BROP gadget** This technique uses the [**ret2csu**](ret2csu.md) gadget. And this is because if you access this gadget in the middle of some instructions you get gadgets to control **`rsi`** and **`rdi`**:

https://www.scs.stanford.edu/brop/bittau-brop.pdf

These would be the gadgets: - `pop rsi; pop r15; ret` - `pop rdi; ret` Notice how with those gadgets it's possible to **control 2 arguments** of a function to call. Also, notice that the ret2csu gadget has a **very unique signature** because it's going to be poping 6 registers from the stack. SO sending a chain like: `'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP` If the **STOP is executed**, this basically means an **address that is popping 6 registers** from the stack was used. Or that the address used was also a STOP address. In order to **remove this last option** a new chain like the following is executed and it must not execute the STOP gadget to confirm the previous one did pop 6 registers: `'A' * offset + canary + rbp + ADDR` Knowing the address of the ret2csu gadget, it's possible to **infer the address of the gadgets to control `rsi` and `rdi`**. ### 6. Find PLT The PLT table can be searched from 0x400000 or from the **leaked RIP address** from the stack (if **PIE** is being used). The **entries** of the table are **separated by 16B** (0x10B), and when one function is called the server doesn't crash even if the arguments aren't correct. Also, checking the address of a entry in the **PLT + 6B also doesn't crash** as it's the first code executed. Therefore, it's possible to find the PLT table checking the following behaviours: - `'A' * offset + canary + rbp + ADDR + STOP` -> no crash - `'A' * offset + canary + rbp + (ADDR + 0x6) + STOP` -> no crash - `'A' * offset + canary + rbp + (ADDR + 0x10) + STOP` -> no crash ### 7. Finding strcmp The **`strcmp`** function sets the register **`rdx`** to the length of the string being compared. Note that **`rdx`** is the **third argument** and we need it to be **bigger than 0** in order to later use `write` to leak the program. It's possible to find the location of **`strcmp`** in the PLT based on its behaviour using the fact that we can now control the 2 first arguments of functions: - strcmp(\, \) -> crash - strcmp(\, \) -> crash - strcmp(\, \) -> crash - strcmp(\, \) -> no crash It's possible to check for this by calling each entry of the PLT table or by using the **PLT slow path** which basically consist on **calling an entry in the PLT table + 0xb** (which calls to **`dlresolve`**) followed in the stack by the **entry number one wishes to probe** (starting at zero) to scan all PLT entries from the first one: - strcmp(\, \) -> crash - `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP` -> Will crash - strcmp(\, \) -> crash - `b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP` - strcmp(\, \) -> no crash - `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP` Remember that: - BROP + 0x7 point to **`pop RSI; pop R15; ret;`** - BROP + 0x9 point to **`pop RDI; ret;`** - PLT + 0xb point to a call to **dl_resolve**. Having found `strcmp` it's possible to set **`rdx`** to a value bigger than 0. > [!TIP] > Note that usually `rdx` will host already a value bigger than 0, so this step might not be necesary. ### 8. Finding Write or equivalent Finally, it's needed a gadget that exfiltrates data in order to exfiltrate the binary. And at this moment it's possible to **control 2 arguments and set `rdx` bigger than 0.** There are 3 common funtions taht could be abused for this: - `puts(data)` - `dprintf(fd, data)` - `write(fd, data, len(data)` However, the original paper only mentions the **`write`** one, so lets talk about it: The current problem is that we don't know **where the write function is inside the PLT** and we don't know **a fd number to send the data to our socket**. However, we know **where the PLT table is** and it's possible to find write based on its **behaviour**. And we can create **several connections** with the server an d use a **high FD** hoping that it matches some of our connections. Behaviour signatures to find those functions: - `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then puts was found - `'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then dprintf was found - `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then write was found ## Automatic Exploitation - [https://github.com/Hakumarachi/Bropper](https://github.com/Hakumarachi/Bropper) ## References - Original paper: [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf) - [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop) {{#include ../../banners/hacktricks-training.md}}