Merge pull request #837 from 7Rocky/master

Review of binary exploitation techniques
This commit is contained in:
cp 2024-04-06 17:48:18 +02:00 committed by GitHub
commit e7515f2102
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 77 additions and 36 deletions

View file

@ -26,9 +26,14 @@ More info about One Gadget in:
[one-gadget.md](../one-gadget.md)
{% endcontent-ref %}
{% hint style="danger" %}
Note that hooks are **disabled for GLIBC >= 2.34**. There are other techniques that can be used on modern GLIBC versions. See [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).
{% endhint %}
## References
* [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)
* [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md)
<details>

View file

@ -54,7 +54,7 @@ Contents of section .fini_array:
Note that this **won't** **create** an **eternal loop** because when you get back to main the canary will notice, the end of the stack might be corrupted and the function won't be recalled again. So with this you will be able to **have 1 more execution** of the vuln.
{% hint style="danger" %}
Note that with [Full Relro](../common-binary-protections-and-bypasses/relro.md), the section `.fini_array` is made **read-only**.
Note that with [Full RELRO](../common-binary-protections-and-bypasses/relro.md), the section `.fini_array` is made **read-only**.
{% endhint %}
<details>

View file

@ -95,7 +95,7 @@ The previous data is for 32-bit systems and the reduced final entropy makes poss
for off in range(0xb7000000, 0xb8000000, 0x1000):
```
* If attacking a remote server, you could try to **burte-force the address of the `libc` function `usleep`**, passing as argument 10 (for example). If at some point the **server takes 10s extra to respond**, you found the address of this function.
* If attacking a remote server, you could try to **brute-force the address of the `libc` function `usleep`**, passing as argument 10 (for example). If at some point the **server takes 10s extra to respond**, you found the address of this function.
{% hint style="success" %}
In 64bit systems the entropy is much higher and this isn't possible.

View file

@ -39,12 +39,12 @@ payload = flat(
)
```
Note how **`puts`** (using the address from the PLT) is called with the address of `puts` located in the `GOT`. This is because by the time `puts` prints the `GOT` entry of puts, this **entry will contain the address of `puts` in memory**.
Note how **`puts`** (using the address from the PLT) is called with the address of `puts` located in the GOT (Global Offset Table). This is because by the time `puts` prints the GOT entry of `puts`, this **entry will contain the exact address of `puts` in memory**.
Also note how the address of `main` is used in the exploit so when `puts` ends its execution, the **binary calls `main` again instead of exiting** (so the leaked address will continue to be valid).
{% hint style="danger" %}
Note how in order for this to work the **binary cannot be compiled with PIE** or you must have **found a leak to bypass PIE** in order to know the address of the `PLT`, `GOT` and `main`.
Note how in order for this to work the **binary cannot be compiled with PIE** or you must have **found a leak to bypass PIE** in order to know the address of the PLT, GOT and `main`. Otherwise, you need to bypass PIE first.
{% endhint %}
You can find a [**full example of this bypass here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/ret2plt-aslr-bypass). This was the final exploit from that example:

View file

@ -22,13 +22,13 @@ Other ways to support HackTricks:
**Partial RELRO** takes a simpler approach to enhance security without significantly impacting the binary's performance. By **positioning the GOT above the program's variables in memory, Partial RELRO aims to prevent buffer overflows from reaching and corrupting the GOT**.&#x20;
This **doesn't prevent to GOT** to be abused **from arbitrary write** vulnerabilities.
This **doesn't prevent the GOT** to be abused **from arbitrary write** vulnerabilities.
### **Full RELRO**
**Full RELRO** steps up the protection by **making the GOT completely read-only.** Once the binary starts all the function addresses are resolved and loaded in the GOT, then, GOT is marked as read-only, effectively preventing any modifications to it during runtime.
However, the trade-off with Full RELRO is in terms of performance and startup time. Because it necessitates resolving all dynamic symbols at startup before marking the GOT as read-only, **binaries with Full RELRO enabled may experience longer load times**. This additional startup overhead is why Full RELRO is not enabled by default in all binaries.
However, the trade-off with Full RELRO is in terms of performance and startup time. Because it needs to resolve all dynamic symbols at startup before marking the GOT as read-only, **binaries with Full RELRO enabled may experience longer load times**. This additional startup overhead is why Full RELRO is not enabled by default in all binaries.
It's possible to see if Full RELRO is enabled in a binary with:
@ -40,6 +40,8 @@ readelf -l /proc/ID_PROC/exe | grep BIND_NOW
If Full RELRO is enabled, the only way to bypass it is to find another way that doesn't need to write in the GOT table to get arbitrary execution.
Note that LIBC's GOT is usually Partial RELRO, so it can be modified with an arbitrary write. More information in [Targetting libc GOT entries](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
<details>
<summary><strong>Learn AWS hacking from zero to hero with</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>

