Or not, back to HOME!




ADMIRER

SUMMARY

A python script, which imports module without explicitly setting the search path, can be called by a command. Such command has tag SETENV enabled and can be run as superuser, if by user waldo.

Waldo uses the same credential for logging into the box and configuring website.

Despite the MySQL server on the box only listens to local clients, one local client called Adminer uses a web page as interface, and such web page is for some reason available to everyone.





REFERENCE

Rogue MySQL Server





WALKTHROUGH

Skip to obtaining foothold!
Skip to obtaining root!


Surface check.
nmap -sV -sC admirer.htb -oA tcp_t1k -v; searchsploit --nmap tcp_t1k.xml -v

Edit searchsploit to make option nmap somewhat usable. Hope for minor typo fix but end up everywhere. Manual search from now on.

Check out how xml is parsed in function nmapxml().

xmllint --xpath '//address/@addr|//service/@name|//service/@product|//service/@version' "${FILE}" \
    | sed -e $'s/addr=/\\\n[IP] /g;   s/name=/\\\n[NAME] /g;   s/product=/\\\n[PRODUCT] /g;s/" version="/\\\n[VERSION] /g;   s/"//g' \

addr, name, product, version are all xml attributes that need to be picked up by sed expression string, yet only s/" version="/\\\n[VERSION] /g; has this weird quoted space situation going on. Space removed.

[i] searchsploit openssh 7 4p1 debian 10 deb9u7

It’s not openssh 7.4p1 debian 10+deb9u7?
Check out function searchsploitout(), which is where those formatted version strings go.

## Try and remove terms that could confuse searches
software=$( echo "${software}" | sed -e 's/[^a-zA-Z0-9]/ /g' )

Non-alphanumeric characters are swapped with spaces, to not “confuse searches”. Manual search term openssh 7.4p1, the search does not seems to be confused tho.

------------------------------------------------------------------------------------------------------- -------------------------
 Exploit Title                                                                                         |  Path
------------------------------------------------------------------------------------------------------- -------------------------
OpenSSH 2.3 < 7.7 - Username Enumeration                                                               | linux/remote/45233.py
OpenSSH 2.3 < 7.7 - Username Enumeration (PoC)                                                         | linux/remote/45210.py
OpenSSH < 7.4 - 'UsePrivilegeSeparation Disabled' Forwarded Unix Domain Sockets Privilege Escalation   | linux/local/40962.txt
OpenSSH < 7.4 - agent Protocol Arbitrary Library Loading                                               | linux/remote/40963.txt
OpenSSH < 7.7 - User Enumeration (2)                                                                   | linux/remote/45939.py
------------------------------------------------------------------------------------------------------- -------------------------

Line commented out.

