Introduction
The first step to a penetration test is reconnaissance. Identifying the target and working from there. When it comes to a Software-Defined Network (SDN), a prime target is the network controller. By fingerprinting the network controller one can begin the process of compromising it and taking control of the network. This article is based on work from the paper “Fingerprinting OpenFlow controllers: The first step to attack an SDN control plane”. It will look at a few ways the controller can be identified; LLDP frame frequency, LLDP frame contents, and port/URI details. All of this detection can be done using the sdnpwn controller-detect module.
sdnpwn@pc ~/sdnpwn> ./sdnpwn.py info controller-detect [+] Module Name: controller_detect [+] Description: Attempts to fingerprint the network controller. [+] Usage: Option Description Required --------------------- -------------------------------------------------------- ---------- -i | --iface Interface to use No -l | --lldp Determine controller based off LLDP traffic No -d | --dump-lldp Dump the contents of the LLDP message No -n | --ignore-content Do not detect controller based on LLDP content No -t | --target Determine controller based northbound interface No -p | --ports Set ports to scan when --target is specified. No -x | --proxy Define a proxy server to use when --target is specified. No -v | --verbose Show verbose output
LLDP Frame Frequency
Link Layer Discovery Protocol (LLDP) is used by many SDN controllers to learn about links in the network. The controller will send LLDP frames down to each connected switch and the switches will flood these frames out all ports. The controller will send these frames to the switches at a certain frequency, and the switches will therefore flood these frames at the same frequency. Controllers often use different default frequencies, so by tracking the frequency it’s easy to work out exactly which controller is being used.
The simplest way to do this accurately is to capture several LLDP frames and look at the time difference between the frames arriving. Do this 3 times and you can work out an average frequency. Compare this frequency to a list of known frequencies, allowing for some margin of error (e.g. +-5%) , and the controller can be identified. Below is a table of default LLDP frequencies used by different controllers (mostly taken from [1]):
Controller | Frequency |
Floodlight | 15 |
OpenDayLight (Lithium & Helium) | 5 |
OpenDayLight (Hydrogen) | 300 |
Pox | 5 |
Ryu | 1 |
Beacon | 15 |
ONOS | 3 |
The sdnpwn controller-detect module will capture LLDP frames on a given interface and use the above frequencies to detect the controller. The following command will do this on interface eth0:
./sdnpwn.py controller-detect -i eth0 --lldp
It should be noted however, that the LLDP frame frequency can change depending on the configuration or the link discovery application used. If the frequency doesn’t give you enough information, the LLDP message contents might help.
LLDP Contents
LLDP allows for optional Type-Length-Value (TLVs) to be added to a message. Controllers use these optional TLVs to add identity information (i.e. the DPID) of a switch used to flood frames. This way, when a controller receives an LLDP frame from a switch, it can look at the TLVs to work out which switch that LLDP frame originated from.
Looking at the contents on an LLDP message can be a quicker way of identifying the controller than monitoring the frequency. The contents of an ONOS LLDP frame, for example, contain the string “ONOS Discovery”. The controller-detect module will automatically try to detect the controller using the contents of the LLDP frame, however this may not be successful if sdnpwn does not have the contents mapped to a known controller. A handy option in this case is –dump-lldp. Using this option, you can check for any obvious indicators, or if you know the controller, use the output to contribute a new fingerprint to the controller-detect module.
Service Information
The open ports and available URLs on the controller can be another identifier. Of course this requires a network connection to the controller itself. The following command will automatically check a given IP address for known open ports and URLs, and output the controllers that the target may be:
sdnpwn@pc ~/sdnpwn> ./sdnpwn.py controller-detect -t 192.168.56.102 [+] Testing visibility of northbound interface on host 192.168.56.102 [+] Enumerating ports... [*] Made HTTP connection to 192.168.56.102 on port 8181 Port used by OpenDayLight (DLUX w/t Karaf) & ONOS for GUI interface [+] Testing GUI URLs for port 8181 [*] Got 200 for /onos/ui/login.html URL associated with ONOS GUI interface
The target of the above command was running ONOS 1.9.0.
References
[1] https://ieeexplore.ieee.org/abstract/document/7841843/