Friday, January 22, 2010

Rogue DHCP detector in Nagios

This Python script I created can be used with Nagios to warn if there are unauthorized DHCP servers on the network. No third party libraries are used.

At the moment the script only checks at IP level, and does not return the MAC address of the rogue server. My plan is to expand this at some stage, but at the moment we do not really need this in our setup.


#!/usr/bin/python
from socket import *
from binascii import *
from random import *
from struct import *

# local machine mac address
chaddr = unhexlify('001122334455')

# allowed dhcp servers
whitelist = set(['11.22.33.44'])

# random session id (xid)
xid = pack('L', randrange(0, 2**32 - 1 ))

# setup socket
s = socket(AF_INET, SOCK_DGRAM)
s.bind(('0.0.0.0', 68))
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)

request = \
'\x01\x01\x06\x00' \
+ xid \
+ ''.ljust(20, '\x00') \
+ chaddr.ljust(16, '\x00') \
+ ''.ljust(192, '\x00') \
+ '\x63\x82\x53\x63' \
+ '\x35\x01\x03' \
+ '\xff'
s.sendto(request, ('255.255.255.255', 67))

# listen for dhcp packets for max 2.5 seconds
status = "OK - No rogue dhcp servers detected"
r = 0
s.settimeout(2.5)
while 1:
try:
buf, (ip, port) = s.recvfrom(65565)
except:
break
opcode, = unpack_from('B', buf)
if not (ip in whitelist and opcode == 0x02):
r = 2
status = "CRITICAL - Rogue dhcp server detected on IP-addr: " + ip
break

s.close()
print status
exit(r)


3 comments:

  1. Hi Allan,

    I tried to run your python code but doesn't seem to work properly for me.

    This is my output :

    root@dream0ne sandbox # ./rogue_detect.py
    OK - No rogue dhcp servers detected

    And here is what I changed my variables to:

    chaddr = unhexlify('000c29805c7c')
    whitelist = set(['11.22.33.44']) # (default)

    I tried also to increase the timeout to 60 seconds but with the same result.

    Using tcpdump I can see the dhcp-request but not a server-reply :

    TIME: 2010-02-10 11:19:21.026
    IP: 192.168.96.51 (0:c:29:80:5c:7c) > 255.255.255.255 (ff:ff:ff:ff:ff:ff)
    OP: 1 (BOOTPREQUEST)
    HTYPE: 1 (Ethernet)
    HLEN: 6
    HOPS: 0
    XID: fa00f3d5
    SECS: 0
    FLAGS: 0
    CIADDR: 0.0.0.0
    YIADDR: 0.0.0.0
    SIADDR: 0.0.0.0
    GIADDR: 0.0.0.0
    CHADDR: 00:0c:29:80:5c:7c:00:00:00:00:00:00:00:00:00:00
    SNAME: .
    FNAME: .
    OPTION: 53 ( 1) DHCP message type 3 (DHCPREQUEST)

    It sounds like the dhcp-request is malformed. Any ideas?

    Thank you in advance,
    Simone

    ReplyDelete
  2. Are you sure you got the local MAC address right? I can't think of anything else that could make the packet malformed on your system, but working here. The request is created from the description on http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol , and from what was observed when using tcpdump (actually Wireshark) to check against a real request. The request you posted looks sane enough I think. Maybe try tcpdumping a real request, and compare it to the script's request. Hope you get it working!

    ReplyDelete
  3. Hi Alla,

    >Are you sure you got the local MAC address right?
    yep, nic's mac is correctly taken.

    I launched the script on two different networks with the same result using the dnsmasq||dhcpd3-server daemon.

    I'll perform some further test in my netkit virtual-lab.

    Thank you :)

    Simone

    ReplyDelete