Identify Known Unknowns: Import DHCP assets to Tenable.io

Casey Reid a.k.a Packet Chaos
6 min readApr 3, 2022

--

Importing assets into Tenable.io is extremely simple, with the help of pytenable it is a single line of code(excluding import statements and T.io authentication). The focus of this article is to explain why this capability is so useful and to use a real-life example.

tio.assets.asset_import(“<Source String>”, <Host Dictionary>)

I have an extensive home lab and my pfSense firewall handles a number of functions, one being DHCP assets from my wireless network. Similar to some corporate networks, I’m scanning daily.

However, even at this high frequency scanning cadence there is a potential to miss DHCP assets. The same problem exists in the cloud with ephemeral assets. I call these assets “Ghosts assets”.

I know they are there, but they haven’t been scanned for vulnerabilities. So in terms of Tenable.io they are invisible hence the term Ghost. The goal is to identify these and scan them when they are on the network.

Tenable has a number of ways to discover assets on your network, however we are going to go directly to the source: our DHCP server. Note that I could use a number of services on the firewall to provide insight, I will stay focused on DHCP to reduce complexity.

So simply put, we are going to programmatically request DHCP leases from my pfSense firewall and import those assets into Tenable.io for visibility and scanning.

Authenticate to pfSense

pfSense doesn’t have a native API. However, thanks to the open source community there is a package that will add a RESTful API allowing you to get information about services or even configure your pfSense firewall.

Install pfSense API; simply run the below command from the pfSense shell:

pkg add https://github.com/jaredhendrickson13/pfsense-api/releases/latest/download/pfSense-2.5-pkg-API.txz && /etc/rc.restart_webgui

Create an API key to authenticate to pfSense

After logging into your pfSense firewall, navigate to System:API:Settings and click on the Generate Button to generate a new API Key.

Immediately afterwards you will be provided with an API key you need to copy:

To Authenticate to pfSense we need to craft our authorization header, which is our client-ID and the API key separated by a space:

“Authorization” : “<client-id> <Api Key>”

As the documentation explains, the header needs to include ‘application/json’ as the ‘Content-type’ shown below.

{‘Content-Type’: ‘application/json’, ‘Authorization’: ‘<client-id> <Api Key>’}

Pull DHCP Data

Sending a GET request to the ‘/services/dhcpd/leases’ endpoint will return the DHCP lease data. My firewall IP address in my lab is 192.168.128.1. Before we move forward, let’s print out what data our firewall will provide. As always, the pprint library is your friend when trying to read json data.

Example Response after running ‘get_data()’:

{‘code’: 200,
‘data’: [{‘ends’: ‘2022/04/02 01:43:10’,
‘hostname’: ‘AD Server’,
‘ip’: ‘192.168.128.89’,
‘mac’: ‘00:11:32:86:eb:dd’,
‘online’: True,
‘starts’: ‘2022/04/01 23:43:10’,
‘state’: ‘active’,
‘type’: ‘dynamic’}

As you can see above we get a bunch of useful DHCP lease information. We only need the IP, Hostname and Mac address since this is all we will be pushing to Tenable.io. While it’s not our focus, we could add more logic to avoid importing the asset or possibly tag it to add context if we desired. Providing the Mac address will ensure our assets will get matched with any current assets scanned by Nessus.

Review the pytenable documentation to see all the asset import options.

Read about Tenable.io’s asset matching algorithm for more details on how assets are evaluated.

Transform the data

The pytenable library requires a source and a dictionary containing the asset information. The Tenable.io API will allow you to update as many as 2500 assets at once. Using a python generator you could create chunks of 2500 assets should you need to import high asset numbers. However, for simplicity we are going to be submitting a single asset per request.

We need to create a host dictionary for pytenable, we will name it ‘host_dict’ and wrap it with a for loop cycling through each record returned by our firewall. Print the dictionary out afterwards to ensure we don’t encounter any unexpected errors.

Push Data to T.io

Now that we have DHCP data from our firewall we need to request a data import to Tenable.io. Again, thanks to pytenable this task is a one-liner. All we need to do is name our source and send our host_dict and pytenable will do the rest!

tio.assets.asset_import(“PFsense”, host_dict)

After a few minutes of cycling through your assets, log into Tenable.io and filter by your newly created source: “pfSense”. Importing thousands of assets can take a few minutes, so give it some time you appear to be missing any assets.

Identify previously Unknown assets

Since DHCP assets may be on and off the network, a network scan may not always have a chance to scan all assets. Now that we have all of the assets known by pfSense uploaded we can use Tenable’s tags to find and scan assets we haven’t seen before.

Simply stated we are going to look for assets that only have the source of PFsense. Using the “Only Contains” filter option we can quickly identify these assets.

Select all of the assets and click the Tag icon at the bottom to create a tactical scan of these assets. The tag I created is “Ghost Assets:PFsense”. Now simply set up a scan making this new tag the target.

While this article was focused on pfSense the concept applies to any DHCP server. Most Firewalls will have an API that you can get this data from and a simple Powershell script can obtain it from a Microsoft DHCP server.

I hope this article gave you some ideas and shown how simple such a powerful solution is to create. In my lab, I have this solution wrapped in a docker container and launched hourly on a cronjob.

Full Code Solution

If you are looking for a no-code solution to get assets into Tenable.io you can use Navi.

navi add --ip "1.1.1.1" --mac "00:01:02:AB:CD:EF" --hostname "Hostname" --source "Navi"

To upload a CSV list of IPs without any code:

navi add --file "my_ip_address_file.csv" --source "Excel/csv"

--

--

Casey Reid a.k.a Packet Chaos
Casey Reid a.k.a Packet Chaos

Written by Casey Reid a.k.a Packet Chaos

I'm a perpetually curious avid learner and athletic hacker/tinker who dabbles in python development, tenable integrations, philosophy, and writing

No responses yet