Skip to content

Commit 5a0e712

Browse files
committed
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks
2 parents 29d65a6 + 89ce398 commit 5a0e712

5 files changed

Lines changed: 134 additions & 41 deletions

File tree

src/binary-exploitation/basic-stack-binary-exploitation-methodology/elf-tricks.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ Each symbol entry contains:
218218
- **Value** (address sin memory)
219219
- **Size**
220220

221+
#### GNU IFUNC (indirect functions)
222+
223+
- GCC can emit `STT_GNU_IFUNC` symbols with the `__attribute__((ifunc("resolver")))` extension. The dynamic loader calls the resolver at load time to select the concrete implementation (commonly CPU dispatch).
224+
- Quick triage: `readelf -sW ./bin | rg -i "IFUNC"`
225+
221226
#### GNU Symbol Versioning (dynsym/dynstr/gnu.version)
222227

223228
Modern glibc uses symbol versions. You will see entries in `.gnu.version` and `.gnu.version_r` and symbol names like `strlen@GLIBC_2.17`. The dynamic linker can require a specific version when resolving a symbol. When crafting manual relocations (e.g. ret2dlresolve) you must supply the correct version index, otherwise resolution fails.
@@ -354,6 +359,11 @@ Relocation section '.rela.plt' at offset 0xcc8 contains 40 entries:
354359
00000001ffa8 003000000402 R_AARCH64_JUMP_SL 0000000000000000 fgets@GLIBC_2.17 + 0
355360
```
356361

362+
#### Packed relative relocations (RELR)
363+
364+
- Modern linkers can emit compact **relative** relocations with `-z pack-relative-relocs`. This adds `DT_RELR`, `DT_RELRSZ`, and `DT_RELRENT` entries to the dynamic section for PIEs/shared libraries (it is ignored for non-PIE executables).
365+
- Recon: `readelf -d ./bin | egrep -i "DT_RELR|RELRSZ|RELRENT"`
366+
357367
### Static Relocations
358368

359369
If the **program is loaded in a place different** from the preferred address (usually 0x400000) because the address is already used or because of **ASLR** or any other reason, a static relocation **corrects pointers** that had values expecting the binary to be loaded in the preferred address.
@@ -420,11 +430,11 @@ Note that these global variables are located in `.data` or `.bss` but in the lis
420430
From C code it's possible to obtain the same result using the GNU extensions :
421431
422432
```c
423-
__attributte__((constructor)) //Add a constructor to execute before
424-
__attributte__((destructor)) //Add to the destructor list
433+
__attribute__((constructor)) //Add a constructor to execute before
434+
__attribute__((destructor)) //Add to the destructor list
425435
```
426436

427-
From a compiler perspective, to execute these actions before and after the `main` function is executed, it's possible to create a `init` function and a `fini` function which would be referenced in the dynamic section as **`INIT`** and **`FIN`**. and are placed in the `init` and `fini` sections of the ELF.
437+
From a compiler perspective, to execute these actions before and after the `main` function is executed, it's possible to create a `init` function and a `fini` function which would be referenced in the dynamic section as **`INIT`** and **`FINI`**. and are placed in the `init` and `fini` sections of the ELF.
428438

429439
The other option, as mentioned, is to reference the lists **`__CTOR_LIST__`** and **`__DTOR_LIST__`** in the **`INIT_ARRAY`** and **`FINI_ARRAY`** entries in the dynamic section and the length of these are indicated by **`INIT_ARRAYSZ`** and **`FINI_ARRAYSZ`**. Each entry is a function pointer that will be called without arguments.
430440

@@ -491,6 +501,8 @@ Leaking `AT_RANDOM` gives you the canary value if you can dereference that point
491501

492502
## References
493503

504+
- GCC Common Function Attributes (ifunc / STT_GNU_IFUNC): https://gcc.gnu.org/onlinedocs/gcc-14.3.0/gcc/Common-Function-Attributes.html
505+
- GNU ld `-z pack-relative-relocs` / `DT_RELR` docs: https://sourceware.org/binutils/docs/ld.html
494506
- ld.so(8) – Dynamic Loader search order, RPATH/RUNPATH, secure-execution rules (AT_SECURE): https://man7.org/linux/man-pages/man8/ld.so.8.html
495507
- getauxval(3) – Auxiliary vector and AT_* constants: https://man7.org/linux/man-pages/man3/getauxval.3.html
496508
{{#include ../../banners/hacktricks-training.md}}

src/binary-exploitation/libc-heap/house-of-roman.md

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
## Basic Information
66

7-
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 ben [**patched**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
7+
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).
8+
9+
### Applicability in 2026
10+
11+
- **glibc window:** Works reliably on **2.23–2.28**. On **2.29** the additional `unsorted_chunks` integrity checks make the unsorted‑bin write unreliable, so success drops sharply. From **2.34** onward `__malloc_hook/__free_hook` were removed, making the original target unavailable. Use it only on old libc’s (or custom builds that keep the hooks) or for CTF challenges that ship an old libc.
12+
- **Tcache era (≥2.26):** Tcache will eat your 0x70 allocations and stop the fastbin/unsorted primitives. Disable it (`setenv("GLIBC_TUNABLES","glibc.malloc.tcache_count=0",1);`) **before** any allocation or fill each 0x70 tcache bin with 7 frees to drain it.
13+
- **Safe-linking:** It applies to tcache/fastbin in ≥2.32, but House of Roman only needs **partial pointer overwrite of a libc address already present in fd/bk**, so safe-linking does not help the defender here (the attacker never forges a fresh pointer). The real stopper is the hook removal and the unsorted-bin checks.
814

915
### Code
1016

@@ -46,24 +52,24 @@ Current heap layout:
4652
0x190: relative_offset_heap - size 0x70
4753
4854
bin layout:
49-
fastbin: fastbin_victim -> relative_offset_heap
50-
unsorted: leftover_main
55+
fastbin: fastbin_victim -> relative_offset_heap
56+
unsorted: leftover_main
5157
*/
5258
```
5359

