I made a thing – Ember

Greetings, Programs!

I wrote this little utility to make it easier to get information about Cisco firewalls from Firewall Management center. It doesn’t require a python interpreter so it’s easier for non-programmy types to use. It’s also my first complete thing written in Go and I’m pretty happy about that.

Have a look, and if you have some cool feature ideas let me know in the comments.


May you care for yourself with ease.


Golang fun

Made some progress on my little app today (code updates happening on the development branch). This week, I learned the importance of composing structs when working with JSON (at least for working with in-memory data structures). What does all that mean?

So in python you have dictionaries that easily convert to json and vice versa, it’s like a couple of lines of code. Go is statically typed, so you have to model out the structure of the json body to tell go what tyes the values should be. Ok so you figure that out no worries, not too hard.

Now let’s talk about nesting.

Say you have json body with lists in it. if you want to be able to access those lists and work with them programmatically, then you need to do composition.

In this example, there’s a response with a list of certificates (only one shown here for brevity). If you wanted to work with those certificates individually, you would need to define a certificate struct, then a response struct, then make the certificate a slice of certificates inside the response. The way I figured it out was to print out the type of the struct I was getting from json.unmashal, to see if it was a generic struct or one I had defined.

  "response": [
      "id": "8c75350b-ea1b-4a51-a2e7-d37118ac04ae",
      "friendlyName": "Default self-signed server certificate",
      "serialNumberDecimalFormat": "16801809625158750310575466749",
      "issuedTo": "ise1.pod1.abl.ninja",
      "issuedBy": "ise1.pod1.abl.ninja",
      "validFrom": "Thu Mar 30 12:56:02 UTC 2023",
      "expirationDate": "Sat Mar 29 12:56:02 UTC 2025",
      "usedBy": "EAP Authentication, Admin, Portal, RADIUS DTLS",
      "keySize": 4096,
      "groupTag": "Default Portal Certificate Group",
      "selfSigned": true,
      "signatureAlgorithm": "SHA384withRSA",
      "portalsUsingTheTag": '"BYOD Portal (default), Blocked List Portal...',
      "sha256Fingerprint": "20af57d758f156d33a7616a664c58d605e53e7a1f678ebf08561421d6571cad6",
      "link": {
        "rel": "self",
        "href": "",
        "type": "application/json"


Ok so here’s how I modeled this in Go:

type CertList struct {
	Response []Cert

type Cert struct {
	ID                        string `json:"id"`
	FriendlyName              string `json:"friendlyName"`
	SerialNumberDecimalFormat string `json:"serialNumberDecimalFormat"`
	IssuedTo                  string `json:"issuedTo"`
	IssuedBy                  string `json:"issuedBy"`
	ValidFrom                 string `json:"validFrom"`
	ExpirationDate            string `json:"expirationDate"`
	UsedBy                    string `json:"usedBy"`
	KeySize                   int    `json:"keySize"`
	GroupTag                  string `json:"groupTag"`
	SelfSigned                bool   `json:"selfSigned"`
	SignatureAlgorithm        string `json:"signatureAlgorithm"`
	PortalsUsingTheTag        string `json:"portalsUsingTheTag"`
	Sha256Fingerprint         string `json:"sha256Fingerprint"`
	Link                      struct {
		Rel  string `json:"rel"`
		Href string `json:"href"`
	} `json:"link"`

So why did I do that? Because I wanted to get the certificate list for each node and simply bolt on to the node struct. to do that I can add my certificate type to my node type like this:

type node struct {
	Id   string
	Name string
	Link struct {
		Rel  string
		Href string
	Certs []Cert

Time for bed.


Firepower Custom Security Intelligence Feeds

Greetings, Programs!

Today I made a brief video on how to set up custom Security Intelligence feeds. This isn’t anything new by any means. However, with the rise of the 3rd party SOC, it’s still quite relevant and a valuable solution for cases where you want allow updates to simple block (or allow) lists without giving administrative access to the firewalls.

Documentation: https://www.cisco.com/c/en/us/td/docs/security/secure-firewall/management-center/device-config/730/management-center-device-config-73/objects-object-mgmt.html#ID-2243-00000291

Restarting work on ISE-T

Greetings programs,

Today I restarted work on my little go-based ISE utility after a long hiatus. It’s like going to the gym after a long absence. Some pain is involved. But I got something done! Just need to finish one task a day, and eventually, I’ll have a fully working tool. I’ll be rambling on about it here to give myself some accountability

The thing I was working on today (besides refamiliarizing myself with the code) was generalizing the API calls into one helper function. If you’re used to thinking like a Python programmer, the tricky part is you can’t just say, “Hey, give me back the JSON body, and I’ll dot into it to grab what I want”. This is because of Go’s strong typing. You have to model the JSON out as a struct ahead of time. Since each API call returns a different JSON data structure, you must have a separate function for each one. My solution was to split things up to have a generic function that will call an API endpoint, read the body into a byte slice, then pass that to another function that will unmarshal it into the struct that I can actually utilize.

It took a minute to figure all this out, but I got it to work.

Development branch: https://github.com/srmcnutt/ise-t/tree/development

ISE Device Extractor

Greetings, programs!

So, I made a thing.

ISE Device Extractor is a small python program that extracts all of the Network devices from ISE and outputs them in an Ansible compatible inventory file. Repo is here:


ISE Device Extractor

ISE is a good source of truth for network devices. I couldn’t find an existing tool to give me output from ISE that I could use for Ansible playbooks, so I made one. Since YAML is super easy to parse, you can use the inventory file as an input for other tools as well. Example uses would be to check and make sure that devices are categorized correctly, or that the inventory is accurate.

If you would like to test it, devnetsandbox.cisco.com has a reservable ISE sandbox. Search the catalog for ISE and select Identity Services Engine with MUD.

Rest of the details are in the readme. Enjoy. 🙂


Monday Morning notes – 03.02.2020

Greetings programs!

It’s been quite a ride for the last month or so, so much going on. Last Monday morning I passed the new Cisco DEVASC exam (200-901) on the first day to test, making me a member of the Devnet 500 club.

DEVNET 500 w00t!

Preparing for the exam really did a lot for sharpening up some relatively new skills I’ve acquired that haven’t had a lot of reinforcement. That’s the real value of IT certifications – having that performance-based focal point. When your learning is self-directed there is a real tendency to sort of wander from topic to topic and lose focus, and learning tracks are a great tool to combat that.

That said, I think the most important takeaway is that we’re rapidly transitioning to an API driven world and it’s important to get comfortable working with structured data and logical abstractions in general regardless of the job role.

Ok, about Terraform. What I’m working through is the approach I want to take. I want to bring a unique angle rather than join a chorus of people all saying and doing the same thing. If there are specific things you would like to see, let me know in the comments.

Thanks for reading and I’ll see you around.

Monday morning note 02.17.2020

Greetings Programs!

Just a quick check-in for this week.

Life has gotten a bit hectic recently, and will likely remain so for another couple of weeks. Small things are beginning to take conscious effort and focus which is a reliable indicator that I need to trim the sails a little. What this means for this space is the first Terraform post is delayed for a week, possibly two.

On a brighter note, the weather was wonderful for this morning’s walk, my dogs were well behaved, and coffee is always there for us and wants us to be happy.

Until next time, may you care for yourself with ease.


Case study: Combating MAC address spoofing in access networks

Greetings programs!

Last week I went down an interesting rabbit hole of MAC address spoofing. I found that while the problem was well defined and easily researched, there were no simple prescriptive recipes for a solution. I thought it might be helpful to share this solution in the hopes it could be useful to others.

I would like to acknowledge the contributions of Marvin Rhoads for technical vetting and proofreading, and Brad Johnson (web page) for climbing down into the rabbit hole with me and lending his considerable expertise.

Unmasking the imposter


Media Access Control (MAC) Addresses commonly are used to identify endpoints for purposes of access control and authorization on access layer networks that have yet to implement 802.1x (dot1x) device authentication. The problem with this approach is MAC address spoofing is trivial to implement. However, with a defense in depth approach using basic tools and techniques, the risk and impact can be largely mitigated.

To explore the issues, we are going to evaluate the case of an organization that had recently implemented a network access control solution. A network penetration tester easily bypassed their access controls by cloning a mac address from an IP phone to a Linux laptop computer,


The organization had recently implemented Cisco Systems Identity Services Engine (ISE) and had hired a pen-testing firm to evaluate its efficacy in preventing unwanted access to the network. In general, Network Access Control (NAC) implementations take a phased approach to control risk and get immediate value from the tool, and this was the case here.

At the time the penetration test was performed, some of the network was using 802.1x authentication with digital certificates, and some of the network was using MAC Authentication Bypass (MAB) combined with device profiling to determine the correct level of authorization for a connecting device.

Additionally, the Authorization policies weren’t fully implemented, so effectively authorization was a simple ‘yes/no’ result where full access is granted based on a device profile match.

When the Pentester did her work, she grabbed the MAC address off the back of an IP phone in a common area, applied it to her Linux laptop computer, and used the network cable from the IP phone to connect to the network. ISE recognized her computer as the IP phone, and she was granted unrestricted access to the network.

The information security team had the impression that ISE was able to handle a basic access layer attack like MAC address spoofing, and wanted some answers regarding how this happened and what could be done to mitigate it until they were able to roll out dot1x authentication


Before getting into the details, we will set the stage by briefly reviewing how the ISE profiler works. Then we will:

  1. Dive into what happens when Windows and Ubuntu Linux devices connect to the network with the same MAC address as a test IP phone
  2. Review the ISE Anomalous Endpoint Detection (AED) feature and explain why it is ineffective in this case

ISE profiler primer

The ISE profiler has 11 modules that ingest information from a variety of sources to build a database of endpoints and endpoint attributes. The primary key for this data structure is the MAC address of the endpoint. The ISE user interface provides an interface to view the endpoint database and inspect individual endpoints through the Context VisibilityEndpoints Menu.

Endpoint Database and Endpoint Attributes

Figure – endpoint database

By clicking on the MAC address of the endpoint, we can view detailed information from the database

Figure – Summary information about the endpoint

In figure 2, we can conclude that Media Access Control (MAC) Authentication bypass is being employed because the username is the same value as the MAC address. Ultimately this means we are not doing authentication. However, we can use the profiling information to authorize a specific level of access, which we will review later.

In the following image, we can see some attributes that ISE learned, as well as a value called Total Certainty Factor (TCF)

Figure TCF and attributes learned from Device Sensor

So how is this information employed? ISE evaluates the attributes against a set of profiling policies, the policy with the highest TCF is assigned as the endpoint policy for that device. We then use that endpoint policy to decide how much access (if any) to authorize.


ISE profiling policies

Profiler polices assign point values to matching attributes. The highest Total Certainty Factor (TCF) score wins. The policies are arranged in a tree-like structure from coarse to finer-grained. The minimum score at each level of the tree has to be met before the child nodes will be evaluated.

Figure – Profiler policy for a 7965 IP phone

Logical polices

Logical policies are used to group like devices together where a collective policy decision would be made for them. It is the functional equivalent of putting users into groups for granting access to files and folders on a computer.

Figure – Logical profile

Policy Set Authorization (AuthZ) rule

Finally, we use the logical profile in an authorization rule, which then directs the network device to apply the authorization we have defined.

Figure – Authorization rule for IP Phones

So how does mac address spoofing bypass this system? Now that we have set the stage, we can start to talk about that.

Effect of MAC address spoofing on the profiler

Now we will see what happens when we try a Windows and then a Linux Computer using the MAC address of our previously profiled phone

Windows laptop

For our first, we will connect a Windows 10 computer to the switch, with the same mac address as the test phone, and we will see what changes.

Figure – Windows 10 laptop

Reviewing figure 7, There are 4 items highlighted:

  1. Authorization profile
  2. Total Certainty Factor
  3. Dhcp-class-identifier
  4. Host-name

The reason why we have an authorization result of DenyIP is that I had configured Anomalous endpoint detection. The dhcp-class-identifier change triggered the Anomalous Endpoint flag on the endpoint to true. I then used this as a condition in a rule to return the DenyIp authorization result. We will dive into the details in the AED section.

There are two main takeaways here:

  1. ISE was able to respond to the MAC address spoofing attempt and flagged the endpoint.
  2. The attributes from when the phone was profiled are still present, even though we can be reasonably sure the laptop did not send them.

It is the second point that’s important to understand. The absence of a value being sent (that was sent prior) does not equal a change as far as the profiler is concerned. The TCF changed by -30 because the dhcp-class-identifier value is scored in two locations for 10 and 20 points, respectively.

Figure – how attribute matches are scored

It is essential to grasp that except for DHCP, when endpoint attributes accumulate, they remain until there is a change. Usually, this is not too much of a problem….

Once a device has had the AED flag set, the only way to clear the condition is to delete the endpoint. I am going to unplug the laptop, delete the endpoint, and next, we will try the Ubuntu Laptop.

Linux laptop

The endpoint was deleted, the phone plugged back in, and our endpoint has been recreated with the phone accurately identified. Now let us plug in the Linux laptop and take a look.

Figure – Linux laptop

The only informational DHCP attribute Ubuntu sends in its DHCP discovery request is host-name. The result is that the laptop received the IP_phones Authorization Profile. Why didn’t AED fire and block the endpoint?

Because we are not getting anything actionable, there is nothing to trigger ISE. If the residual attributes left from when the phone was plugged in were not persistent, this would trigger a reprofile and we would be able to do something. The reasons the attributes are cached are understandable, but it presents a difficulty here.

The main takeaways here are:

  1. In default DHCP configuration, the Ubuntu laptop doesn’t give up any useful information.
  2. We just got p0wned.

Anomalous Endpoint Detection (AED)

We saw that AED worked in the case of a Windows machine but not in the case of the Ubuntu Linux machine. Let us take a closer look at AED and see how it works.

According to the Documentation (Cisco, 2018), AED can trigger on a change in one of three things.

  1. NAS-Port-Type (i.e. wired or wireless)
  2. DHCP-class-identifier
  3. Endpoint policy change

If any of these conditions occur with AED enabled, the endpoint will be flagged. It should be noted that not getting the class-id when it was received prior will not trigger AED. And this is why we got p0wned by Linux.

While we are here, let us walk through how to configure AED.

  1. Enable it
  2. Create an Authorization exception rule that matches on the AnomalousBehaviour endpoint flag
  3. Apply an authorization profile that allows the device to receive an address (optional, I’ll explain)

Enabling AED

In the profiler configuration settings, check off the AED boxes.

Figure – Enable AED

Define a DACL that only allows DHCP/Bootp

Reference the DACL in an authorization profile:

In the policy set, create an Exception rule that conditions on AnomalousBehaviour Endpoint Attribute. In this case, I also conditioned on IP phones because I only want the scope to cover the specific assets of interest. Assign the AuthZ profile.

Why the access-accept, and why give out an IP address? The simple answer is visibility. If we give the device an IP address, ISE can ingest the DHCP attributes and we will be able to tell from the ISE UI that a different device has been plugged in even though the endpoint was flagged by AED. If we were to prevent all access, we might not receive any new information until the endpoint was deleted and recreated.

Proposed Solution

Now we have discussed the limitations of AED and the inability to act with the Linux laptop because ISE is not receiving any actionable information. Even if we rolled out 802.1x, there might still be devices that require using MAB, so we cannot sidestep the issue.

There is a straightforward solution: Implement first-hop security and require the client to send a class-identifier in its DHCP requests. If the class-identifier does not match, or there is not one sent, then the device will not obtain an IP Address.

There are three tools we will employ to accomplish this:

  1. DHCP Snooping (which you have already enabled on your network, right?)
  2. IP source guard (depends on DHCP snooping, prevents user-assigned static addresses)
  3. DHCP policy on the DCHP Server

DHCP Snooping

DHCP snooping listens to DHCP traffic and creates a table of IP MAC and Interface bindings. Configuring DHCP snooping is very straightforward. However, consult the documentation and make to understand how to scope it to specific VLANS and trust the uplinks leading towards the DHCP server. (Cisco Security Configuration Guide, no.date.)

Sample configuration:

ip dhcp snooping vlan 10,100

no ip dhcp snooping information option

ip dhcp snooping


interface GigabitEthernet1/0/48


!———–Trust the northbound link towards the DHCP server

ip dhcp snooping trust


Binding example:

IP Source Guard

IP source guard will check the DHCP snooping binding table as well as the static binding table for a matching entry when IP packets are received on the switchport. If there no match, the traffic will be dropped. This prevents an attacker from statically applying an IP address.

Ip source guard is a one-line command:

interface GigabitEthernet1/0/36


ip verify source

Verification output:

DHCP Policy

To close the loop, we will create a DHCP policy that will only offer addresses to devices that send the correct class-id in the DHCP Discover or Request packets. (Microsoft Docs, 2016). Creating the policy consists of the following steps:

  1. Create a vendor Class
  2. Create a policy that references the vendor class

Creating the Vendor Class.

In the DHCP management tool, right-click on the IP Address family icon and select define vendor classes. When defining the class, the beginning or the end of the string can be used for wildcard matches, but the characters must be exact. An easy way to get this is to copy it from the endpoint attribute in ISE.

Creating the policy that references the vendor class

  1. In the policies folder, right-click and select new policy. This will launch the new policy wizard.
  2. On the configure conditions window, click add to add a condition.
  3. Select vendor class, operator, the vendor class defined earlier, then wildcard if desired. Select add, and click ok.

  1. Use all of the addresses in the scope. NOTE: once done, the policy will reserve 100% of the addresses even if disabled. The policy must be deleted to release the reservation.

  1. Click through the rest of the wizard and select finish.


Strong authentication using 802.1x will protect against identity spoofing, but it is a significant undertaking for existing networks, and it takes time to roll out. Additionally, there may be devices that cannot perform 802.1x authentication, but they require network access. Therefore, we have to deploy a defense-in-depth strategy to secure the access network when device authentication is not possible.


  • Use 802.1x with certificate authentication whenever possible.
  • If you have a NAC such as ISE, employ least privilege authorization to mitigate impact.
  • Deploy First Hop Security (FHS), primarily DHCP snooping and IP Source Guard.
  • DHCP servers are a good control point to perform policy enforcement. Take advantage.
  • Take operations security practices seriously and follow the cycle.


Cisco. (2018, May). Configure Anomalous Endpoint Detection and Enforcement on ISE 2.2. Retrieved from Cisco.com: https://www.cisco.com/c/en/us/support/docs/security/identity-services-engine-22/200973-configure-anomalous-endpoint-detection-a.html

Cisco Security Configuration Guide. (no.date.). Security Configuration Guide, Cisco IOS XE Fuji 16.9.x, Configuring DHCP. Retrieved from Cisco.com: https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst9300/software/release/16-9/configuration_guide/sec/b_169_sec_9300_cg/configuring_dhcp.html?bookSearch=true&arrowback=true

Microsoft Docs. (2016, August 31). Scenario: Secure a subnet to a specific set of clients. Retrieved from https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn425039(v%3Dws.11)

Monday Morning Brief: Terraform series coming

Greetings programs!

Just a quick post this morning to mention that I’m working on a thing about deploying infrastructure with Terraform. Tentatively should have the first installment out next Monday.

For the not-yet-informed. Terraform is an infrastructure deployment tool that takes a text file description of a distributed application infrastructure, compares it to what exists, and changes reality to match the description of what you want. It does this very well, and has a quick learning curve and excellent ease of use. If you’re doing production deploys into AWS or Azure, or even Cisco ACI, this is a tool you should get to know.

Brilliant sunrise this morning

If you want to understand how Terraform does it’s thing from an architecture perspective here’s a link to a 30 minute talk that I found enlightening. TL;DR Graph theory is everywhere!

That’s it for this week. May you care for yourself with ease, and may the odds ever be in your favor.