Unable to get packet parameters with Scapy - python

Not sure if this is the best way, but I'm trying to read a .pcap file using Scapy and get all DHCP6 Solicit request & Advertise response parameters and the corresponding values using the following snippet:
from scapy.all import *
packets = rdpcap('DHCPv6.cap')
for packet in packets:
if packet.haslayer(DHCP6_Advertise):
print(packet.getlayer(DHCP6_Advertise))
print(packet.getlayer(DHCP6OptClientId).show())
The output shows all the fields that can be retrieved, but I noticed some fields are missing as compared to what is shown by the Wireshark output(attached image).
Is there any other way to do the same?
DHCP6_Advertise / DHCP6OptIA_PD / DHCP6OptClientId / DHCP6OptServerId
###[ DHCP6 Client Identifier Option ]###
optcode = CLIENTID
optlen = 14
\duid \
|###[ DUID - Link-layer address plus time ]###
| type = Link-layer address plus time
| hwtype = Ethernet (10Mb)
| timeval = Fri, 02 Jan 2015 21:52:08 +0000 (1420235528)
| lladdr = 08:00:27:fe:8f:95
###[ DHCP6 Server Identifier Option ]###
optcode = SERVERID
optlen = 14
\duid \
|###[ DUID - Link-layer address plus time ]###
| type = Link-layer address plus time
| hwtype = Ethernet (10Mb)
| timeval = Thu, 01 Jan 2015 15:36:08 +0000 (1420126568)
| lladdr = 08:00:27:d4:10:bb

Related

How do I configure the protocol layer of my packets Scapy?

I am reading packets from pcap files and sending them on my network. The trouble is I keep getting invalid checksum errors. I have set the packets to have a checksum of None in the IP layer (as Scapy auto generates any missing data) however I can't seem to do it for the Protocol Layer (TCP,UDP etc). Thus the checksum errors still occur.
Example
###[ IP ]###
version = 4
ihl = 5
tos = 0x20
len = 436
id = 50116
flags =
frag = 0
ttl = 107
proto = udp
chksum = None --- Correct as Scapy will Autogen
src = 169.254.162.71
dst = 169.254.208.208
\options \
###[ UDP ]###
sport = 23616
dport = 23575
len = 416
chksum = 0x5f4a ---Incorrect Checksum
I have looked online and have found this:
pkt.payload.chksum = None
However that did not work.
pkt[Ether].src = "00:E0:4C:00:02:42"
pkt[Ether].dst = "00:E0:4C:01:08:99"
pkt[IP].src = "169.254.162.71" # i.e new_src_ip="255.255.255.255"
pkt[IP].dst = "169.254.208.208"
pkt[IP].chksum = None
pkt.payload.chksum = None
pkt.show()
Example Output
###[ Ethernet ]###
dst = 00:E0:4C:01:08:99
src = 00:E0:4C:00:02:42
type = IPv4
###[ IP ]###
version = 4
ihl = 5
tos = 0x20
len = 436
id = 50116
flags =
frag = 0
ttl = 107
proto = udp
chksum = None
src = 169.254.162.71
dst = 169.254.208.208
\options \
###[ UDP ]###
sport = 23616
dport = 23575
len = 416
chksum = 0x5f4a ---Not set to None
Do note that the file I'm reading from uses all different types of protocols, so the solution should be generic if possible.
pkt.payload is the IP layer. You're performing the same operation twice.
You should do:
pkt[IP].payload.chksum = None

DNS headers are being sent as Raw data with scapy

