Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ Each symbol entry contains:

#### GNU IFUNC (indirect functions)

- GCC can emit `STT_GNU_IFUNC` symbols with the `__attribute__((ifunc("resolver")))` extension. The dynamic loader calls the resolver at load time to select the concrete implementation (commonly CPU dispatch).
- GCC can emit `STT_GNU_IFUNC` symbols with the `__attribute__((ifunc("resolver")))` extension. The dynamic loader calls the resolver at load time to select the concrete implementation (commonly CPU dispatch).<sup>[[1]](#references)</sup>
- Quick triage: `readelf -sW ./bin | rg -i "IFUNC"`

#### GNU Symbol Versioning (dynsym/dynstr/gnu.version)
Expand Down Expand Up @@ -268,7 +268,7 @@ The NEEDED directory indicates that the program **needs to load the mentioned li

### Dynamic loader search order (RPATH/RUNPATH, $ORIGIN)

The entries `DT_RPATH` (deprecated) and/or `DT_RUNPATH` influence where the dynamic loader searches for dependencies. Rough order:
The entries `DT_RPATH` (deprecated) and/or `DT_RUNPATH` influence where the dynamic loader searches for dependencies.<sup>[[3]](#references)</sup> Rough order:

- `LD_LIBRARY_PATH` (ignored for setuid/sgid or otherwise "secure-execution" programs)
- `DT_RPATH` (only if `DT_RUNPATH` absent)
Expand Down Expand Up @@ -361,7 +361,7 @@ Relocation section '.rela.plt' at offset 0xcc8 contains 40 entries:

#### Packed relative relocations (RELR)

- Modern linkers can emit compact **relative** relocations with `-z pack-relative-relocs`. This adds `DT_RELR`, `DT_RELRSZ`, and `DT_RELRENT` entries to the dynamic section for PIEs/shared libraries (it is ignored for non-PIE executables).
- Modern linkers can emit compact **relative** relocations with `-z pack-relative-relocs`. This adds `DT_RELR`, `DT_RELRSZ`, and `DT_RELRENT` entries to the dynamic section for PIEs/shared libraries (it is ignored for non-PIE executables).<sup>[[2]](#references)</sup>
- Recon: `readelf -d ./bin | egrep -i "DT_RELR|RELRSZ|RELRENT"`

### Static Relocations
Expand Down Expand Up @@ -478,7 +478,7 @@ The Linux kernel passes an auxiliary vector to processes containing useful addre

- `AT_RANDOM`: points to 16 random bytes used by glibc for the stack canary and other PRNG seeds.
- `AT_SYSINFO_EHDR`: base address of the vDSO mapping (handy to find `__kernel_*` syscalls and gadgets).
- `AT_EXECFN`, `AT_BASE`, `AT_PAGESZ`, etc.
- `AT_EXECFN`, `AT_BASE`, `AT_PAGESZ`, etc.<sup>[[4]](#references)</sup>

As an attacker, if you can read memory or files under `/proc`, you can often leak these without an infoleak in the target process:

Expand All @@ -501,8 +501,9 @@ Leaking `AT_RANDOM` gives you the canary value if you can dereference that point

## References

- GCC Common Function Attributes (ifunc / STT_GNU_IFUNC): https://gcc.gnu.org/onlinedocs/gcc-14.3.0/gcc/Common-Function-Attributes.html
- GNU ld `-z pack-relative-relocs` / `DT_RELR` docs: https://sourceware.org/binutils/docs/ld.html
- ld.so(8) – Dynamic Loader search order, RPATH/RUNPATH, secure-execution rules (AT_SECURE): https://man7.org/linux/man-pages/man8/ld.so.8.html
- getauxval(3) – Auxiliary vector and AT_* constants: https://man7.org/linux/man-pages/man3/getauxval.3.html
- [1] [GCC Common Function Attributes (ifunc / STT_GNU_IFUNC)](https://gcc.gnu.org/onlinedocs/gcc-14.3.0/gcc/Common-Function-Attributes.html)
- [2] [GNU ld `-z pack-relative-relocs` / `DT_RELR` docs](https://sourceware.org/binutils/docs/ld.html)
- [3] [ld.so(8) – Dynamic Loader search order, RPATH/RUNPATH, secure-execution rules (AT_SECURE)](https://man7.org/linux/man-pages/man8/ld.so.8.html)
- [4] [getauxval(3) – Auxiliary vector and AT_* constants](https://man7.org/linux/man-pages/man3/getauxval.3.html)

{{#include ../../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ pwn update

## ELF → raw shellcode packaging (loader_append)

Pwntools can turn a standalone ELF into a single raw shellcode blob that self‑maps its segments and transfers execution to the original entrypoint. This is ideal for memory‑only loaders (e.g., Android apps invoking JNI to execute downloaded bytes).
Pwntools can turn a standalone ELF into a single raw shellcode blob that self‑maps its segments and transfers execution to the original entrypoint. This is ideal for memory‑only loaders (e.g., Android apps invoking JNI to execute downloaded bytes).<sup>[[2]](#references)</sup>

Typical pipeline (amd64 example)

Expand Down Expand Up @@ -207,7 +207,7 @@ Notes

## References

- [Pwntools](https://docs.pwntools.com/en/stable/)
- [CoRPhone – ELF→shellcode pipeline used for Android in-memory execution](https://github.com/0xdevil/corphone)
- [1] [Pwntools](https://docs.pwntools.com/en/stable/)
- [2] [CoRPhone – ELF→shellcode pipeline used for Android in-memory execution](https://github.com/0xdevil/corphone)

{{#include ../../../banners/hacktricks-training.md}}
10 changes: 5 additions & 5 deletions src/binary-exploitation/libc-heap/heap-memory-functions/free.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
2. If possible, add the chunk to the fast bin
3. Call `_int_free_merge_chunk` to consolidate the chunk is needed and add it to the unsorted list

> Note: Starting with glibc 2.42, the tcache step can also take chunks up to a much larger size threshold if `glibc.malloc.tcache_max` was raised (up to 4 MiB). This changes when a free lands in tcache vs. unsorted/small/large bins.
> Note: Starting with glibc 2.42, the tcache step can also take chunks up to a much larger size threshold if `glibc.malloc.tcache_max` was raised (up to 4 MiB). This changes when a free lands in tcache vs. unsorted/small/large bins.<sup>[[1]](#references)</sup>

## __libc_free <a href="#libc_free" id="libc_free"></a>

Expand Down Expand Up @@ -391,8 +391,8 @@ _int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)

- Safe-Linking in tcache/fastbins: `free()` stores the `fd` pointer of singly-linked lists using the macro `PROTECT_PTR(pos, ptr) = ((size_t)pos >> 12) ^ (size_t)ptr`. This means crafting a fake next pointer for tcache poisoning requires the attacker to know a heap address (e.g., leak `chunk_addr`, then use `chunk_addr >> 12` as the XOR key). See more details and PoCs in the tcache page below.
- Tcache double-free detection: Before pushing a chunk into tcache, `free()` checks the per-entry `e->key` against the per-thread `tcache_key` and walks the bin up to `mp_.tcache_count` looking for duplicates, aborting with `free(): double free detected in tcache 2` when found.
- Recent glibc change (2.42): `free()` can now keep **much larger arena chunks** inside tcache when `glibc.malloc.tcache_max` is raised above the historical ceiling (up to **4 MiB**). Therefore, assumptions such as “large free => unsorted bin” are no longer reliable on modern tuned targets. **Mmapped chunks are still not cached in tcache.**
- Heap-grooming gotcha (glibc 2.42+): if your first heap activity uses **large chunks that never touch tcache**, the `tcache_perthread_struct` may be initialized **later** than in older labs. This can place tcache metadata **after attacker-controlled large chunks**, which is useful when an overflow/UAF can later target that metadata.
- Recent glibc change (2.42): `free()` can now keep **much larger arena chunks** inside tcache when `glibc.malloc.tcache_max` is raised above the historical ceiling (up to **4 MiB**). Therefore, assumptions such as “large free => unsorted bin” are no longer reliable on modern tuned targets. **Mmapped chunks are still not cached in tcache.**<sup>[[1]](#references)</sup>
- Heap-grooming gotcha (glibc 2.42+): if your first heap activity uses **large chunks that never touch tcache**, the `tcache_perthread_struct` may be initialized **later** than in older labs. This can place tcache metadata **after attacker-controlled large chunks**, which is useful when an overflow/UAF can later target that metadata.<sup>[[2]](#references)</sup>

### Quick crafting of a safe-linked fd (for tcache poisoning)

Expand Down Expand Up @@ -448,7 +448,7 @@ Related reading within HackTricks:

## References

- GNU C Library 2.42 release notes (large-block tcache support via `glibc.malloc.tcache_max`) <https://lists.gnu.org/archive/html/info-gnu/2025-07/msg00011.html>
- how2heap `glibc_2.42/tcache_metadata_hijacking.c` (practical example of delayed tcache metadata placement on modern glibc) <https://github.com/shellphish/how2heap/blob/master/glibc_2.42/tcache_metadata_hijacking.c>
- [1] [GNU C Library 2.42 release notes (large-block tcache support via glibc.malloc.tcache_max)](https://lists.gnu.org/archive/html/info-gnu/2025-07/msg00011.html)
- [2] [how2heap glibc_2.42/tcache_metadata_hijacking.c (practical example of delayed tcache metadata placement on modern glibc)](https://github.com/shellphish/how2heap/blob/master/glibc_2.42/tcache_metadata_hijacking.c)

{{#include ../../../banners/hacktricks-training.md}}
21 changes: 9 additions & 12 deletions src/binary-exploitation/rop-return-oriented-programing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ First, let's assume we've identified the necessary gadgets within the binary or

### **ROP Chain**

Using **pwntools**, we prepare the stack for the ROP chain execution as follows aiming to execute `system('/bin/sh')`, note how the chain starts with:
Using **pwntools**, we prepare the stack for the ROP chain execution as follows aiming to execute `system('/bin/sh')`, note how the chain starts with:<sup>[[1]](#references)</sup>

1. A `ret` instruction for alignment purposes (optional)
2. Address of `system` function (supposing ASLR disabled and known libc, more info in [**Ret2lib**](ret2lib/index.html))
Expand Down Expand Up @@ -289,7 +289,7 @@ G3:

## Shellcode via /proc/self/mem (Embedded Linux)

If you already have a ROP chain but **no RWX mappings**, an alternative is to **write shellcode into the current process using** `/proc/self/mem` and then jump to it. This is common on embedded Linux targets where `/proc/self/mem` can ignore write protections on executable segments in default configurations.
If you already have a ROP chain but **no RWX mappings**, an alternative is to **write shellcode into the current process using** `/proc/self/mem` and then jump to it. This is common on embedded Linux targets where `/proc/self/mem` can ignore write protections on executable segments in default configurations.<sup>[[5]](#references)[[6]](#references)</sup>

Typical chain idea:

Expand Down Expand Up @@ -334,19 +334,16 @@ rop-syscall-execv/
../stack-overflow/stack-pivoting.md
{{#endref}}

## Other Examples & References
## References

- [https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions)
- [https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html)
- [1] [Exploiting calling conventions (ir0nstone notes)](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions)
- [2] [Nightmare: hacklu15 stackstuff](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html)
- 64 bit, Pie and nx enabled, no canary, overwrite RIP with a `vsyscall` address with the sole purpose or return to the next address in the stack which will be a partial overwrite of the address to get the part of the function that leaks the flag
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- [3] [Using mprotect to bypass NX protection (ARM64 Part 4, 8ksec)](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- arm64, no ASLR, ROP gadget to make stack executable and jump to shellcode in stack
- [https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-4.html](https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-4.html)

## References

- [Now You See mi: Now You're Pwned](https://labs.taszk.io/articles/post/nowyouseemi/)
- [TaszkSecLabs/xiaomi-c400-pwn](https://github.com/TaszkSecLabs/xiaomi-c400-pwn)
- [4] [In-the-wild iOS exploit chain 4 (Google Project Zero)](https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-4.html)
- [5] [Now You See mi: Now You're Pwned](https://labs.taszk.io/articles/post/nowyouseemi/)
- [6] [TaszkSecLabs/xiaomi-c400-pwn](https://github.com/TaszkSecLabs/xiaomi-c400-pwn)

{{#include ../../banners/hacktricks-training.md}}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## 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**.\
The goal of this attack is to be able to **abuse a ROP via a buffer overflow without any information about the vulnerable binary**.<sup>[[1]](#references)[[2]](#references)</sup>\
This attack is based on the following scenario:

- A stack vulnerability and knowledge of how to trigger it.
Expand Down Expand Up @@ -35,7 +35,7 @@ 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.
Notice how with those gadgets it's possible to **control 2 arguments** of a function to call.<sup>[[1]](#references)</sup>

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:

Expand Down Expand Up @@ -104,7 +104,7 @@ However, the original paper only mentions the **`write`** one, so lets talk abou

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.
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.<sup>[[1]](#references)</sup>

Behaviour signatures to find those functions:

Expand All @@ -118,8 +118,8 @@ Behaviour signatures to find those functions:

## 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)
- [1] [Hacking Blind (original BROP paper)](https://www.scs.stanford.edu/brop/bittau-brop.pdf)
- [2] [Blind Return Oriented Programming - BROP (CTF Recipes)](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop)

{{#include ../../banners/hacktricks-training.md}}

Expand Down
15 changes: 11 additions & 4 deletions src/binary-exploitation/rop-return-oriented-programing/ret2csu.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ ret
The conditions will be:

- `[r12 + rbx*8]` must be pointing to an address storing a callable function (if no idea and no pie, you can just use `_init` func):
- If \_init is at `0x400560`, use GEF to search for a pointer in memory to it and make `[r12 + rbx*8]` be the address with the pointer to \_init:
- If \_init is at `0x400560`, use GEF to search for a pointer in memory to it and make `[r12 + rbx*8]` be the address with the pointer to \_init:<sup>[[4]](#references)</sup>

```bash
# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
Expand All @@ -73,7 +73,7 @@ gef➤ search-pattern 0x400560

## RDI and RSI

Another way to control **`rdi`** and **`rsi`** from the ret2csu gadget is by accessing it specific offsets:
Another way to control **`rdi`** and **`rsi`** from the ret2csu gadget is by accessing it specific offsets:<sup>[[1]](#references)</sup>

<figure><img src="../../images/image (2) (1) (1) (1) (1) (1) (1) (1).png" alt="" width="283"><figcaption><p><a href="https://www.scs.stanford.edu/brop/bittau-brop.pdf">https://www.scs.stanford.edu/brop/bittau-brop.pdf</a></p></figcaption></figure>

Expand All @@ -95,7 +95,7 @@ Here's where **ret2csu** comes into play:
1. **Set Up the Registers**: Use the first magic gadget to pop values off the stack and into rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx), and r15.
2. **Use the Second Gadget**: With those registers set, you use the second gadget. This lets you move your chosen values into `rdx` and `rsi` (from r14 and r13, respectively), readying parameters for a function call. Moreover, by controlling `r15` and `rbx`, you can make the program call a function located at the address you calculate and place into `[r15 + rbx*8]`.

You have an [**example using this technique and explaining it here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation), and this is the final exploit it used:
You have an [**example using this technique and explaining it here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation), and this is the final exploit it used:<sup>[[2]](#references)</sup>

```python
from pwn import *
Expand Down Expand Up @@ -126,7 +126,7 @@ print(p.recvline()) # should receive "Awesome work!"

### Bypassing the call and reaching ret

The following exploit was extracted [**from this page**](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html) where the **ret2csu** is used but instead of using the call, it's **bypassing the comparisons and reaching the `ret`** after the call:
The following exploit was extracted [**from this page**](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html) where the **ret2csu** is used but instead of using the call, it's **bypassing the comparisons and reaching the `ret`** after the call:<sup>[[3]](#references)[[4]](#references)</sup>

```python
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
Expand Down Expand Up @@ -182,6 +182,13 @@ target.interactive()

Usually these cases are also vulnerable to [**ret2plt**](../common-binary-protections-and-bypasses/aslr/ret2plt.md) + [**ret2lib**](ret2lib/index.html), but sometimes you need to control more parameters than are easily controlled with the gadgets you find directly in libc. For example, the `write()` function requires three parameters, and **finding gadgets to set all these directly might not be possible**.

## References

- [1] [Hacking Blind (original BROP paper)](https://www.scs.stanford.edu/brop/bittau-brop.pdf)
- [2] [ret2csu exploitation - ir0nstone notes](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation)
- [3] [ROP Emporium - ret2csu (RootNetSec)](https://www.rootnetsec.com/ropemporium-ret2csu/)
- [4] [ropemporium_ret2csu - Nightmare (guyinatuxedo)](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html)

{{#include ../../banners/hacktricks-training.md}}


Loading