View file

@ -64,9 +64,21 @@ The stack vulnerable to a stack overflow might **contain addresses to strings or
[pointer-redirecting.md](../../stack-overflow/pointer-redirecting.md)
{% endcontent-ref %}
* **Modifying both master and thread canary**
A buffer overflow in a threaded function protected with canary can be used to modify the master canary of the thread. As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).
* **Modify the GOT entry of `__stack_chk_fail`**
If the binary has Partial RELRO, then you can use an arbitrary write to modify the GOT entry of `__stack_chk_fail` to be a dummy function that does not block the program if the canary gets modified.
## References
* [https://guyinatuxedo.github.io/7.1-mitigation\_canary/index.html](https://guyinatuxedo.github.io/7.1-mitigation\_canary/index.html)
* [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
* 64 bits, no PIE, nx, modify thread and master canary.
* [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
* 64 bits, no PIE, nx, write-what-where primitive. Modify GOT entry of `__stack_chk_fail`.
<details>

View file

@ -120,9 +120,13 @@ log.info(f"The canary is: {canary}")
## Threads
Threads of the same process will also **share the same canary token**, therefore it'll be possible to **brute-forc**e a canary if the binary spawns a new thread every time an attack happens.&#x20;
Threads of the same process will also **share the same canary token**, therefore it'll be possible to **brute-force** a canary if the binary spawns a new thread every time an attack happens.&#x20;
A buffer overflow in a threaded function protected with canary can be used to modify the master canary of the thread. As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).
## Other examples & references
* [https://guyinatuxedo.github.io/07-bof\_static/dcquals16\_feedme/index.html](https://guyinatuxedo.github.io/07-bof\_static/dcquals16\_feedme/index.html)
* 64 bits, no PIE, nx, BF canary, write in some memory a ROP to call `execve` and jump there.
* [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
* 64 bits, no PIE, nx, modify thread and master canary.

View file

@ -29,7 +29,7 @@ rop2 = base + p64(ONE_GADGET) + "\x00"*100
To the address indicated by One Gadget you need to **add the base address where `libc`** is loaded.
{% hint style="success" %}
One Gadget is a **great help for Arbitrary Write 2 Exec techniques** and might **simplifies ROP** chains as you only need to call one address (and fulfill the requirements).
One Gadget is a **great help for Arbitrary Write 2 Exec techniques** and might **simplify ROP chains** as you only need to call one address (and fulfill the requirements).
{% endhint %}
<details>

View file

@ -18,10 +18,10 @@ Other ways to support HackTricks:
A **stack overflow** is a vulnerability that occurs when a program writes more data to the stack than it is allocated to hold. This excess data will **overwrite adjacent memory space**, leading to the corruption of valid data, control flow disruption, and potentially the execution of malicious code. This issue often arises due to the use of unsafe functions that do not perform bounds checking on input.
The main problem of this overwrite is that the **EIP** and **EBP** pointers to return to the previos function are **stored in the stack**. Therefore, an attacker will be able to overwrite those and **control the execution flow of the program**.
The main problem of this overwrite is that the **saved instruction pointer (EIP/RIP)** and the **saved base pointer (EBP/RBP)** to return to the previous function are **stored on the stack**. Therefore, an attacker will be able to overwrite those and **control the execution flow of the program**.
The vulnerability usually arises because a function **copies inside the stack more bytes than the amount allocated for it**, therefore being able to overwrite other parts of the stack.\
Some common functions vulnerable to this are: `strcpy`, `strcat`, `sprintf`, `gets`, `fgets`...
Some common functions vulnerable to this are: `strcpy`, `strcat`, `sprintf`, `gets`... Also, functions like `fgets` or `read`, that take a length argument, might be used in a vulnerable way if the specified length is greater than the allocated one.
For example, the following functions could be vulnerable:
@ -36,11 +36,11 @@ void vulnerable() {
### Finding Stack Overflows
The most common way to find stack overflows is to give a very big input of `A`s (e.g. `python3 -c 'print("A"*1000)'`) and expected a `Segmentation Fault` indicating that the **address `0x41414141` was tried to be accessed**.
The most common way to find stack overflows is to give a very big input of `A`s (e.g. `python3 -c 'print("A"*1000)'`) and expect a `Segmentation Fault` indicating that the **address `0x41414141` was tried to be accessed**.
Moreover, once you found that there is Stack Overflow vulnerability you will need to find the offset until it's possible to **overwrite the EIP pointer**, for this it's usually used a **De Bruijn sequence.** Which for a given alphabet of size _k_ and subsequences of length _n_ is a **cyclic sequence in which every possible subsequence of length **_**n**_** appears exactly once** as a contiguous subsequence.
Moreover, once you found that there is Stack Overflow vulnerability you will need to find the offset until it's possible to **overwrite the return address**, for this it's usually used a **De Bruijn sequence.** Which for a given alphabet of size _k_ and subsequences of length _n_ is a **cyclic sequence in which every possible subsequence of length **_**n**_** appears exactly once** as a contiguous subsequence.
This way, instead of needing to figure out which offset is overwriting the EIP by hand, it's possible to use as padding one of these sequences and then find the offset of the bytes that ended overwriting it.
This way, instead of needing to figure out which offset is needed to control the EIP by hand, it's possible to use as padding one of these sequences and then find the offset of the bytes that ended overwriting it.
It's possible to use **pwntools** for this:
@ -67,14 +67,14 @@ pattern search $rsp #Search the offset given the content of $rsp
## Exploiting Stack Overflows
During an overflow (supposing the overflow size if big enough) you will be able to overwrite values of other variables inside the stack until reaching the EBP and EIP (or even more).\
The most common way to abuse this type of vulnerability is by **modifying the EIP pointer** so when the function ends the **control flow will be redirected wherever the user specified** in this pointer.
During an overflow (supposing the overflow size if big enough) you will be able to overwrite values of local variables inside the stack until reaching the saved EBP/RBP and EIP/RIP (or even more).\
The most common way to abuse this type of vulnerability is by **modifying the return address** so when the function ends the **control flow will be redirected wherever the user specified** in this pointer.
However, in other scenarios maybe just **overwriting some variables values in the stack** might be enough for the exploitation (like in easy CTF challenges).
### Ret2win
In this type of CTF challenges, there is a **function** **inside** the binary that is **never called** and that **you need to call in order to win**. For these challenges you just need to find the **offset to overwrite the EIP** and **find the address of the function** to call (usually [**ASLR**](../common-binary-protections-and-bypasses/aslr/) would be disabled) so when the vulnerable function returns, the hidden function will be called:
In this type of CTF challenges, there is a **function** **inside** the binary that is **never called** and that **you need to call in order to win**. For these challenges you just need to find the **offset to overwrite the return address** and **find the address of the function** to call (usually [**ASLR**](../common-binary-protections-and-bypasses/aslr/) would be disabled) so when the vulnerable function returns, the hidden function will be called:
{% content-ref url="ret2win.md" %}
[ret2win.md](ret2win.md)
@ -82,7 +82,7 @@ In this type of CTF challenges, there is a **function** **inside** the binary th
### Stack Shellcode
In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP to go to the shellcode and execute the attackers code:
In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP/RIP to jump to the shellcode and execute arbitrary code:
{% content-ref url="stack-shellcode.md" %}
[stack-shellcode.md](stack-shellcode.md)
@ -90,7 +90,7 @@ In this scenario the attacker could place a shellcode in the stack and abuse the
## ROP
This technique is the fundamental framework to bypass the main protection to the previous technique: **No executable stack**. And it allows to perform several other techniques (ret2lib, ret2syscall...) that will end executeing arbitrary commands by abusing existing intructions in the binary:
This technique is the fundamental framework to bypass the main protection to the previous technique: **No executable stack** (NX). And it allows to perform several other techniques (ret2lib, ret2syscall...) that will end executing arbitrary commands by abusing existing intructions in the binary:
{% content-ref url="rop-return-oriented-programing.md" %}
[rop-return-oriented-programing.md](rop-return-oriented-programing.md)

View file

@ -14,7 +14,7 @@ Other ways to support HackTricks:
</details>
## **Rest2esp**
## **Ret2esp**
**Because the ESP (Stack Pointer) always points to the top of the stack**, this technique involves replacing the EIP (Instruction Pointer) with the address of a **`jmp esp`** or **`call esp`** instruction. By doing this, the shellcode is placed right after the overwritten EIP. When the `ret` instruction executes, ESP points to the next address, precisely where the shellcode is stored.

View file

@ -17,7 +17,7 @@ Other ways to support HackTricks:
## Quick Resume
1. **Find** overflow **offset**
2. **Find** `POP_RDI`, `PUTS_PLT` and `MAIN_PLT` gadgets
2. **Find** `POP_RDI` gadget, `PUTS_PLT` and `MAIN`
3. Use previous gadgets lo **leak the memory address** of puts or another libc function and **find the libc version** ([donwload it](https://libc.blukat.me))
4. With the library, **calculate the ROP and exploit it**

View file

@ -205,7 +205,7 @@ P.interactive() #Interact with your shell :)
## MAIN\_PLT = elf.symbols\['main'] not found
If the "main" symbol does not exist. Then you can just where is the main code:
If the "main" symbol does not exist (probably because it's a stripped binary). Then you can just where is the main code:
```python
objdump -d vuln_binary | grep "\.text"

View file

@ -16,7 +16,7 @@ Other ways to support HackTricks:
## Basic Information
**Ret2win** challenges are a popular category in **Capture The Flag (CTF)** competitions, particularly in tasks that involve **binary exploitation**. The goal is to exploit a vulnerability in a given binary to execute a specific, uninvoked function within the binary, often named something like `win`, `ret2win`, etc. This function, when executed, usually prints out a flag or a success message. The challenge typically involves overwriting the **return address** on the stack to divert execution flow to the desired function. Here's a more detailed explanation with examples:
**Ret2win** challenges are a popular category in **Capture The Flag (CTF)** competitions, particularly in tasks that involve **binary exploitation**. The goal is to exploit a vulnerability in a given binary to execute a specific, uninvoked function within the binary, often named something like `win`, `flag`, etc. This function, when executed, usually prints out a flag or a success message. The challenge typically involves overwriting the **return address** on the stack to divert execution flow to the desired function. Here's a more detailed explanation with examples:
### C Example
@ -89,7 +89,7 @@ The Python script sends a carefully crafted message that, when processed by the
## Protections
* [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **should be disabled** for the address to be reliable across executions or the address where the function will be stored won't be always the same and you would need some leak in order to figure out where is the win function loaded.
* [**PIE**](../common-binary-protections-and-bypasses/pie/) **should be disabled** for the address to be reliable across executions or the address where the function will be stored won't be always the same and you would need some leak in order to figure out where is the win function loaded. In some cases, when the function that causes the overflow is `read` or similar, you can do a **Partial Overwrite** of 1 or 2 bytes to change the return address to be the win function. Because of how ASLR works, the last three hex nibbles are not randomized, so there is a **1/16 chance** (1 nibble) to get the correct return address.
* [**Stack Canaries**](../common-binary-protections-and-bypasses/stack-canaries/) should be also disabled or the compromised EIP return address won't never be followed.
## Other examples & References
@ -105,6 +105,8 @@ The Python script sends a carefully crafted message that, when processed by the
* 32 bits, no ASLR, double small overflow, first to overflow the stack and enlarge the size of the second overflow
* [https://guyinatuxedo.github.io/10-fmt\_strings/backdoor17\_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt\_strings/backdoor17\_bbpwn/index.html)
* 32 bit, relro, no canary, nx, no pie, format string to overwrite the address `fflush` with the win function (ret2win)
* [https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/](https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/)
* 64 bit, relro, no canary, nx, pie. Partial overwrite to call the win function (ret2win)
<details>

View file

@ -24,6 +24,10 @@ Other ways to support HackTricks:
2. **Gadget Chaining**: The attacker then carefully selects and chains gadgets to perform the desired actions. This could involve setting up arguments for a function call, calling the function (e.g., `system("/bin/sh")`), and handling any necessary cleanup or additional operations.
3. **Payload Execution**: When the vulnerable function returns, instead of returning to a legitimate location, it starts executing the chain of gadgets.
### Tools
Typically, gadgets can be found using **[ROPgadget](https://github.com/JonathanSalwan/ROPgadget)**, **[ropper](https://github.com/sashs/Ropper)** or directly from **pwntools** ([ROP](https://docs.pwntools.com/en/stable/rop/rop.html)).
## ROP Chain in x86 Example
### **x86 (32-bit) Calling conventions**
@ -37,7 +41,7 @@ First, let's assume we've identified the necessary gadgets within the binary or
* `pop eax; ret`: This gadget pops the top value of the stack into the `EAX` register and then returns, allowing us to control `EAX`.
* `pop ebx; ret`: Similar to the above, but for the `EBX` register, enabling control over `EBX`.
* `mov [ebx], eax; ret`: Moves the value in `EAX` to the memory location pointed to by `EBX` and then returns.
* `mov [ebx], eax; ret`: Moves the value in `EAX` to the memory location pointed to by `EBX` and then returns. This is often called a **write-what-where gadget**.
* Additionally, we have the address of the `system()` function available.
### **ROP Chain**
@ -60,7 +64,7 @@ p = process(binary.path)
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))
# Address of system() function (hypothetical value)
system_addr = 0xdeadcode
system_addr = 0xdeadc0de
# A gadget to control the return address, typically found through analysis
ret_gadget = 0xcafebabe # This could be any gadget that allows us to control the return address
@ -105,7 +109,7 @@ And we know the address of the **system()** function.
Below is an example using **pwntools** to set up and execute a ROP chain aiming to execute **system('/bin/sh')** on **x64**:
```python
pythonCopy codefrom pwn import *
from pwn import *
# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')

View file

@ -16,7 +16,7 @@ Other ways to support HackTricks:
## Basic Information
This is similar to Ret2lib, however, in this case we won't be calling a function from a library. In this case, everything will be prepared to call the syscall `sys_execve` with some aregumentes to execute `/bin/sh`.
This is similar to Ret2lib, however, in this case we won't be calling a function from a library. In this case, everything will be prepared to call the syscall `sys_execve` with some arguments to execute `/bin/sh`. This technique is usually performed on binaries that are compiled statically, so there might be plenty of gadgets and syscall instructions.
In order to prepare the call for the **syscall** it's needed the following configuration:
@ -28,10 +28,10 @@ In order to prepare the call for the **syscall** it's needed the following confi
So, basically it's needed to write the string `/bin/sh` somewhere and then perform the `syscall` (being aware of the padding needed to control the stack). For this, we need a gadget to write `/bin/sh` in a known area.
{% hint style="success" %}
Another interesting syscall to call is **`mprotect`** which would allow an attacker to **modify the permissions of a page in memory**.
Another interesting syscall to call is **`mprotect`** which would allow an attacker to **modify the permissions of a page in memory**. This can be combined with [ret2shellcode](stack-shellcode.md).
{% endhint %}
## Register Gadgets
## Register gadgets
Let's start by finding **how to control those registers**:
@ -64,11 +64,19 @@ Start End Offset Perm Path
Then you need to find a way to write arbitrary content in this address
```python
```bash
ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx
```
### Automate ROP chain
The following command creates a full `sys_execve` ROP chain given a static binary when there are write-what-where gadgets and syscall instructions:
```bash
ROPgadget --binary vuln --ropchain
```
#### 32 bits
```python
@ -119,6 +127,8 @@ If you are **lacking gadgets**, for example to write `/bin/sh` in memory, you ca
[srop-sigreturn-oriented-programming.md](srop-sigreturn-oriented-programming.md)
{% endcontent-ref %}
There might be gadgets in the vDSO region, which is used to change from user mode to kernel mode. In these type of challenges, usually a kernel image is provided to dump the vDSO region.
## Exploit Example
```python
@ -196,6 +206,8 @@ target.interactive()
* 64 bits, nx, no PIE, write in some memory a ROP to call `execve` and jump there. In order to write to the stack a function that performs mathematical operations is abused
* [https://guyinatuxedo.github.io/07-bof\_static/dcquals16\_feedme/index.html](https://guyinatuxedo.github.io/07-bof\_static/dcquals16\_feedme/index.html)
* 64 bits, no PIE, nx, BF canary, write in some memory a ROP to call `execve` and jump there.
* [https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/)
* 32 bits, no ASLR, use vDSO to find ROP gadgets and call `execve`.
<details>

View file

@ -21,8 +21,8 @@ This technique exploits the ability to manipulate the **Base Pointer (EBP)** to
As a reminder, **`leave`** basically means:
```
movl %ebp, %esp
popl %ebp
mov esp, ebp
pop ebp
ret
```
@ -65,7 +65,7 @@ Now, the **`ESP`** is controlled pointing to a desired address and the next inst
Basically this way it's possible to chain several fake EBPs to control the flow of the program.
Tbh, this is like a [ret2lib](ret2lib/), but more complex with no apparent benefit but could be interesting in some edge-cases.
This is like a [ret2lib](ret2lib/), but more complex with no apparent benefit but could be interesting in some edge-cases.
Moreover, here you have an [**example of a challenge**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) that uses this technique with a **stack leak** to call a winning function. This is the final payload from the page:
@ -186,12 +186,12 @@ p.sendline(payload)
print(p.recvline())
```
### xchg \<rag>, rsp gadget
### xchg \<reg>, rsp gadget
```
pop <reg> <=== return pointer
<reg value>
xchg <rag>, rsp
xchg <reg>, rsp
```
## References