I am trying to set up a socket server on a linux machine using python , as a side project for my networking team.
the machine will listen to port 53, and will respond to dns queries using scapy.
Now, the asking part is all working great, atleast i think, i didnt really get to the part when i set the server as my dns server and try to use the internet yet, but when i try tcpdump it looks like a normal packet.
Anyway, when i respond from the server to the client, the packet is being sent with all the headers that i need, of DNS,DNSQR and DNSRR, as i saw in tcpdump.
But, when the client receive the packet, it only has IP,and UDP headers, as the rest is being sent as Raw data.
As i previously mentioned, i tried looking at wireshark and tcpdump and saw the difference that is being sent between the server and the client, and i saw that from the server side, the reply packet is being marked as malformed packet
Im not completely sure if this is the case, as i saw on the internet that its just because i didnt spoof it complettly.
code:
Client packet:
pkt = IP(dst='<Server IP>')/UDP(dport=53,sport=RandShort())/DNS(rd=1,qd=DNSQR(qname='dns.google'))
Server packet:
def build_dns_response(src_addr,og_sport,dns_qtype,dns_qname,response_type=True,response_name=None):
'''
a function that will build a DNS response packet back to the sender, according to the parameters that are recieved.
dns_qname = url/ip that the sender asked for.
og_sport = original source port, will be used as the dport of this packet
src_addr = source address of the original packet, will be used as the destination of this packet.
dns_qtype = the question type of the original request, 1 stands for type A, and 12 for PTR
response_type = will indicate if the server responds with an answer of 'ok' or 'name-error' on the 'rcode' field,True for ok,False for name-error
response_name = the response that the server will send as a result of the dns request, in case that a request matches to a database query.
'''
if response_type is True:
pkt = IP(src='<Server IP>',dst=src_addr)/\
UDP(sport=53,dport=og_sport)/\
DNS(opcode=0,rd=1,rcode='ok',nscount=1,ancount=1,qd=DNSQR(qname=dns_qname,qtype=dns_qtype),an=DNSRR(rrname=dns_qname,type=dns_qtype,rdata=response_name))
packet being sent by server:
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = udp
chksum = None
src = <Server IP>
dst = <client IP >
\options \
###[ UDP ]###
sport = domain
dport = 25151
len = None
chksum = None
###[ DNS ]###
id = 0
qr = 0
opcode = QUERY
aa = 0
tc = 0
rd = 1
ra = 0
z = 0
ad = 0
cd = 0
rcode = ok
qdcount = 1
ancount = 1
nscount = 1
arcount = 0
\qd \
|###[ DNS Question Record ]###
| qname = 'dns.google.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'dns.google.'
| type = A
| rclass = IN
| ttl = 0
| rdlen = None
| rdata = 8.8.8.8
ns = None
ar = None
packet that is received by the client:
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 82
id = 1
flags =
frag = 0
ttl = 64
proto = udp
chksum = 0x6686
src = <Server IP>
dst = <Client IP>
\options \
###[ UDP ]###
sport = domain
dport = 25151
len = 62
chksum = 0xf99
###[ Raw ]###
load = '\x00\x00\x01\x00\x00\x01\x00\x01\x00\x01\x00\x00\x03dns\x06google\x00\x00\x01\x00\x01\x03dns\x06google\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x08\x08\x08\x08'
I guess its worth mentioning that the entire conversation is from Host PC to vm being hosted on it.
Thanks in advance for any help!

Scapy NTP request

I would like to get the ntp_monlist response of my NTP server.
Actually the packet is send but I don't receive anything.
Someone can tell me why ?
Code :
#!/usr/bin/env python
from scapy.all import *
import threading
import os
import sys
import socket
#Data to send
ntpip = "xxx.xx.xxx.xx"
packet = IP(dst=ntpip)/UDP(dport=123)/Raw(load=str("\x17\x00\x03\x2a")+ str("\x00")*4)
packet.show()
rep,non_rep = srp(packet)
rep.show()
Reponse :
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = udp
chksum = None
src = xxx.xxx.xxx.xxx
dst = xxx.xxx.xxx.xxx
\options \
###[ UDP ]###
sport = domain
dport = ntp
len = None
chksum = None
###[ Raw ]###
load = '\x17\x00\x03*\x00\x00\x00\x00'
Begin emission:
Finished to send 1 packets.
......................................................................................................................
Received XXX packets, got 0 answers, remaining 1 packets
As you can see, I never receive any response.
You have multiple issues:
you're sending a layer 3 packet, so you need to use sr, not srp;
you need to specify a UDP source port;
your NTP payload is malformed.
There are two issues with your NTP payload. First of all, the first word of the NTP packet is defined as follows (RFC 5905):
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|LI | VN |Mode | Stratum | Poll | Precision |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
You want LI to be 0, VN to be 3, and Mode to be 3, so this gives a first octet of 0 + (3 * 8) + 3, or 0x1b.
Second, the minimum NTP packet is 12*4 octets.
So you need to say:
packet = IP(dst=ntpip)/UDP(dport=123,sport=50000)/("\x1b\x00\x00\x00"+"\x00"*11*4)
rep,non_rep = sr(packet)

Unreadable encoding of a SMB/Browser packet in Scapy

I'm trying to parse a pcap file with scapy (in python), and getting raw data at the layer above TCP.
on wireshark, all the layers are shown correctly:
but on scapy all i'm seeing is just a Raw layer...
i'm thinking maybe it didn't parsed the packet well?
maybe the NetBIOS moduled did not load? or maybe i didn't import the module right?
(i tryied:
import scapy.all, import scapy, import scapy.layers.smb )
how do i make scapy load the layers of the packet correctly?
thanks!
If someone has a similar problem…
You need something like
packet[TCP].decode_payload_as(NBTSession)
And then you Will get the decoded layers by scapy:
packet[TCP].show()
[ TCP ]
sport = microsoft_ds
…
options = []
[ NBT Session Packet ]###
TYPE = Session Message
RESERVED = 0
LENGTH = 4873
[ SMBNegociate Protocol Request Header ]###
Start = '\xfeSMB'
Command = 64
Error_Class= 0
Reserved = 1
Error_code= 0
Flags = 0
Flags2 = 0
PIDHigh = 5
Signature = 0
Unused = 0
TID = 183
PID = 0
UID = 0
MID = 0
WordCount = 0
ByteCount = 0
[ SMB Negotiate Protocol Request Tail ]###
BufferFormat= 0
BufferData= '\x03'
Also you can try after that to decode the packet with the different clases:
packet.decode_payload_as(SMBNegociate Protocol Request Header)

python SIP log file processing

