Monitoring for NDP Spoofing

I have previously posted a blog post describing how to monitor for ARP Spoofing. With IPv6 on everyone’s mind today (It IS on your mind, right?), it would seem that it is a good time to talk about a similar concern for IPv6 networks. IPv6 networks do not support multicast, but they DO have a comparable protocol. Unfortunately, it is also subject to the same exploits using similar techniques. Like ARP however, there are tools available to assist in monitoring and detecting NDP spoofing attempts. Let’s look at how we can proactively monitor this critical function of our network.

Understanding Neighbor Discovery Protocol

In order to address this issue, we must first have an understanding of why NDP is not more secure.

Neighbor Discovery Protocol, defined by RFC 4861 is the IPv6 replacement for ARP. This newcomer in the protocol world handles not only (OSI) Layer 3 to Layer 2 address mapping, but expands to include router discovery, neighbor presence, redirects, network options (think DHCP options) and stateless auto-configuration. NDP is an absolutely critical protocol on ANY local IPv6 network. This is also, similar to ARP, susceptible to Flooding and Poisoning attacks, due to the fact that NDP cannot easily handle security in most scenarios without affecting it’s dynamic configuration ability.

While it may seem at first look to be a lack of forethought to write a modern protocol that, by default, allows the same exploits as it forerunner, you must take into account the consideration that this protocol is a “first contact protocol” just as it’s predecessor was. Designed for be utilization during the initial configuration of the network interface itself makes it VERY difficult to both support dynamic configuration AND security. IPV6 does, after all, use NDP for the basis of auto-configuration.

Hardening NDP is a topic that is WELL beyond the scope of this post. If you are adventurous or experimental by nature and would like to try it out, the NSA has an IPv6 focused supplement to it’s Router Security Configuration Guide available for download.

Addressing the Issue

Note – NDP Monitoring is a fairly new concept, so not much attention has been spent on the practice by most howto sites yet. NDPmon, however, is looking like one of the applications which we will depend on heavily in the future. Getting used to it’s configuration now is very likely be time very well spent.

Addressing the issue requires us to monitor requests on the network and alert on changes. The optimum method for handling the monitoring process on a switched network is to configure a port on your switch as a monitor port, and installing the monitoring services on a computer connected to that port. If your switching equipment does not support monitor port configuration, then the alternate method would be to install these utilities on as many machines as possible. It is critical that you do not skimp on monitoring saturation as it is impossible to know which computer would be targeted by a spoofing or poisoning attack.

NDPmon is a Sourceforge project, headed by Frederic Beck – Inria, and is available for a number of Posix Systems. NDPmon uses libpcap to capture and analyze IPv6 traffic for changes. This project is designed to work along with arpwatch, and uses the same alert methods.

Most Linux distributions have a packaged version of ndpmon available, and I recommend using this method if it is there for maintenance purposes. for this, we would simply type (for Debian-based distros):

apt-get install ndpmon

If your distro does not include this package, you can use the instructions on the sourceforge documentation page.

IT is not recommended to use stateless autoconfiguration on the host running ndpmon. If you are not using stateful dhcp/dns, you should manually configure a global address on the host. You are then ready to configure and use ndpmon.

The default configuration file for ndpmon is /etc/ndpmon/config_ndpmon.xml. this is (obviously) an xml config, and is fairly easy to edit using your favorite editor or exim. The defult config_ndpmon.xml will look similar to this:

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="config.xsl" ?>
<!DOCTYPE config_ndpmon SYSTEM "/etc/ndpmon/config_ndpmon.dtd">
<config_ndpmon>
<ignor_autoconf>1</ignor_autoconf>
<syslog_facility>LOG_LOCAL1</syslog_facility>
<admin_mail>root@localhost</admin_mail>
<actions_low_pri>
<sendmail>0</sendmail>
<syslog>1</syslog>
<exec_pipe_program>/usr/lib/ndpmon/create_html_table.py</exec_pipe_program>
</actions_low_pri>
<actions_high_pri>
<sendmail>0</sendmail>
<syslog>1</syslog>
<exec_pipe_program>/usr/lib/ndpmon/create_html_table.py</exec_pipe_program>
</actions_high_pri>
<use_reverse_hostlookups>1</use_reverse_hostlookups>
<routers>
<!-- Example of router definition
<router>
<mac>00:11:22:33:44:55</mac>
<lla>fe80:0:0:0:211:22ff:fe33:4455</lla>
<param_curhoplimit>64</param_curhoplimit>
<param_flags_reserved>0</param_flags_reserved>
<param_router_lifetime>10800</param_router_lifetime>
<param_reachable_timer>0</param_reachable_timer>
<param_retrans_timer>0</param_retrans_timer>
<param_mtu>0</param_mtu>
<params_volatile>1</params_volatile>
<prefixes>
<prefix>
<address>2001:db8:1234:5678:0:0:0:0</address>
<mask>64</mask>
<param_flags_reserved>224</param_flags_reserved>
<param_valid_time>2592000</param_valid_time>
<param_preferred_time>604800</param_preferred_time>
</prefix>
</prefixes>
<addresses/>
</router>
-->
</routers>
<!-- Example of countermeasures configuration
(If no configuration is present, all countermeasures will be suppressed.)
<countermeasures>
<kill_illegitimate_router>RESPOND</kill_illegitimate_router>
<kill_wrong_prefix>LAUNCH AFTER 10</kill_wrong_prefix>
<propagate_router_params>CEASE AFTER 10</propagate_router_params>
<indicate_ndpmon_presence>SUPPRESS</indicate_ndpmon_presence>
</countermeasures>
-->
</config_ndpmon>