[-] Skipping output: openssh 7.4p1   (Too many results, 100+. You'll need to force a search: searchsploit openssh 7.4p1

8, as in the block before, has turned into “Too many results, 100+”.
Locate such string, and read code above.

arg="-t"   ## Title search by default!

Manual search term openssh 7.4p1 but this time with -t.

searchsploit -t 'openssh 7.4p1' | wc -l
226

Maybe it is the non-alphanumeric character dot that “confuse searches”.

searchsploit -t 'openssh 7 4p1' | wc -l
472

Void, void that arg!
Then the auto-search finally behaves like a manual one: openssh 7.4p1 is tried, then openssh 7.4p1 debian and openssh 7.4p1 debian 10+deb9u7 and.

[-] Skipping term: apachehttpd2.4.25

Per nmap, ftp is open on port 21, ssh is open on port 22, and http is open on port 80 with robots.txt of one disallowed entry /admin-dir.


ftp admirer.htb
Connected to admirer.htb.
220 (vsFTPd 3.0.3)
Name (admirer.htb:scum):^C

Local username is somehow prompted. Maybe if an ftp cred is obtained later on, use it on ssh or su. Anyways, need cred so leave it for now.


The blog has pictures and a feedback box with html comment “Still under development… This does not send anything yet, but it looks nice!”.

Screenshot of the blog.

[Seriously, listen to album The Third Chimpanzee. Thank the creators later.]
[Dead buttons.]

gobuster under the forbidden /admin-dir: contacts.txt and credentials.txt.
[There actually is a comment in robots.txt: “This folder contains personal contacts and creds, so no one -not even robots- should see it - waldo”; with such info one could grep contact and cred in wordlists and significantly reduce bruteforce attempts.]

Content of two files.
##########
# 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

[Internal mail account]
w.cooper@admirer.htb
fgJr6q#S\W:$P

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

[Wordpress account]
admin
w0rdpr3ss01!

Full names except w.cooper, job titles, three creds, and that there could be a WordPress and an “internal” mail service. [No idea how “internal” this mailing stuff is but, something that is supposed to be internal is totally out there, as we’ll see later.]




Fail to ssh in as ftpuser.

Message returned.
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.
Connection to admirer.htb closed.

Cred should be right, as otherwise the message will be “Permission denied, please try again.”, but the connection is closed right after above message being sent.
Send command via ssh does not stop the connection from closing, does not even stall it a bit.
Check out manual of this vsFTPd 3.0.3. This ftpuser seems to be a “virtual user”: “does not exist in /etc/shadow file” i.e. it’s only for this ftp system. Still no idea why the above message is sent but. [After rooting the box, it is found out that ftpuser actually is a “real user”, that is, does exist in /etc/shadow file, but with shell set to /bin/false.]

ftp admirer.htb
Connected to admirer.htb.
220 (vsFTPd 3.0.3)
Name (admirer.htb:scum): ftpuser
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
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.

The file share seems to be the source of the website. [Information overload all of a sudden.]
[It’s intended that after some digging, the comment in utility-scripts/db_admin.php, which is “TODO: Finish implementing this or find a better open source alternative”, would remind you field people of a popular application Adminer, so you’d try adminer.php under this utility-scripts/ and voila. Me without experiences just cry for help a lot then voila. Anyways.]


Screenshot of the interface offered by Adminer.

Checking out the database of the blog, using cred in index.php file from the ftp share, to be honest, is not even attractive here, as the blog only contains pictures and texts, shown in dump.sql from the ftp share. [Can it be that after the database is dumped, it’s used for other purposes, which will lead us into the box? Ehh.]
searchsploit adminer 4.6.2: no results.
[Hit wall, and don’t want to go mix-up-creds-and-try-each-combo-every-frigging-where route. Sure sense googling with version number would provide a quick way out but. Decide to first reason a bit about it myself. As I really don’t know shits, and database applications they only aim for storing stuff (and give them back, always give them back), which should be the simplest application to understand.]


Start of skiddie wild guess. [You have been warned, and corrections welcome.]
Database applications store and give back stuff, that is, write and then read file in the file system, basically a fancy vi and a fancy cat. They also provide a way to search through, that is, give back only part of the stuff that has been stored, basically add a fancy awk and a fancy grep. Maybe that’s the selling point of a database over a lame flat file: whatever required will be found out and returned, based on how customers would like to ask for stuff a query language is invented, and then this process of selecting what’s asked is optimized towards speed, maybe stuff that’s asked for together a lot simply get fancy vied together, maybe fancy grep would go hoppity hop across lines following some rule instead of going through them one after another.
A database is just a fancy file. Well maybe a fancy file is achieved by one lame file, or many lame files, or maybe fancy files and lame files match in some weird ass way that is good for speed. Still, databases are just fancy files, and a database application simply do fancy vi cat awk grep on lame files to give you this delusion of fancy files out of nowhere.
Sanity check. Does the above wild guess match the user experience that I have had?
I start with typing in terminal, say, mysql -u and yeee forgot to guess about authentications.


Username and password make sense here, afterall files, even the fancy ones, need access control unless this world does not have secrets, well it very much has secrets so. To achieve the decision of who can access a fancy file, well a concept of who need to exist in the first place like duhh, and a username and a password is in this case what makes a who. Just like a lame file system, file permission stuff.
So basically a database application is a fancy file system where you can log in and read write some fancy files! If I recall correctly, it even has its own cute root: king of this limited land and nothing across the border, which is kinda lame, afterall brilliant root, the one of the underlying blunt flat lame yet full-scale file system, can access everything, and the almighty database application from the cute root’s point of view, is merely a normal user called mysql in the underlying world.


At this point it becomes clear that, not having fancy cred only stops us from interacting with fancy file system and as I said earlier, they are ultimately just pictures and texts from the blog and we don’t care about them anyways; not having fancy cred does not stop us from interacting with the underlying non-fancy file system, it is up to some other rules to stop us and they might just not.


The returned stuff from the underlying file system, if any, has to be sent somewhere. It can’t stay at any databases on target, as cred with write access there is needed but we don’t have any, not to mention we have to read the same database later to get the info. Might as well set up our own database server, create a database x, and a cred saying “allowed to write database x here”, and give this cred to database client Adminer so it can pass it to the database server on target. Once the server on target come with cred and successfully identified itself to the server on our box as someone who is “allowed to write database x here”, we can then issue LOAD DATA LOCAL command to it, via Adminer of course as we simply lack of other interfaces, and that’s it, data will be sent to database x, waiting to be read.
To catch the returned stuff, our database server has to listen on traffic beyond those from localhost, which per my understanding, subject ourselves to the same attack that we’re attempting on target. Pretty ironic. To avoid so, use a pseudo server.

Content of index.php returned.
Enter filename to get [/var/www/html/index.php] > 
[.] Waiting for connection on 0.0.0.0:3306
[+] Connection from 10.10.10.187:36528 - greet... auth ok... some shit ok... want file... 
[+] /var/www/html/index.php from 10.10.10.187:36528:
[...]
$servername = "localhost";
$username = "waldo";
$password = "&<h5b~yK3F#{PaPB&dA}{H>";
$dbname = "admirerdb";
[...]



Then it’s pretty smooth: cred reuse, hats time (it is sudo -l that worked).

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

I used to assume all environment variables are automatically swapped by sudo, say /home/bro to /home/another_bro, now that I see SETENV appears at the place where NOPASSWD used to be, it seems that me the person who type the password, can also type in command line some syntax to set environment variables.


Content of /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

User input limited to an option number, then it’s up to the script to call some binaries. Full path specified, can’t write to those path, can’t write to those binaries either. /opt/scripts/backup.py, which is behind option 6, stands out as not being part of a standard install.

Content of /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)

from shutil import make_archive, so go to directory of choice, create shutil.py in which function make_archive is defined as taking three arguments but only doing payload of choice, then sudo -E PYTHONPATH=<dir_of_choice> /opt/scripts/admin_tasks.sh 6.


That’s it for the box.