Trying to parse DNS responses with Scapy (see function below). My issue is all of the answers in the rdata[] field are not showing. When I do a packet capture with Wireshark, I see multiple answers in the rdata[] field, there are usually two or three answers in a single response packet for those unfamiliar with DNS.
I am only returned with one of the answers (the first). I have tried using sr() instead of sr1() and have also tried adding multi=True as a parameter when sending the packet but neither of these work.
Any ideas?
def send_query_recursion(resolver, target):
dns_req = IP(dst=f'{resolver}')/UDP(dport=53)/DNS(qr=0, rd=1, qd=DNSQR(qname=f'{target}'))
answer = sr1(dns_req, verbose=1)
for received in answer:
if received.haslayer(DNS):
for x in received:
print(str(x[DNS].id))
print("rrname: " + str(x[DNSRR].rrname))
print("Type: " + str(x[DNSRR].type))
if str(x[DNSRR].rclass) == "1":
print("Class: " + str(x[DNSRR].rclass) + " IN")
print("TTL: " + str(x[DNSRR].ttl))
print("Resource Data Length: " + str(x[DNSRR].rdlen))
print("Resource Data: " + str(x[DNSRR].rdata[:-1]))
I have the same issue as you do. I could not resolve it using scapy, so I have used dpkt package to parse the answer of the DNS responses as follow (python 3):
with open('your_pcap.pcap', 'rb') as f:
pcap = dpkt.pcap.Reader(f)
for timestamp, buf in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf)
except:
continue
if eth.type != 2048:
continue
try:
ip = eth.data
except:
continue
if ip.p != 17:
continue
#filter on UDP assigned ports for DNS
try:
udp = ip.data
except:
continue
if udp.sport != 53 and udp.dport != 53:
continue
#make the dns object out of the udp data and
#check for it being a RR (answer) and for opcode QUERY
try:
dns = dpkt.dns.DNS(udp.data)
except:
continue
if dns.qr != dpkt.dns.DNS_R:
continue
if dns.opcode != dpkt.dns.DNS_QUERY:
continue
if dns.rcode != dpkt.dns.DNS_RCODE_NOERR:
continue
if len(dns.an) < 1:
continue
for qname in dns.qd:
print("The DNS response packet has ", len(dns.an), " answers")
print("The answers (in a list) are: ", dns.an)
You can find additional information on parsing DNS using dpkt on the following pages:
https://dpkt.readthedocs.io/en/latest/_modules/dpkt/dns.html
https://mmishou.wordpress.com/2010/04/13/passive-dns-mining-from-pcap-with-dpkt-python/
Related
Alright so for a school assignment me and my classmate decided to make a macfiler/ids script in python3. We got pretty far but we are stuck at 1 thing. We need the scan to go on infinite and break when a new connection in the network is found and continue when the new connection is blocked or not. Could someone help us in the right direction?
from scapy.all import ARP, Ether, srp
import os
import netifaces
#Ask for the subnet mask and calculate it to CIDR notation
netmask = input("What is the subnetmask of your network? (xxx.xxx.xxx.xxx:)")
CIDR = sum(bin(int(x)).count('1') for x in netmask.split('.'))
#Find the defaultgateway ip
gateways = netifaces.gateways()
default_gateway = gateways['default'][netifaces.AF_INET][0]
#Conversions to make the code easier to read
target_ip = default_gateway + "/" + str(CIDR)
arp = ARP(pdst=target_ip)
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
packet = ether/arp
result = srp(packet, timeout=3, verbose=0)[0]
#Empty list for the found clients in the network
clients = []
#Empty list for the blocked addresses
blockedMac = []
#This needs an infinite loop and break when a new connection is in the network is found
for sent, received in result:
clients.append({'ip': received.psrc, 'mac': received.hwsrc})
#if new connection is found do this
print("Available devices in the network:\n")
print("IP" + " "*18+"MAC")
for client in clients:
print("{:16} {}".format(client['ip'], client['mac']))
blockedConnectionStatus = input("\nWould you like to block a connection? Y/n:")
if blockedConnectionStatus == 'Y' or blockedConnectionStatus == 'y':
macAdress = input("\nEnter the MAC Address to block: \n")
#Open rules.v4 and read if the mac address is allready blocked
with open("/etc/iptables/rules.v4", "r") as f:
data = f.read()
if macAdress.upper() in data:
blockedMac.append(macAdress) #Append the blocked mac address to list blockedMac
print("Allready blocked!")
else:
print(macAdress + " is now being blocked!")
os.system("iptables -A INPUT -p ALL -m mac --mac-source " + macAdress + " -j DROP")
os.system("iptables-save > /etc/iptables/rules.v4")
blockedMac.append(macAdress) #Append the blocked mac address to list blockedMac
#Go back to infinite loop```
From my understanding, you want a while loop that only runs while something is true you could do something like this
loop = 'True'
while loop == 'True':
print('Worked!')
loop = 'False'
Let me know if it is not.
I am connecting to a pre-configured server that serves four different file formats with different sizes. Each file is appended with the file size...
Example: lighthouse.jpg
561276ÿØÿà JFIF ` ` ÿî Adobe
The "561276" is the file size and needs to be pruned before saving the file.
Example: randomText.txt
45711111111111111111111111111111111111111111111111111111111
222222222222222222222222222222222222222222222222222222222
33333333333333333333333333333333333333333333333333
44444444444444444444444444444444444444444444444444444444
66666666666666666666
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cvccccccccccccccccccccccccccccccccccccccccccccccc
ddddddddddddddddddddddddddddddddddddddddddddddddddd
The "457" is the file size and needs to be pruned before saving the file.
Some files have a size that is only 3-digits long. Some have a file size that is 6-digits long (as seen here). I want to make my code size-agnostic; regardless of how many digits is in the size.
I've tried using:
while len(buf) < 4:
buf += sock.recv(4 - len(buf))
size = struct.unpack('!i', buf)
but this only prunes the first four digits.
AND
I've tried using
len = sock.recv(4)
data = sock.recv(len)
but once again... only prunes the first four digits
Here is what I have so far:
def get_size():
buf = ''
while len(buf) < 4:
buf += sock.recv(4 - len(buf))
size = struct.unpack('!i', buf)
print "[*] Receiving %s bytes" % size
def download_pic():
size = get_size()
fname = 'tst.jpg'
with open(fname, 'wb') as img:
while True:
data = sock.recv(1024)
if not data:
break
img.write(data)
print '[*] {0} received!'.format(fname)
def main():
doconnectionstuffandprinttoconsole() #establishes connection
answer = input("[>] Your Selection: ")
sock.send(str(answer))
if answer == 2:
download_pic()
sock.close()
Any help in pruning the size from the file(s) would be greatly appreciated!
Jason Harper's suggestion (#jasonharper) got me thinking. When I ran repr(data) on the chunks from randomText.txt, I saw that it had a break in it that looked like...
'457''1111111111111111111111...
The server was attempting to send two different chunks (one at at time) but it kept getting merged into one chunk. So, I increased my sock.recv(64) up to sock.recv(256). And for some reason, it send two chunks!
'457'
'111111111...' [truncated]
NEW AND IMPROVED CODE!
import socket
import sys
import struct
import os
user1 = {'user1': 91827364}
user2 = {'user2': 19283746}
user3 = {'user3': 46372819}
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('127.0.0.1', 2058))
def print_data():
data_rcv = sock.recv(1024)
print "[-] {0}".format(data_rcv)
def download_file(format):
fname = 'download'
fullname = fname + '.' + format
try:
with open(fullname, 'wb') as txt:
len = sock.recv(256)
while True:
data = sock.recv(int(len))
if not data:
break
txt.write(data)
print("[*] {0} successfully downloaded with a length of {1} characters!".format(fullname, len))
except Exception:
print("[!] Error receiving file. Please try again.")
def connect():
print("[*] Sending Length")
sock.send("5")
my_struct = struct.pack('5s i', 'user1', 91827364)
print("[*] Sending User1 Struct")
sock.send(my_struct)
print_data()
def main():
print_data()
connect()
print_data()
answer = input("[>] Your Selection: ")
sock.send(str(answer))
if answer == 2: # Option to download Lighthouse.jpg
download_file("jpg")
elif answer == 4: # Option to download randomText.txt
download_file("txt")
sock.close()
if __name__ == "__main__":
main()
MY OUTPUT
[-] Please enter credentials
[*] Sending Length
[*] Sending User1 Struct
[-] Authenticated
[-] Choose a file to retrieve from the following list (enter the number):
1. photo.png
2. Lighthouse.jpg
3. npp.6.8.5.Installer.exe
4. randomText.txt
[>] Your Selection: 2
[*] download.jpg successfully downloaded with a length of 561276 characters!
I'm developing a server monitoring utility in Python that I want to work on everything from macOS to Haiku. It's split into a client that connects to and queries multiple servers. Right now I'm testing the client on a macOS host with the server running on Debian in a Parallels VM. However, I didn't commit the new changes I made that did work to GitHub, and then made some changes that broke the whole thing. I'm only going to include the parts of my code that are relevant.
This is from the client.
def getServerInfoByName(serverName):
serverIndex = serverNames.index(serverName)
serverAddress = serverAddressList[serverIndex]
serverPort = serverPorts[serverIndex]
serverUsername = serverUsernames[serverIndex]
return serverAddress, serverPort, serverUsername
for server in serverNames:
try:
if server != None:
serverInfo = getServerInfoByName(server)
exec(server + "Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)")
exec(server + "Socket.connect(('" + serverInfo[0] + "', " + serverInfo[1] + "))")
except ConnectionRefusedError:
print("Could not establish a connection to " + server + ".")
print(divider)
sys.exit()
def clientLoop():
sys.stdout.write(termcolors.BLUE + "-> " + termcolors.ENDC)
commandInput = input()
splitCommand = commandInput.split(' ')
whichServer = splitCommand[0]
if splitCommand[0] == "exit":
sys.exit()
# Insert new one word client commands here
elif len(splitCommand) < 2:
print("Not enough arguments")
print(divider)
clientLoop()
elif splitCommand[1] == "ssh":
serverInfo = getServerInfoByName(whichServer)
os.system("ssh " + serverInfo[2] + "#" + serverInfo[0])
print(divider)
clientLoop()
# Insert new external commands above here (if any, perhaps FTP in the
# future).
# NOTE: Must be recursive or else we'll crash with an IndexError
# TODO: Possibly just catch the exception and use that to restart the
# function
else:
whichServer = splitCommand[0]
commandToServer = splitCommand[1]
exec(whichServer + "Socket.send(commandToServer.encode('utf-8'))")
response = exec(whichServer + "Socket.recv(1024)")
print(response.decode('utf-8'))
print(divider)
clientLoop()
clientLoop()
And this is from the server.
### Start the server
try:
incomingSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
incomingSocket.bind((address, port))
except OSError:
print("The configured address is already in use.")
print("The problem should solve itself in a few seconds.")
print("Otherwise, make sure no other services are using")
print("the configured address.")
sys.exit()
incomingSocket.listen(1)
### Main loop for the server
while True:
clientSocket, clientAddress = incomingSocket.accept()
incomingCommand = clientSocket.recv(1024)
command = incomingCommand.decode('utf-8')
if command != None:
if command == "os":
clientSocket.send(osinfo[0].encode('utf-8'))
elif command == "hostname":
clientSocket.send(osinfo[1].encode('utf-8'))
elif command == "kernel":
clientSocket.send(osinfo[2].encode('utf-8'))
elif command == "arch":
clientSocket.send(osinfo[3].encode('utf-8'))
elif command == "cpu":
cpuOverall = getOverall()
cpuOverallMessage = "Overall CPU usage: " + str(cpuOverall) + "%"
clientSocket.send(cpuOverallMessage.encode('utf-8'))
elif command == "stopserver":
incomingSocket.close()
clientSocket.close()
sys.exit()
else:
clientSocket.send("Invalid command".encode('utf-8'))
Any time I try to send a command to the server, the client crashes with AttributeError: 'NoneType' object has no attribute 'decode' as soon as it tries to decode the response from the server. Eventually I want to encrypt the sockets with AES but I can't do that if it doesn't even work in plain text.
exec does not return anything. You should not generate variable names with exec but use dictionaries to store the sockets.
servers = {}
for name, address, port, username in zip(serverNames, serverAddressList, serverPorts, serverUsernames):
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.connect((address, port))
servers[name] = server, address, port, username
except ConnectionRefusedError:
print("Could not establish a connection to {}.".format(name))
print(divider)
sys.exit()
def client_loop():
while True:
sys.stdout.write("{}-> {}".format(termcolors.BLUE,termcolors.ENDC))
command = input().split()
which_server = command[0]
if which_server == "exit":
break
elif len(command) < 2:
print("Not enough arguments")
print(divider)
elif command[1] == "ssh":
_, address, _, username = servers[which_server]
os.system("ssh {}#{}".format(username, address))
print(divider)
else:
server = servers[which_server][0]
server.sendall(command[1].encode('utf-8'))
response = server.recv(1024)
print(response.decode('utf-8'))
print(divider)
client_loop()
I'm creating a log server, that write incoming and outgoing connections (any type) to a TXT file . everything is working fine and here is my code :
from scapy.all import *
import datetime
from threading import Thread
from Queue import Queue, Empty
from scapy.layers.dns import DNS, DNSQR
firstime = 0
times = time.time()+86400
def print_summary(pkt):
global firstime
global times
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
else:
ip_src="Null"
ip_dst="Null"
mac_src="Null"
mac_dst="Null"
if TCP in pkt:
tcp_sport=pkt[TCP].sport
tcp_dport=pkt[TCP].dport
else:
tcp_sport="Null"
tcp_dport="Null"
if DNSQR in pkt:
dns = pkt.qd.qname
else:
dns = "NULL"
if Ether in pkt:
mac_src = pkt[Ether].src
mac_dst = pkt[Ether].dst
else:
mac_src = "Null"
mac_dst = "Null"
Clog = " IP src: " + str(ip_src) +" ,MAC src: " + str(mac_src) + " , IP dst: " + str(ip_dst) +" ,MAC dst: "+str(mac_dst)+" ,TCP sport: " + str(tcp_sport) + ",TCP dport: " + str(tcp_dport) +", Time: " + str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(pkt.time))) + " Dns: "+dns
if(times > pkt.time):
if(firstime == 0):
f = open("/root/Desktop/LOG-SERVER/"+time.strftime('%Y-%m-%d %H:%M:', time.localtime(time.time()))+".txt",'a')
f.write(Clog+"\n")
f.close()
else:
f.write(Clog+"\n")
f.close()
else:
f = open("/root/Desktop/LOG-SERVER/"+time.strftime('%Y-%m-%d %H:%M:', time.localtime(time.time()))+".txt",'a')
f.write(Clog+"\n")
f.close()
times=times+86400
def startsnif():
sniff(prn=print_summary, store=0)
# you can filter with something like that
#if ( ( pkt[IP].src == "192.168.0.1") or ( pkt[IP].dst == "192.168.0.1") ):
# print("!")
#def writing(log,indexp):
#if(indexp == 0):
#f = open("/root/Desktop/LOG-SERVER/"+time.strftime('%Y-%m-%d %H:%M:', time.localtime(time.time()))+".txt",'a')
#f.write(log+"\n")
#f.close()
#else:
#f.write(log+"\n")
#f.close()
thread.start_new_thread(startsnif,());
while 1:
pass
# or it possible to filter with filter parameter...!
#sniff(filter="ip and host 192.168.0.1",prn=print_summary)
output is:
IP Src: 192.168.10.1 MAC Src: 54:55:12:FC:2D:CA IP Dst:192.168.10.15 MAC Src: 54:55:12:FC:1F:3A TCP sport: 80 TCP dport: 51233 Time:2015-12-16 13:25:11 DNS:Null(IF available DNS Name)
the problem is that the company got mikrotics, mikrotics mirror traffic through a technique called TZSP Sniff which encapsulate the packet with the IP of the router and MAC of the router IP of the destination PC MAC of the destination pc, i was searching and i couldn't find any appropriate solution but i read that you need to strip first 5 bytes of a packet.
is there a way to strip the TZSP encapsulation live(without saving PCAP), could you please explain the process because I'm new to this stuff?
please if you have any question ask I'm not very good in explaining stuff.
Thank you!
After examining the binary of the TZSP packet header it appears that TZSP strip original mac address after adding it's own, so the project was closed thank you for the help.
I am trying to reconstruct a webpage from a libpcap file from a python script. I have all the packets so the goal I guess is to have a libpcap file as input and you find all the necessary packets and somehow have a webpage file as output with all pictures and data from that page. Can anyone get me started off in the right direction. I think I will need dkpt and/or scaPY.
Update 1: Code is below! Here is the code I have come up so far with in Python. It is suppose to grab the first set of packets from a single HTTP session beginning with a packet with the SYN and ACK flags set to 1 and ends with a packet that has the FIN flag set to 1.
Assuming there is only one website visited during the packet capture does this code append all the necessary packets needed to reconstruct the visited webpage?
Assuming I have all the necessary packets how do I reconstruct the webpage?
import scaPy
pktList = list() #create a list to store the packets we want to keep
pcap = rdpcap('myCapture.pcap') #returns a packet list with every packet in the pcap
count = 0 #will store the index of the syn-ack packet in pcap
for pkt in pcap: #loops through packet list named pcap one packet at a time
count = count + 1 #increments by 1
if pkt[TCP].flags == 0x12 and pkt[TCP].sport == 80: #if it is a SYN-ACK packet session has been initiated as http
break #breaks out of the for loop
currentPkt = count #loop from here
while pcap[currentPkt].flags&0x01 != 0x01: #while the FIN bit is set to 0 keep loops stop when it is a 1
if pcap[currentPkt].sport == 80 and pcap[currentPkt].dport == pcap[count].dport and pcap[currentPkt].src == pcap[count].src and pcap[currentPkt].dst == pcap[count].dst:
#if the src, dst ports and IP's are the same as the SYN-ACK packet then the http packets belong to this session and we want to keep them
pktList.append(pcap[currentPkt])
#once the loop exits we have hit the packet with the FIN flag set and now we need to reconstruct the packets from this list.
currentPkt = currentPkt + 1
Perhaps something like tcpick -r your.pcap -wRS does the job for you.
http://tcpick.sourceforge.net/?t=1&p=OPTIONS
This python script will extract all unencrypted HTTP webpages that are in a PCAP File and output them as HTML Files. It uses scaPY to work with the individual packets (another good python module is dpkt).
from scapy.all import *
from operator import *
import sys
def sorting(pcap):
newerList = list()
#remove everything not HTTP (anything not TCP or anything TCP and not HTTP (port 80)
#count = 0 #dont need this it was for testing
for x in pcap:
if x.haslayer(TCP) and x.sport == 80 and bin(x[TCP].flags)!="0b10100":
newerList.append(x);
newerList = sorted(newerList, key=itemgetter("IP.src","TCP.dport"))
wrpcap("sorted.pcap", newerList)
return newerList
def extract(pcap,num, count):
listCounter = count
counter = 0
#print listCounter
#Exit if we have reached the end of the the list of packets
if count >= len(pcap):
sys.exit()
#Create a new file and find the packet with the payload containing the beginning HTML code and write it to file
while listCounter != len(pcap):
thisFile = "file" + str(num) + ".html"
file = open(thisFile,"a")
s = str(pcap[listCounter][TCP].payload)
#print "S is: ", s
x,y,z = s.partition("<")
s = x + y + z #before was y+z
if s.find("<html") != -1:
file.write(s)
listCounter = listCounter + 1
break
listCounter = listCounter + 1
#Continue to loop through packets and write their contents until we find the close HTML tag and
#include that packet as well
counter = listCounter
while counter != len(pcap):
s = str(pcap[counter][TCP].payload)
if s.find("</html>") != -1:
file.write(s)
file.close
break
else:
file.write(s)
counter = counter + 1
#Recursively call the function incrementing the file name by 1
#and giving it the last spot in the PCAP we were in so we continue
#at the next PCAP
extract(pcap, num+1, counter)
if __name__ == "__main__":
#Read in file from user
f = raw_input("Please enter the name of your pcap file in this directory. Example: myFile.pcap")
pcapFile = rdpcap(f)
print "Filtering Pcap File of non HTTP Packets and then sorting packets"
#Sort and Filter the PCAP
pcapFile = sorting(pcapFile)
print "Sorting Complete"
print "Extracting Data"
#Extract the Data
extract(pcapFile,1,0)
Print "Extracting Complete"