From fe2d6b3fcbad7e6cae12cd225347e953e6416675 Mon Sep 17 00:00:00 2001 From: Oleksii Shevchuk Date: Sat, 3 Dec 2016 09:00:00 +0200 Subject: [PATCH] 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. --- pupy/network/lib/picocmd/server.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pupy/network/lib/picocmd/server.py b/pupy/network/lib/picocmd/server.py index 649caffa..6936c09c 100644 --- a/pupy/network/lib/picocmd/server.py +++ b/pupy/network/lib/picocmd/server.py @@ -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()]