Add more checks to DNSCNC server

[+] Omit non-A requests. SOA and DS will bombard server in stealth mode
[+] Check that nonce is growing, or at least the same.
    Because of size, our AES-CTR scheme usage is insecure to CPA. While we
    really don't care about that, lets check at least that nobody plays
    with nonces. Growing nonce will kill the channel withing timeout
    time range.
This commit is contained in:
Oleksii Shevchuk 2016-12-03 09:00:00 +02:00
parent 240c503769
commit fe2d6b3fcb
1 changed files with 22 additions and 0 deletions

View File

@ -29,6 +29,8 @@ class Session(object):
self._last_access = 0
self.system_info = None
self.commands = commands
self.last_nonce = None
self.last_qname = None
@property
def idle(self):
@ -321,6 +323,11 @@ class DnsCommandServerHandler(BaseResolver):
qname = request.q.qname
reply = request.reply()
if request.q.qtype != QTYPE.A:
reply.header.rcode = RCODE.NXDOMAIN
logging.debug('Request unknown qtype: {}'.format(QTYPE.get(request.q.qtype)))
return reply
# TODO:
# Resolve NS?, DS, SOA somehow
if not qname.matchSuffix(self.domain):
@ -342,10 +349,25 @@ class DnsCommandServerHandler(BaseResolver):
try:
request, session, nonce = self._q_page_decoder(qname)
if session and session.last_nonce:
if nonce < session.last_nonce:
logging.error('Ignore nonce from past: {} < {}'.format(
nonce, session.last_nonce))
reply.header.rcode = RCODE.NXDOMAIN
return reply
elif session.last_nonce == nonce and session.last_qname != qname:
logging.error('Last nonce but different qname: {} != {}'.format(
session.last_qname, qname))
reply.header.rcode = RCODE.NXDOMAIN
return reply
for command in Parcel.unpack(request):
for response in self._cmd_processor(command, session):
responses.append(response)
if session:
session.last_nonce = nonce
except DnsCommandServerException as e:
nonce = e.nonce
responses = [e.error, Policy(self.interval, self.kex), Poll()]