def handle(self): try: data = self.get_data() query = dnslib.DNSRecord.parse(data) reply = query.reply() answers = [] if reply.get_q().qtype == dnslib.QTYPE.TXT: try: challenge_files = os.listdir(BaseDNSRequestHandler.challenges_path) for challenge_file in challenge_files: if challenge_file.startswith(str(reply.get_q().qname).strip('.')): with open(os.path.join(BaseDNSRequestHandler.challenges_path, challenge_file), 'r') as challenge_data: answers.append(dnslib.RR(rname=reply.get_q().qname, rtype=reply.get_q().qtype, ttl=60, rdata=dnslib.TXT(challenge_data.read().strip()))) except OSError: pass else: answers.append(dnslib.RR(rname=reply.get_q().qname, ttl=60, rdata=dnslib.A(LISTEN_ADDRESS))) for answer in answers: reply.add_answer(answer) self.send_data(reply.pack()) except Exception as e: print(e)
def try_tox3_resolve(self, reply, name, domain, req_name): if not name.startswith("_"): return None encrypted = name.replace(".", "")[1:] try: b = notsecure32_decode(encrypted) nonce = b[:4] + (b"\0" * 20) ck = b[4:36] payload = b[36:] dec_name = self.cryptocore.dsrep_decode_name(ck, nonce, payload) except Exception: return None try: dec_name = dec_name.decode("utf8") except UnicodeDecodeError: return None query = self.db.query(User).filter( and_(User.name == name, User.domain == domain)) user = query.one() if not user: return None msg = binascii.unhexlify(user.toxid) nonce_reply = b[:4] + b"\x01" + (b"\0" * 19) ct = self.cryptocore.dsrec_encrypt_key(ck, nonce_reply, msg) key_part = notsecure32_encode(ct).decode("ascii") base = "v=tox3;id={0}".format(key_part).encode("utf8") reply.add_answer(dnslib.RR(req_name, 16, ttl=0, rdata=dnslib.TXT(base))) return reply
def handle(self): global count count=count+1 #序号 request_data = self.request[0] client_socket = self.request[1] #内部搜索 d=DNSRecord.parse(request_data) qname=str(d.q.qname) qid=d.header.id search=cache.get(qname) #print(qname) if search: ret=d.reply() # 不良网站 if search=="0.0.0.0": ret.add_answer(dnslib.RR(qname,QTYPE.TXT,rdata=dnslib.TXT(warning))) else: ret.add_answer(dnslib.RR(qname,rdata=dnslib.A(search))) ret.header.id=qid if debug_print: print(time.asctime( time.localtime(time.time()))," ", count," ",self.client_address,qname) elif debug_print2: print("\n\n\n") print("*******Request Data***********") print(d) print("********Client Address********") print(self.client_address) print("********Search Name***********") print(qname) print("********Search IP*************") print(search) client_socket.sendto(bytes(ret.pack()), self.client_address) else: # 将请求转发到 外部 DNS redirect_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) redirect_socket.sendto(request_data, (DNS_server, 53)) response_data, address = redirect_socket.recvfrom(8192) if debug_print: print(time.asctime( time.localtime(time.time()))," ", count," ",self.client_address,qname) elif debug_print2: print("\n\n\n") print("*******Request Data***********") print(d) print("********Client Address********") print(self.client_address) print("********Search Name***********") print(qname) print("********Search IP*************") print(DNSRecord.parse(response_data)) # 将外部响应响应给客户 client_socket.sendto(response_data, self.client_address)
def resolve(self, request, handler): reply = request.reply() qname = request.q.qname # Refuse queries thaat are not for our domain if tuple(map(str.lower, map(qname._decode, qname.label[-2:]))) != \ tuple(map(str.lower, map(self.domain._decode, self.domain.label[-2:]))): reply.header.rcode = dnslib.RCODE.REFUSED return reply # Answer questions about the root domain name # TODO(supersat): We don't need to implement this, right? if len(qname.label) <= 3: if request.q.qtype == dnslib.QTYPE.A: reply.add_answer( dnslib.RR(qname, dnslib.QTYPE.A, ttl=300, rdata=self.server_ip)) return reply subdomain = qname._decode(qname.label[1]).lower() hostname = qname._decode(qname.label[0]).lower() if BASE36_SHA256_HASH.match(subdomain) and len(qname.label) == 4: if hostname == '_acme-challenge' and \ (request.q.qtype == dnslib.QTYPE.TXT or \ request.q.qtype == dnslib.QTYPE.ANY): txt = self.redis.get('acme-dns-01-chal:{}'.format(subdomain)) if txt: reply.add_answer( dnslib.RR(qname, dnslib.QTYPE.TXT, ttl=300, rdata=dnslib.TXT(txt))) else: reply.header.rcode = dnslib.RCODE.NXDOMAIN elif IPV4_REGEX.match(hostname) and \ (request.q.qtype == dnslib.QTYPE.A or \ request.q.qtype == dnslib.QTYPE.ANY): try: ip = tuple(map(int, hostname.split('-'))) reply.add_answer( dnslib.RR(qname, dnslib.QTYPE.A, ttl=300, rdata=dnslib.A(ip))) except: reply.header.rcode = dnslib.RCODE.NXDOMAIN else: reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply
def try_tox1_resolve(self, reply, name, domain, req_name): query = self.db.query(User).filter( and_(User.name == name, User.domain == domain)) user = query.one() if not user: reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply else: rec = "v=tox1;id={0}".format(user.toxid).encode("utf8") reply.add_answer( dnslib.RR(req_name, 16, ttl=self.ttl, rdata=dnslib.TXT(rec))) return reply
def resolve(self, req, handler): reply = req.reply() try: obj = TheQueryResponsePair(req, reply) obj.evaluate() except Exception as ex: reply.add_ar( dnslib.RR( rname = '' + str(ex.__class__.__name__) + ".exception", rclass = dnslib.CLASS.IN, rtype = dnslib.QTYPE.TXT, ttl=10, rdata=dnslib.TXT(str(ex)) ) ) return reply
def make_jianbing(query): response = query.reply() response.header.ra = 0 word = query.q.qname.label[0] desc = stardict.check(word) desc = [desc] if desc else notfound(word) # force change rtype to TXT response.rr = [] for txt in desc: # if len(txt) > 255 for part in split_len(txt, 255): response.add_answer( dnslib.RR(query.q.qname, dnslib.QTYPE.TXT, rdata=dnslib.TXT(part), ttl=5)) # no Recursion Available return response
def _txt_search(record, rr_list, auth_list, addi_list): """ Searches and adds any TXT records for the domain. :param record: Overall record for domain :param rr_list: Current record list for the domain :param auth_list: Authority list for the domain :param addi_list: Additional list for the domain """ try: txt_record = record["TXT"] ttl = int(txt_record["ttl"]) for txt in txt_record["value"]: rr_list.append(dnslib.RR(rname = record["domain"], rtype = dnslib.QTYPE.TXT, rdata = dnslib.TXT(txt), ttl = ttl)) _add_authority(record["domain"], auth_list) _add_additional(addi_list) except: pass
def add_service(self, service: ServiceConfig) -> None: type = DNSLabel(service.type) name = type.add(DNSLabel(service.name)) type_suffixed = self.hostname.add(type) name_suffixed = self.hostname.add(name) port = service.port props_list = [] for key, value in (service.properties or {}).items(): prop = key if isinstance(value, bool): if not value: prop += '=' else: prop += '=' + str(value) if len(prop) > 255: self.logger.error('Property too large to add to txt record %s', key) continue props_list.append(prop) props = ''.join( chr(len(prop)) + prop for prop in props_list ) self.add_record( type, QTYPE.PTR, dnslib.PTR(name_suffixed)) self.add_record( '_services._dns-sd._udp', QTYPE.PTR, dnslib.PTR(type_suffixed)) self.add_record( name, QTYPE.SRV, dnslib.SRV(0, 0, port, self.hostname)) self.add_record( name, QTYPE.TXT, dnslib.TXT(props))
def resolve(self, request, handler): question = request.get_q() req_name = str(question.get_qname()) # TXT = 16 reply = request.reply() pivot = req_name.rfind("_tox.") if pivot == -1: reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply name = req_name[:pivot].rstrip(".") suffix = req_name[pivot:] domain = suffix[5:].rstrip(".") if question.qtype == 16: if not name and domain in self.workable_domains: data = self.cryptocore.public_key.encode("ascii") reply.add_answer( dnslib.RR(req_name, 16, ttl=0, rdata=dnslib.TXT(data))) return reply first_try = self.try_tox3_resolve(reply, name, domain, req_name) if not first_try: return self.try_tox1_resolve(reply, name, domain, req_name) else: return first_try elif question.qtype == 2: reply.add_answer( dnslib.RR(req_name, 2, ttl=86400, rdata=dnslib.NS(self.home))) return reply else: reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply return reply
def handle(self): request = dnslib.DNSRecord.parse(self.request[0]) """ see http://www.networksorcery.com/enp/protocol/dns.htm QR flag is 1 (0 = Query, 1 = Response) AA flag is 1 (0 = Not authoritative, 1 = Is authoritative) """ reply = dnslib.DNSRecord(dnslib.DNSHeader(id=request.header.id, qr=1, aa=1), q=request.q) reply.add_answer(dnslib.RR( rname=request.q.qname, rtype=1, rdata=dnslib.A(self.DNS_LOOKUP), )) request_name = str(request.q.qname) if request_name in self.TXT_LOOKUP: for answer in self.TXT_LOOKUP[request_name]: reply.add_answer(dnslib.RR( request.q.qname, ttl=300, rtype=dnslib.QTYPE.TXT, rdata=dnslib.TXT(answer.encode("utf-8")) )) print('dnsserver served txt record for {}: {}'.format(request_name, answer)) else: print('dnsserver didn\'t find txt record for {}'.format(request_name)) # print("{} not in memory".format(request_name)) # print("memory", self.TXT_LOOKUP) # print(type(request_name)) pass self.send_data(reply.pack())
def resolve(self, request, handler): question = request.get_q() req_name = str(question.get_qname()) # TXT = 16 reply = request.reply() suffix = "._tox.{0}".format(self.ireg) if question.qtype != 16 and not req_name.endswith(self.ireg): reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply if question.qtype == 16: if req_name == suffix[1:]: reply.add_answer(dnslib.RR(req_name, 16, ttl=0, rdata=dnslib.TXT(self.cryptocore.public_key.encode("ascii")))) return reply if not req_name.endswith(suffix): reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply user_name = req_name[:req_name.rfind(suffix)] if len(user_name) > NAME_LIMIT_HARD and user_name[0] == "_": encrypted = user_name.replace(".", "")[1:] try: b = notsecure32_decode(encrypted) nonce = b[:4] + (b"\0" * 20) ck = b[4:36] payload = b[36:] name = self.cryptocore.dsrep_decode_name(ck, nonce, payload) except Exception: print("error >_<") reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply rec = self.store.get(name.decode("utf8")) if not rec: reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply base = b"v=tox3;id=" if rec.pin: r_payload = "{0}{1}{2}".format(rec.public_key, rec.pin, rec.checksum) else: r_payload = "{0}00000000{1}".format(rec.public_key, rec.checksum) msg = binascii.unhexlify(r_payload) nonce_reply = b[:4] + b"\x01" + (b"\0" * 19) ct = self.cryptocore.dsrec_encrypt_key(ck, nonce_reply, msg) key_part = notsecure32_encode(ct) reply.add_answer(dnslib.RR(req_name, 16, ttl=0, rdata=dnslib.TXT(b"".join((base, key_part))))) return reply else: rec = self.store.get(user_name) if not rec: reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply else: reply.add_answer(dnslib.RR(req_name, 16, ttl=0, rdata=dnslib.TXT(rec.record(0) .encode("utf8")))) return reply elif question.qtype == 6: self.update_soa() reply.add_answer(self.soa) return reply elif question.qtype == 2: for name in self.authority_list: reply.add_answer(dnslib.RR(req_name, 2, ttl=86400, rdata=dnslib.NS(name.encode("utf8")) )) return reply elif question.qtype == 1 and self.home_addresses: for ip in self.home_addresses: reply.add_answer(dnslib.RR(req_name, 1, ttl=3600, rdata=dnslib.A(ip))) elif question.qtype == 28 and self.home_addresses_6: for ip in self.home_addresses_6: reply.add_answer(dnslib.RR(req_name, 28, ttl=3600, rdata=dnslib.AAAA(ip))) else: reply.header.rcode = dnslib.RCODE.NXDOMAIN return reply return reply
def processRequest(self, request): reply = dnslib.DNSRecord(dnslib.DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) qname = request.q.qname qn = str(qname) qtype = request.q.qtype qt = dnslib.QTYPE[qtype] if qn == self.D or qn.endswith('.' + self.D): for name, rrs in self.records.items(): if name == qn: for rdata in rrs: rqt = rdata.__class__.__name__ if qt in ['*', rqt]: reply.add_answer( dnslib.RR(rname=qname, rtype=getattr(dnslib.QTYPE, rqt), rclass=1, ttl=self.TTL, rdata=rdata)) for rdata in self.ns_records: reply.add_ar( dnslib.RR(rname=self.D, rtype=dnslib.QTYPE.NS, rclass=1, ttl=self.TTL, rdata=rdata)) reply.add_auth( dnslib.RR(rname=self.D, rtype=dnslib.QTYPE.SOA, rclass=1, ttl=self.TTL, rdata=self.soa_record)) for question in request.questions: if (question.qtype == dnslib.QTYPE.TXT): #only process TXT record requests content = str(question.qname)[:-1] if content.endswith(self.D[:-1]): content = content[:-len(self.D[:-1]) - 1] key = content[:4] if key in self.fIP: content = str(content[4:]) self.fIP[key][3] += content self.fIP[key][1] -= len(content) #print(key, content,len(content),self.fIP[key][1] ) #print("Left: "+str(self.fIP[sIP][1])) self.progressBar( self.fIP[key][1], self.fIP[key][4], "Receiving '" + self.fIP[key][0] + "' with index " + key) reply.add_answer( dnslib.RR(rname=qname, rtype=question.qtype, rclass=1, ttl=self.TTL, rdata=dnslib.TXT(content))) #reply.add_answer(dnslib.RR(rname=qname, rtype=question.qtype, rclass=1, ttl=self.TTL, rdata=dnslib.TXT("OK"))) if (self.fIP[key][1] == 0): #we have received the entire file. Time to write it. content_decoded = base64.standard_b64decode( self.fIP[key][3]) with open(self.fIP[key][0], 'wb') as newfile: newfile.write(content_decoded) hashedWord = md5(content_decoded).hexdigest() if (self.fIP[key][2] == hashedWord): print("\nFile successfully received") reply.add_answer( dnslib.RR(rname=qname, rtype=question.qtype, rclass=1, ttl=self.TTL, rdata=dnslib.TXT("OK"))) else: print("\nFile received but failed hash:") reply.add_answer( dnslib.RR(rname=qname, rtype=question.qtype, rclass=1, ttl=self.TTL, rdata=dnslib.TXT("FAIL HASH"))) del self.fIP[key] else: # new connection. we expect a file name print("New file:", content) parts = content.split("|") if (len(parts) == 3): #we have valid request print("new file upload: ", content) self.fIP[parts[2][:4]] = [ os.path.basename(parts[0]), int(parts[1]), parts[2], "", int(parts[1]) ] reply.add_answer( dnslib.RR(rname=qname, rtype=question.qtype, rclass=1, ttl=self.TTL, rdata=dnslib.TXT("OK"))) else: reply.add_answer( dnslib.RR(rname=qname, rtype=question.qtype, rclass=1, ttl=self.TTL, rdata=dnslib.A(self.IP))) #print("responding:",reply) return reply.pack()
def resolve(self, request, handler): reply = request.reply() if sys.version_info[0] > 2: labelsNormalized = [ item.decode(errors='replace').lower().strip() for item in request.q.qname.label ] else: labelsNormalized = [ item.decode().lower().strip() for item in request.q.qname.label ] type, label, position = MatchLabel(self.labels, labelsNormalized) replyNXDOMAIN = False rcode = None if type == None: replyNXDOMAIN = True elif type == TYPE_PAYLOAD: if request.q.qtype != dnslib.QTYPE.TXT and request.q.qtype != dnslib.QTYPE.NULL: replyNXDOMAIN = True elif not (len(labelsNormalized) >= 3 and labelsNormalized[0] in self.payloads.keys()): replyNXDOMAIN = True else: label = labelsNormalized[0] try: index = 0 encodingIndex = 1 index = int(labelsNormalized[1]) encodingIndex = 2 except: pass encoding = self.payloads[label][PAYLOAD][ENCODING] if encoding == ENCODING_DYNAMIC: if labelsNormalized[encodingIndex] in [ ENCODING_BASE64, ENCODING_HEX ]: encoding = labelsNormalized[encodingIndex] else: encoding = ENCODING_NONE if not encoding in self.payloads[label][DATA]: if encoding == ENCODING_BASE64: self.payloads[label][DATA][ ENCODING_BASE64] = binascii.b2a_base64( self.payloads[label][DATA] [ENCODING_NONE]).strip() elif encoding == ENCODING_HEX: self.payloads[label][DATA][ ENCODING_HEX] = binascii.b2a_hex( self.payloads[label][DATA] [ENCODING_NONE]).strip() data = self.payloads[label][DATA][encoding] if index > len(data) / (self.maxSizeString * self.maxCountStrings): replyNXDOMAIN = True else: if handler.protocol == 'tcp' or not self.args.tcp: dnsStrings = [ data[(index * self.maxCountStrings + iter) * self.maxSizeString: (index * self.maxCountStrings + iter + 1) * self.maxSizeString] for iter in range(self.maxCountStrings) ] dnsStrings = [ dnsString for dnsString in dnsStrings if len(dnsString) != 0 ] if request.q.qtype == dnslib.QTYPE.TXT: reply.add_answer( dnslib.RR(request.q.qname, dnslib.QTYPE.TXT, ttl=self.ttl, rdata=dnslib.TXT(dnsStrings))) elif request.q.qtype == dnslib.QTYPE.NULL: reply.add_answer( dnslib.RR(request.q.qname, dnslib.QTYPE.NULL, ttl=self.ttl, rdata=NULL(dnsStrings))) else: raise Exception('DNS payload: type unknown') else: reply.header.tc = True elif type == TYPE_EXFILTRATION: if request.q.qtype != dnslib.QTYPE.A: replyNXDOMAIN = True elif not (len(labelsNormalized) >= 4 and label in self.exfiltrations.keys()): replyNXDOMAIN = True else: hexdata = ''.join(labelsNormalized[0:position]) try: data = '' data = binascii.a2b_hex(hexdata) except: pass result = Unpack('>HI', data) if result != []: filenumber, filesize, data = result filename = '%s-%05d' % (label, filenumber) if not filename in self.exfiltrations[label][FILES]: try: with open(filename, 'wb') as filehandle: filehandle.write(b'\x00' * filesize) filehandle = open(filename, 'r+b') filemmap = mmap.mmap(filehandle.fileno(), filesize) self.exfiltrations[label][FILES][filename] = { FILEHANDLE: filehandle, FILEMMAP: filemmap } except: pass if filesize == 0: if filename in self.exfiltrations[label][FILES]: try: self.exfiltrations[label][FILES][filename][ FILEMMAP].close() self.exfiltrations[label][FILES][filename][ FILEMMAP] = None except: pass try: self.exfiltrations[label][FILES][filename][ FILEHANDLE].close() self.exfiltrations[label][FILES][filename][ FILEHANDLE] = None except: pass else: result = Unpack('>IB', data) if result != []: fileposition, chuncksize, data = result if chuncksize == len( data ) and filename in self.exfiltrations[label][FILES]: try: self.exfiltrations[label][FILES][filename][ FILEMMAP][fileposition:fileposition + chuncksize] = data except: pass if self.exfiltrations[label][ANSWER] == '': replyNXDOMAIN = True else: qname = request.q.qname for rr in dnslib.RR.fromZone( self.exfiltrations[label][ANSWER]): a = copy.copy(rr) a.rname = qname reply.add_answer(a) elif type == TYPE_TRACK: if LOGGING in self.tracks[label]: with open(self.tracks[label][LOGGING], 'a') as f: print('%s %s:%d %d %s' % (FormatTimeUTC(), handler.client_address[0], handler.client_address[1], position, '.'.join(labelsNormalized).encode('utf8').decode()), file=f) if request.q.qtype != dnslib.QTYPE.A: #a# handle AAAA too replyNXDOMAIN = True elif not label in self.tracks.keys(): replyNXDOMAIN = True elif position == 0: replyNXDOMAIN = True else: if self.tracks[label][ANSWER] == '': replyNXDOMAIN = True else: qname = request.q.qname for rr in dnslib.RR.fromZone(self.tracks[label][ANSWER]): a = copy.copy(rr) a.rname = qname reply.add_answer(a) elif type == TYPE_RCODE: if position != 1: replyNXDOMAIN = True elif not label in self.rcodes.keys(): replyNXDOMAIN = True else: try: rcode = abs(ParseInteger(labelsNormalized[0])) % 0x100 except: replyNXDOMAIN = True elif type == TYPE_WILDCARD: if LOGGING in self.wildcards[label]: with open(self.wildcards[label][LOGGING], 'a') as f: print('%s %s:%d %d %s' % (FormatTimeUTC(), handler.client_address[0], handler.client_address[1], position, '.'.join(labelsNormalized).encode('utf8').decode()), file=f) if request.q.qtype != dnslib.QTYPE.A: #a# handle AAAA too replyNXDOMAIN = True elif not label in self.wildcards.keys(): replyNXDOMAIN = True elif position == 0: replyNXDOMAIN = True else: qname = request.q.qname zoneWildcard = ParseWildcardRequest( labelsNormalized[:position]) if zoneWildcard == None: replyNXDOMAIN = True else: for rr in dnslib.RR.fromZone(zoneWildcard): a = copy.copy(rr) a.rname = qname reply.add_answer(a) elif type == TYPE_RESOLVE: if position != 0: replyNXDOMAIN = True else: if LOGGING in self.resolves[label]: with open(self.resolves[label][LOGGING], 'a') as f: print('%s %s:%d %d %s' % (FormatTimeUTC(), handler.client_address[0], handler.client_address[1], position, '.'.join( labelsNormalized).encode('utf8').decode()), file=f) if request.q.qtype == dnslib.QTYPE.A: qname = request.q.qname answer = self.resolves[label][ANSWER][self.resolves[label] [INDEX]] self.resolves[label][INDEX] = ( self.resolves[label][INDEX] + 1) % len( self.resolves[label][ANSWER]) for rr in dnslib.RR.fromZone(answer): a = copy.copy(rr) a.rname = qname reply.add_answer(a) else: replyNXDOMAIN = True else: replyNXDOMAIN = True if replyNXDOMAIN: reply.header.rcode = dnslib.RCODE.NXDOMAIN if rcode != None: reply.header.rcode = rcode return reply
def dns_resolve(self, query, tcp): """ Resolves DNS request from one client at the time. Encodes its actual data and forms DNS response from it. """ request = dns.DNSRecord.parse(query) reply = request.reply() domain = request.q.get_qname() qtype = request.q.qtype data = exf.domain_decode(str(domain), base64.urlsafe_b64decode) # If encryption key is present - decode it for futher data decryption if (len(request.questions) > 1): enc_domain = str(request.questions[1].get_qname()) enc_key = exf.domain_decode(enc_domain, base64.urlsafe_b64decode) # Descramble key enc_key = exf.scramble(enc_key, (4, 12), True) # Check if the key is scramble offset if len(enc_key) < 3: enc_key = tuple(enc_key) data = exf.scramble(data, enc_key, True) # Or AES decryption key else: enc_key = enc_key.decode() data = exf.aes_decrypt(data, enc_key) # reply.add_question(request.questions[1]) if DEBUG: print_with_time("***", f"DNS QTYPE is {qtype}") print_with_time("***", f"Original data length {len(data)} bytes") print_with_time("***", f"{data[:24]}...") data = base64.b64encode(data) core_domain = deepcopy(domain) # Get TLD domain from original object core_domain.label = domain.label[-2:] if (qtype == dns.QTYPE.A): data = exf.ip_encode(data, False) elif (qtype == dns.QTYPE.AAAA): data = exf.ip_encode(data, True) elif (qtype == dns.QTYPE.TXT): data = [dns.TXT(data)] elif (qtype == 10): # NULL type data = [dns.RD(data)] else: data = exf.domain_encode(data, str(core_domain), base64.urlsafe_b64encode) if (qtype == dns.QTYPE.CNAME): data = [dns.CNAME(data)] elif (qtype == dns.QTYPE.MX): data = [dns.MX(data)] elif (qtype == dns.QTYPE.NS): data = [dns.NS(data)] for rd in data: reply.add_answer(dns.RR(str(domain), rtype=qtype, rdata=rd)) raw_reply = reply.pack() # Truncate large (> 512 bytes) data for UDP payload if (len(raw_reply) > exf.MAX_DNS_LEN and not tcp): print_with_time("DNS", f"Response message is big! Truncate it...") reply.header.set_tc(1) raw_reply = reply.pack()[:exf.MAX_DNS_LEN] print_with_time("DNS", f"Sending back the request in size {len(raw_reply)} bytes\n") return raw_reply
def StartDNSListener(self): # Setup a UDP server listening on port UDP 53 udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udps.bind(('0.0.0.0', 53)) try: numberOfChunks = 0 chunkIndex = 0 fileData = '' domainName = tasks.define_dns_domain.dnsDomainName tasks.send_command.send_cmd = "OK" while True: data, addr = udps.recvfrom(1024) request = dnslib.DNSRecord.parse(data) if request.q.qtype == 16: # Get the query qname qname = str(request.q.qname) if qname.startswith("checker."): checkerDetails = qname.split(".") # DNS Agent Isolation if checkerDetails[ 1] == tasks.agent_iso_class.unique_agent_name: if len(tasks.send_command.send_cmd) > 255: print("Task lengh is more than 255 characters.") print( "Functionality added in TODO list for future release." ) tasks.send_command.send_cmd = "OK" else: xorkey = 'j' * len(tasks.send_command.send_cmd) encrypt_cmd = encrypt.Encryption.xor_crypt_string( self, tasks.send_command.send_cmd, xorkey, True, False) reply = dnslib.DNSRecord(dnslib.DNSHeader( id=request.header.id, qr=1, aa=1, ra=1), q=request.q) reply.add_answer( dnslib.RR(request.q.qname, dnslib.QTYPE.TXT, rdata=dnslib.TXT(encrypt_cmd))) udps.sendto(reply.pack(), addr) tasks.send_command.send_cmd = "OK" else: reply = dnslib.DNSRecord(dnslib.DNSHeader( id=request.header.id, qr=1, aa=1, ra=1), q=request.q) reply.add_answer( dnslib.RR(request.q.qname, dnslib.QTYPE.TXT, rdata=dnslib.TXT("OK"))) udps.sendto(reply.pack(), addr) elif qname.startswith("agent."): agentDetails = qname.split(".") agentChunk = encrypt.Encryption.fromBase64URL( self, agentDetails[1]) numberOfChunks = int(agentChunk) # Reset all variables fileData = '' chunkIndex = 0 # send OK in order to receive the data reply = dnslib.DNSRecord(dnslib.DNSHeader( id=request.header.id, qr=1, aa=1, ra=1), q=request.q) reply.add_answer( dnslib.RR(request.q.qname, dnslib.QTYPE.TXT, rdata=dnslib.TXT("OK"))) udps.sendto(reply.pack(), addr) elif qname.startswith("results."): resultsDetails = qname.split(".") resultsChunk = encrypt.Encryption.fromBase64URL( self, resultsDetails[1]) numberOfChunks = int(resultsChunk) # Reset all variables fileData = '' chunkIndex = 0 # send OK in order to receive the data reply = dnslib.DNSRecord(dnslib.DNSHeader( id=request.header.id, qr=1, aa=1, ra=1), q=request.q) reply.add_answer( dnslib.RR(request.q.qname, dnslib.QTYPE.TXT, rdata=dnslib.TXT("OK"))) udps.sendto(reply.pack(), addr) else: try: msg = qname[0:-(len(domainName) + 2)] chunkNumber, rawData = msg.split('.', 1) except: print("Failed to split the message.") if (int(chunkNumber) == chunkIndex): fileData += rawData.replace('.', '') chunkIndex += 1 # Always acknowledge the received chunk (whether or not it was already received) reply = dnslib.DNSRecord(dnslib.DNSHeader( id=request.header.id, qr=1, aa=1, ra=1), q=request.q) reply.add_answer( dnslib.RR(request.q.qname, dnslib.QTYPE.TXT, rdata=dnslib.TXT(chunkNumber))) udps.sendto(reply.pack(), addr) # Have we received all chunks of data ? if chunkIndex == numberOfChunks: try: if agentDetails[0] == "agent": results = encrypt.Encryption.fromBase64URL( self, fileData) decodeData = results.decode() realData = str(decodeData) xorkey = 'j' * len(realData) data = encrypt.Encryption.xor_crypt_string( self, realData, xorkey, False, True) agentName = data.split(" ") print("DNS Agent " + agentName[0] + " Arrived!\n") # clean agentdetails variable agentDetails[0] = "clean" handlers.listAllAgents.append(data) else: results = encrypt.Encryption.fromBase64URL( self, fileData) decodeData = results.decode() realData = str(decodeData) xorkey = 'j' * len(realData) data = encrypt.Encryption.xor_crypt_string( self, realData, xorkey, False, True) if "DownloadingFileRand1me3" in data: AgentFolder = './Agents/' + tasks.agent_iso_class.unique_agent_name os.chdir(os.path.dirname(__file__)) if not os.path.exists(AgentFolder + '/Downloads'): os.makedirs(AgentFolder + '/Downloads') split_data = data.split(" ") tempFile = "ignoremeFile.txt" # https://stackoverflow.com/questions/22216076/unicodedecodeerror-utf8-codec-cant-decode-byte-0xa5-in-position-0-invalid-s fullPath = AgentFolder + '/Downloads/' + tempFile orgFile = AgentFolder + '/Downloads/' + split_data[ 1] try: with open(fullPath, 'w') as out_file: out_file.write(split_data[2]) out_file.close() Convertb64_to_orgFile = subprocess.Popen( "cat " + fullPath + " | base64 -d > " + orgFile, stdin=subprocess.PIPE, shell=True) Convertb64_to_orgFile.communicate() print( "File " + split_data[1] + " Downloaded Successfully under " + orgFile) except: print("Failed to download the file!") elif "This1sScreenSh0t" in data: AgentFolder = './Agents/' + tasks.agent_iso_class.unique_agent_name os.chdir(os.path.dirname(__file__)) if not os.path.exists(AgentFolder + '/Screenshots'): os.makedirs(AgentFolder + '/Screenshots') split_data = data.split(" ") imgPath = AgentFolder + '/Screenshots/' try: with open( imgPath + tasks.agent_iso_class. unique_agent_name + str(datetime.now().strftime( '-%d%m%Y-%H.%M.%S')) + '.png', 'wb') as out_image: out_image.write( base64.b64decode( split_data[1])) out_image.close() print("Screenshot save under " + imgPath) except: print("Screenshot failed") else: print(data) except IOError: print("[!] Could not read") # Query type is not TXT else: reply = dnslib.DNSRecord(dnslib.DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) udps.sendto(reply.pack(), addr) except KeyboardInterrupt: print("[!] Stopping DNS Server") udps.close()
def py3dns(serverip='', serverport=0): class DNSify(str): def __getattr__(self, item): return DNSify(item + '.' + self) def get_lan_ip4(forcelocalhost=False): if forcelocalhost: return '127.0.0.1' s = dnslib.socket.socket(dnslib.socket.AF_INET, dnslib.socket.SOCK_DGRAM) try: s.connect(('10.255.255.255', 0)) IP = s.getsockname()[0] except: IP = '127.0.0.1' finally: s.close() return IP def is_domain_blacklisted(sqname, domain_blacklist): for test_domain in domain_blacklist: if test_domain in sqname: return True return False # Init server settings killcommand = 'stop.py3dns.now' serve_forever = True udp_buffer_size = 1024 server_name = dnslib.socket.getfqdn() server_ip = get_lan_ip4() if serverip: server_ip = serverip reverse_server_ip = '.'.join(reversed( server_ip.split('.'))) + '.in-addr.arpa' server_port = 53 if serverport: server_port = int(serverport) server_protocol = 'UDP' public_dns_resolvers = [ '91.239.100.100', '89.233.43.71', '8.8.8.8', '8.8.4.4' ] # Init simple host cache host_cache = {} host_cache[server_ip] = server_name # Init blacklists use_blacklists = True domain_blacklist = make_domain_blacklist() ipaddr_blacklist = make_ipaddr_blacklist() rpz_domain = DNSify('getthefuckaway.net') rpz_ip4 = '10.20.30.40' rpz_ip6 = '10:20:30:40:50:60:70:80' # Init UDP socket server udpsrv = dnslib.socket.socket(dnslib.socket.AF_INET, dnslib.socket.SOCK_DGRAM) udpsrv.bind((server_ip, server_port)) udpsrv.setblocking(False) # Init external resolvers external_resolver = dns.resolver.Resolver() external_resolver_cache = dns.resolver.Cache(cleaning_interval=600.0) external_resolver.cache = external_resolver_cache external_resolver.nameservers = public_dns_resolvers external_resolver.retry_servfail = False external_resolver.port = 53 ##external_resolver.timeout = 1.0 ##external_resolver.lifetime = 2.0 # Timestamp UTC now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f') # App Header print('+' + ('-' * 71)) print('| PY3DNS v/1.0 by BikerDroid') print('+' + ('-' * 71)) print('| Server :', server_name) print('| Address :', server_ip) print('| Port Used :', server_port) print('| Protocol :', server_protocol) print('| Recv Size :', udp_buffer_size, 'bytes') print('| Solvers :', str(public_dns_resolvers).strip("[]").replace("'", "")) print('+' + ('-' * 71)) print('| Stop PY3DNS by sending "nslookup ' + killcommand + ' ' + server_ip + '"') print('+' + ('-' * 71)) print(now, ': Ready to serve...') # Main Loop while serve_forever: # Clear vars sres = sip4 = sip6 = smx = scname = sns = stxt = sptr = ssoa = sany = hostip = '' # Main: Get client request, add hostip and host name to host_cache try: data, addr = udpsrv.recvfrom(udp_buffer_size) hostip = str(addr[0]) if not hostip in host_cache: host_cache[hostip] = dnslib.socket.getfqdn( str(dnslib.socket.gethostbyaddr(hostip)[0])) now = datetime.datetime.utcnow().strftime( '%Y-%m-%d %H:%M:%S.%f') # UTC except: continue # Client request -> id, qname (domain), qtype (A,AAAA,MX etc) request = dnslib.DNSRecord.parse(data) qid = request.header.id qname = request.q.qname qtype = request.q.qtype slabel = str(qname.label) sqname = str(qname) sqtype = str(dnslib.QTYPE[qtype]) # Rem this line if rpz_domain is to overwrite # blacklisted domains with their real names. sdomain = sqname # Dirty trick to shut down server from commandline: # Syntax : nslookup stop.dns.srv <server_ip> # Example: nslookup stop.dns.srv 127.0.0.1 # Must be before external_resolver.query() if sqname.rstrip('.') == killcommand: serve_forever = False continue # Dirty Reverse Lookup of local server # Allows requesting client to get server_name if qtype == dnslib.QTYPE.PTR: if sqname.rstrip('.') == reverse_server_ip: reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid, qr=1, aa=1, ra=1, rcode=0), q=dnslib.DNSQuestion(sqname, qtype)).reply() reply.add_answer( dnslib.RR(sqname, dnslib.QTYPE.PTR, rdata=dnslib.PTR(server_name), ttl=3600)) udpsrv.sendto(reply.pack(), addr) print(now, ':', sqname, '|', sqtype, '=', qtype, '|', server_name, '|', hostip, '=', host_cache[hostip]) continue # Get DNS record from public_dns_resolvers. # This section can be changed to serve from # own database, stationary files or similar. try: if not sqname.rstrip('.') in domain_blacklist: external_resolver_result = external_resolver.query( sqname.rstrip('.'), sqtype) found = True except: print(now, '> qtype', sqtype, '(' + str(qtype) + ') was not found for', sqname) external_resolver_result = [] sres = sip4 = sip6 = '' found = False if not found: # Create DNSRecord Header reply: rcode = 5 (Query Refused). See RFC2136 for rcode's. reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid, qr=1, aa=1, ra=1, rcode=5), q=dnslib.DNSQuestion(sdomain, qtype)).reply() else: # Create DNSRecord Header reply: rcode = 0 (No Error) reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid, qr=1, aa=1, ra=1, rcode=0), q=dnslib.DNSQuestion(sdomain, qtype)).reply() # Add A record answer for domain and IP # Filter blacklisted IP4/6 addresses. if qtype == dnslib.QTYPE.A: if is_domain_blacklisted( sqname.rstrip('.'), domain_blacklist): # Simple domain blacklist check sres = sip4 = rpz_ip4 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.A, rdata=dnslib.A(sip4), ttl=60)) else: for data in external_resolver_result: sres = sip4 = str(data).strip() if sip4: if sip4 in ipaddr_blacklist: # Simple IP (4+6) blacklist check sres = sip4 = rpz_ip4 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.A, rdata=dnslib.A(sip4), ttl=60)) # Add AAAA record answer for domain and IP # Filter blacklisted IP4/6 addresses. elif qtype == dnslib.QTYPE.AAAA: if is_domain_blacklisted( sqname.rstrip('.'), domain_blacklist): # Simple domain blacklist check sres = sip6 = rpz_ip6 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.AAAA, rdata=dnslib.AAAA(sip6), ttl=60)) else: for data in external_resolver_result: sres = sip6 = str(data).strip() if sip6: if sip6 in ipaddr_blacklist: # Simple IP (4+6) blacklist check sres = sip6 = rpz_ip6 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.AAAA, rdata=dnslib.AAAA(sip6), ttl=60)) # Add NS record answer for domain elif qtype == dnslib.QTYPE.NS: for data in external_resolver_result: sres = sns = str(data).strip() if sns: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.NS, rdata=dnslib.NS(sns), ttl=60)) # Add MX record answer for domain and IP elif qtype == dnslib.QTYPE.MX: for data in external_resolver_result: sres = smx = str(data).strip() if smx: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.MX, rdata=dnslib.MX(smx), ttl=60)) # Add CNAME record answer for domain elif qtype == dnslib.QTYPE.CNAME: for data in external_resolver_result: sres = scname = str(data).strip() if scname: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.CNAME, rdata=dnslib.CNAME(scname), ttl=60)) # Add TXT record answer for domain elif qtype == dnslib.QTYPE.TXT: for data in external_resolver_result: sres = stxt = str(data).strip() if stxt: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.TXT, rdata=dnslib.TXT(stxt), ttl=60)) # Add PTR record answer for domain elif qtype == dnslib.QTYPE.PTR: for data in external_resolver_result: sres = sptr = str(data).strip() if sptr: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.PTR, rdata=dnslib.PTR(sptr), ttl=60)) # Add ANY record answer for domain elif qtype == dnslib.QTYPE.ANY: for data in external_resolver_result: sres = sany = str(data).strip() if sany: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.ANY, rdata=dnslib.ANY(sany), ttl=60)) # Add SOA record answer for domain elif qtype == dnslib.QTYPE.SOA: for data in external_resolver_result: if str(data).strip(): soa_data = str(data).strip().split(' ') soa_mname = soa_data[0] soa_rname = soa_data[1] soa_serial = soa_data[2] soa_refresh = soa_data[3] soa_retry = soa_data[4] soa_expire = soa_data[5] soa_minimum = soa_data[6] soa_time = (int(soa_serial), int(soa_refresh), int(soa_retry), int(soa_expire), int(soa_minimum)) sres = soa_mname + ',' + soa_rname + ',' + soa_serial + ',' + soa_refresh + ',' + soa_retry + ',' + soa_expire + ',' + soa_minimum reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.SOA, rdata=dnslib.SOA(soa_mname, soa_rname, soa_time), ttl=60)) else: # Unknown qtype - add CNAME as answer :) reply.add_answer( dnslib.RR(qname, dnslib.QTYPE.CNAME, rdata=dnslib.CNAME(server_name), ttl=60)) # Send DNS reply to client address using UDP udpsrv.sendto(reply.pack(), addr) # Show status in console print(now, ':', sqname, '|', sqtype, '=', qtype, '|', sres, '|', hostip, '=', host_cache[hostip]) #,reply.pack() # Shutting down print(now, ': Shutting down...') udpsrv.shutdown(0) print(now, ': Done.')