i have a sniff/log file for VoIP/SIP generated by python scapy in format
time | src | srcport | dst | dstport | payload
the sniff python script looks like this:
## Import Scapy module
from scapy.all import *
import sys
sys.stdout = open('data.txt', 'w')
pkts = sniff(filter="udp and port 5060 and not port 22", count=0,prn=lambda x:x.sprintf("%sent.time% | %IP.src% | %IP.sport% | %IP.dst% | %IP.dport% | Payload {Raw:%Raw.load%\n}"))
each packet in one line and each line can have different size depends on SIP message type (Register, 200 OK, Invite, Notify and so on...)
What i would like to get from the file are fields
time, src, srcport, dst, dstport and from Payload type (just right after Payload) of SIP message, From, To, Call-iD, Contact
and the whole payload and then prepare these to insert into MySQL database.
1st msg:
07:57:01.894990 | 192.168.1.10 | 5060 | 192.168.1.1 | 5060 | Payload 'INVITE sip:210#test-lab.org SIP/2.0\r\nVia:
SIP/2.0/UDP 192.168.1.10:5060;rport;branch=z9hG4bK-9cbb0ba8\r\nRoute: <sip:192.168.1.1:5060;lr>\r\nFrom: "test-311" <sip:311#test-lab.org>;tag=3d13bd6f\r\n
To: <sip:210#test-lab.org>\r\nCall-ID: 21b0e2c755973976d6d06702ca33b32f#10.193.40.249\r\nCSeq: 1 INVITE\r\n
Contact: "test-311" <sip:311#192.168.1.10:5060;transport=UDP>\r\nMax-Forwards: 70\r\n
Supported: 100rel,replaces\r\nAllow: ACK, BYE, CANCEL, INFO, INVITE, OPTIONS, NOTIFY, PRACK, REFER, UPDATE, MESSAGE\r\nContent-Type: application/sdp\r\nContent-Length: 276\r\n\r\nv=0\r\no=- 3506863524 285638052 IN IP4 192.168.1.10\r\ns=-\r\nc=IN IP4 192.168.1.10\r\nt=0 0\r\nm=audio 8000 RTP/AVP 8 0 18 101\r\nc=IN IP4 192.168.1.10\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-15\r\na=ptime:20\r\n'
2nd msg:
07:57:01.902618 | 192.168.1.1 | 5060 | 192.168.1.10 | 5060 | Payload 'SIP/2.0 100 Trying\r\nVia: SIP/2.0/UDP 192.168.1.10:5060;received=192.168.1.10;branch=z9hG4bK-9cbb0ba8;rport=5060\r\nFrom: "test-311" <sip:+38551311#test-lab.org>;tag=3d13bd6f\r\nTo: <sip:210#test-lab.org>\r\nCall-ID: 21b0e2c755973976d6d06702ca33b32f#192.168.1.10\r\nCSeq: 1 INVITE\r\n\r\n'
I have tried to read line by line and split but I do not know how to split and take data from payload part.
Any help is more then welcome.
Well, you can enter the data into mysql straight from this program too; it might very well be the easiest approach.
from scapy.all import *
import sys
# connect to mysql
connection = ...
def insert_into_mysql(packet):
# now you can use packet.src, packet.sport, packet.dst, packet.dport, and
# I believe packet['Raw'].load
connection.execute(...)
# to not print the packet
return None
# to print the packet
return x.sprintf("%sent.time% | %IP.src% | %IP.sport% | %IP.dst% | %IP.dport% | Payload {Raw:%Raw.load%\n}"
pkts = sniff(filter="udp and port 5060", count=0, store=0, prn=insert_into_mysql)
But if you need to use the existing log, I think you need to use:
for line in open('log.txt'):
sent_time, src, sport, dst, dport, payload = line.split(' | ', 6)
payload = payload.replace('Payload ', '')
# to get the unquoted payload, I'd guess (can't test SIP though)
from ast import literal_eval
payload = literal_eval(payload)
from scapy.all import *
import MySQLdb, string, sys
def insert_into_mysql(packet):
db = MySQLdb.connect("localhost","test","testpwd","my_db" )
cursor = db.cursor()
# now you can use packet.src, packet.sport, packet.dst, packet.dport,
# and packet['Raw'].load
add_sip = ("INSERT INTO py_sniff "
"(time, src_ip, src_port, dst_ip, dst_port, message) "
"VALUES (%s, %s, %s, %s, %s, %s)")
# data from sniff
add_sip = {
'time': packet.sprintf("%sent.time%"),
'src_ip': packet.sprintf("%IP.src%"),
'src_port': packet.sprintf("%IP.sport%"),
'dst_ip': packet.sprintf("%IP.dst%"),
'dst_port': packet.sprintf("%IP.dport%"),
'message': packet.sprintf("{Raw:%Raw.load%}"),
}
# to print the packet
# return packet.sprintf("%sent.time% | %IP.src% | %IP.sport% | %IP.dst% | %IP.dport% | Payload {Raw:%Raw.load%\n}"
cursor.execute(add_sip)
db.commit()
pkts = sniff(iface="eth0", filter="udp and port 5060", count=0, store=0, prn=insert_into_mysql)

Categories