5460
- `fastbin_victim` has a `fd` pointing to `relative_offset_heap`
5561
- `relative_offset_heap` is an offset of distance from `fake_libc_chunk`, which contains a pointer to `main_arena + 0x68`
56-
- Just changing the last byte of `fastbin_victim.fd` it's possible to make `fastbin_victim points` to `main_arena + 0x68`
62+
- Changing the last byte of `fastbin_victim.fd` makes `fastbin_victim` point to `main_arena + 0x68`.
5763

5864
For the previous actions, the attacker needs to be capable of modifying the fd pointer of `fastbin_victim`.
5965

60-
Then, `main_arena + 0x68` is not that interesting, so lets modify it so the pointer points to **`__malloc_hook`**.
66+
Then, `main_arena + 0x68` is not that interesting, so let's modify it so the pointer points to **`__malloc_hook`**.
6167

62-
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 are interested. So a BF attack is performed here so the chunk ends like: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`.**
68+
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)`.**
6369

64-
(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 BF don't work the program just crashes (so start gain until it works).
70+
(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).
6571

66-
Then, 2 mallocs are performed to remove the 2 initial fast bin chunks and the a third one is alloced to get a chunk in the **`__malloc_hook:`**
72+
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`**.
6773

6874
```c
6975
malloc(0x60);
@@ -75,12 +81,11 @@ uint8_t* malloc_hook_chunk = malloc(0x60);
7581
7682
For more info you can check:
7783
78-
7984
{{#ref}}
8085
unsorted-bin-attack.md
8186
{{#endref}}
8287
83-
But basically it allows to write `main_arena + 0x68` to any location by specified in `chunk->bk`. And for the attack we choose `__malloc_hook`. Then, after overwriting it we will use a relative overwrite) to point to a `one_gadget`.
88+
But basically it allows to write `main_arena + 0x68` to any location specified in `chunk->bk`. For the attack we choose `__malloc_hook`. Then, after overwriting it we will use a relative overwrite to point to a `one_gadget`.
8489
8590
For this we start getting a chunk and putting it into the **unsorted bin**:
8691
@@ -102,20 +107,26 @@ So, to trigger the write of `main_arena + 0x68` in `__malloc_hook` we perform af
102107

103108
### Step 3: Set \_\_malloc_hook to system
104109

105-
In the step one we ended controlling a chunk containing `__malloc_hook` (in the variable `malloc_hook_chunk`) and in the second step we managed to write `main_arena + 0x68` in here.
110+
In step one we controlled a chunk containing `__malloc_hook` (in the variable `malloc_hook_chunk`) and in the second step we managed to write `main_arena + 0x68` there.
106111

107-
Now, we abuse a partial overwrite in `malloc_hook_chunk` to use the libc address we wrote there(`main_arena + 0x68`) to **point a `one_gadget` address**.
112+
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**.
108113

109114
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)).
110115

111-
Finally, one the correct address is overwritten, **call `malloc` and trigger the `one_gadget`**.
116+
Finally, once the correct address is overwritten, **call `malloc` and trigger the `one_gadget`**.
117+
118+
## Modern tips & variants
119+
120+
- **Unsorted-bin check in 2.29+:** If you must run on 2.29–2.33, corrupt both `fd` **and** `bk` to satisfy the integrity check before triggering the write; otherwise `_int_malloc` aborts. Success rate is very low and usually only viable in brute-force CTF settings.
121+
- **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.
122+
- **Any‑address fastbin alloc (2024 gist):** A recent writeup shows reusing the same grooming to fastbin‑allocate over `__free_hook` or other globals by first landing a libc pointer in fastbin and then re‑pointing it before the fixup. This works on 2.24–2.28 but still dies on 2.29 integrity checks.
112123

113124
## References
114125

115126
- [https://github.com/shellphish/how2heap](https://github.com/shellphish/how2heap)
116127
- [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)
117128
- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_roman/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_roman/)
129+
- [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)
130+
- [https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc](https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc)
118131

119132
{{#include ../../banners/hacktricks-training.md}}
120-
121-

src/pentesting-web/deserialization/livewire-hydration-synthesizer-abuse.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,16 @@ Leveraging Livewire's instantiation primitives, Synacktiv adapted phpggc's `Lara
7171
`synacktiv/laravel-crypto-killer` now ships a `livewire` mode that stitches everything:
7272

7373
```bash
74-
./laravel_crypto_killer.py -e livewire -k base64:APP_KEY \
74+
./laravel_crypto_killer.py exploit -e livewire -k base64:APP_KEY \
7575
-j request.json --function system -p "bash -c 'id'"
7676
```
7777

7878
The tool parses the captured snapshot, injects the gadget tuples, recomputes the checksum, and prints a ready-to-send `/livewire/update` payload.
7979

8080
## CVE-2025-54068 – RCE without `APP_KEY`
8181

82+
According to the vendor advisory, the issue affects Livewire v3 (>= 3.0.0-beta.1 and < 3.6.3) and is unique to v3.
83+
8284
`updates` are merged into component state **after** the snapshot checksum is validated. If a property inside the snapshot is (or becomes) a synthetic tuple, Livewire reuses its meta while hydrating the attacker-controlled update value:
8385

8486
```php
@@ -95,6 +97,21 @@ Exploit recipe:
9597

9698
1. Find a Livewire component with an untyped public property (e.g., `public $count;`).
9799
2. Send an update that sets that property to `[]`. The next snapshot now stores it as `[[], {"s": "arr"}]`.
100+
101+
A minimal type-juggling flow looks like this:
102+
103+
```http
104+
POST /livewire/update
105+
...
106+
"updates": {"count": []}
107+
```
108+
109+
Then the next snapshot stores a tuple that keeps the `arr` synthesizer metadata:
110+
111+
```json
112+
"count": [[], {"s": "arr"}]
113+
```
114+
98115
3. Craft another `updates` payload where that property contains a deeply nested array embedding tuples such as `[ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ]`.
99116
4. During recursion, `hydrate()` evaluates each nested child independently, so attacker-chosen synth keys/classes are honoured even though the outer tuple and checksum never changed.
100117
5. Reuse the same `CollectionSynth`/`FormObjectSynth` primitives to instantiate a Queueable gadget whose `$chained[0]` contains the phpggc payload. Livewire processes the forged updates, invokes `dispatchNextJobInChain()`, and reaches `system(<cmd>)` without knowing `APP_KEY`.
@@ -112,6 +129,7 @@ Key reasons this works:
112129
- Fingerprints the deployed Livewire version by parsing `<script src="/livewire/livewire.js?id=HASH">` and mapping the hash to vulnerable releases.
113130
- Collects baseline snapshots by replaying benign actions and extracting `components[].snapshot`.
114131
- Generates either an `updates`-only payload (CVE-2025-54068) or a forged snapshot (known APP_KEY) embedding the phpggc chain.
132+
- If no object-typed parameter is found in a snapshot, Livepyre falls back to brute-forcing candidate params to reach a coercible property.
115133

116134
Typical usage:
117135

@@ -139,5 +157,6 @@ python3 Livepyre.py -u https://target/livewire/component -a base64:APP_KEY \
139157
- [Synacktiv – Livewire: Remote Command Execution via Unmarshaling](https://www.synacktiv.com/publications/livewire-execution-de-commandes-a-distance-via-unmarshaling.html)
140158
- [synacktiv/laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer)
141159
- [synacktiv/Livepyre](https://github.com/synacktiv/Livepyre)
160+
- [GHSA-29cq-5w36-x7w3 – Livewire v3 RCE advisory](https://github.com/livewire/livewire/security/advisories/GHSA-29cq-5w36-x7w3)
142161

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

0 commit comments

Comments
 (0)