The first step is to establish a baseline of the network, to do this, we can launch ndpmon in learning mode sig the follow command as root:

ndpmon -L

The -L switch starts the service in learning mode, assuming no network configuration errors and no untrustworthy traffic. It will output items detected to the console in a format similar to this:

root@system:/etc/ndpmon# ndpmon -L
----- Initialization -----
learning phase
Reading configuration file: "/etc/ndpmon/config_ndpmon.xml" ...
    Done.
------------------

----- ND_NEIGHBOR_SOLICIT -----
Reset timer for 0:f:8f:89:48:e0 fe80:0:0:0:20f:8fff:fe89:48e0
------------------

Writing cache...
----- ND_NEIGHBOR_ADVERT -----
Reset timer for 14:da:e9:e0:b7:5a fe80:0:0:0:16da:e9ff:fee0:b75a
------------------

----- ND_NEIGHBOR_SOLICIT -----
Reset timer for 14:da:e9:e0:b7:5a fe80:0:0:0:16da:e9ff:fee0:b75a
------------------

Exiting ndpmon, after some time has passed, will end the sampling phase. As the ndpmon configuration assumed that everything learned during auto-configuration was correct, it would be wise to go back and check the configuration after learning just for sanity’s sake. Let’s look at an example of the changes on a quick monitor:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE config_ndpmon
SYSTEM "/etc/ndpmon/config_ndpmon.dtd">
<?xml-stylesheet type="text/xsl" href="config.xsl" ?>
<config_ndpmon>
<ignor_autoconf>1</ignor_autoconf>
<syslog_facility>LOG_LOCAL1</syslog_facility>
<admin_mail>root@localhost</admin_mail>
<actions_low_pri>
<sendmail>0</sendmail>
<syslog>1</syslog>
<exec_pipe_program>/usr/lib/ndpmon/create_html_table.py</exec_pipe_program>
</actions_low_pri>
<actions_high_pri>
<sendmail>0</sendmail>
<syslog>1</syslog>
<exec_pipe_program>/usr/lib/ndpmon/create_html_table.py</exec_pipe_program>
</actions_low_pri>
<actions_high_pri>
<sendmail>0</sendmail>
<syslog>1</syslog>
<exec_pipe_program>/usr/lib/ndpmon/create_html_table.py</exec_pipe_program>
</actions_high_pri>
<use_reverse_hostlookups>0</use_reverse_hostlookups>
<routers>
<router>
<mac>0:f:8f:89:48:e0</mac>
<lla>fe80:0:0:0:20f:8fff:fe89:48e0</lla>
<param_curhoplimit>64</param_curhoplimit>
<param_flags_reserved>0</param_flags_reserved>
<param_router_lifetime>1800</param_router_lifetime>
<param_reachable_timer>0</param_reachable_timer>
<param_retrans_timer>0</param_retrans_timer>
<param_mtu>1500</param_mtu>
<params_volatile>1</params_volatile>
<prefixes>
<prefix>
<address>2001:470:e5cb:1:0:0:0:0</address>
<mask>64</mask>
<param_flags_reserved>192</param_flags_reserved>
<param_valid_time>2592000</param_valid_time>
<param_preferred_time>604800</param_preferred_time>
</prefix>
</prefixes>
<addresses/>
</router>
</routers>
<countermeasures>
<kill_illegitimate_router>SUPPRESS</kill_illegitimate_router>
<kill_wrong_prefix>SUPPRESS</kill_wrong_prefix>
<propagate_router_params>SUPPRESS</propagate_router_params>
<indicate_ndpmon_presence>SUPPRESS</indicate_ndpmon_presence>
</countermeasures>
</config_ndpmon>

The basic auto-configuration should get you up and running. Documentation on configuration for this service is sparce, but available. It is worth looking at the configuration and plugins pages on sourceforge once auto-configuration is complete to review options for configuration.

These steps, as before with ARP monitoring, should get you stated with NDP monitoring. The next step is to configure a Syslog server to simplify the process monitoring the logs themselves. For that step, please refer to my post “Centralize Your System Logging Using Syslog.