Scapy - persistent RandIP - python

I am trying to simulate a TCP communication between two hosts with scapy.
My problem is, that I can't save the random IP addresses scapy generates for me.
This code
src_IP = RandIP()
print(src_IP)
print(src_IP)
print(src_IP)
gives me an output like this
234.200.98.20
147.3.56.17
135.102.142.49
So every time I access src_IP it has a new value.
Is there a way to save a random IP from scapy? So I could generated 2 IPs at the beginning of my function and use them as source and destination for my TCP communication.
I could generate the IPs myself, but I thought there had to be a more elegant solution to it.
BTW. non of the packets are going to be sent, they will be written into a PCAP file. Therefor I have to create both sides of the communication.

The accepted answer is a hack; it is correct (as in "it works and do what was asked"), but it is not the correct way to do that in Scapy.
The method you are looking for is ._fix(). It will work with any volatile value type.
src_IP = RandIP()._fix()
If you also need for example a random source port, you could do:
src_port = RandShort()._fix()

I found an answer.
RandIP() creates an instance of an object, and every time this object gets accessed, to print or do send a packet or something else, it generates a new IP.
So my solution is to cast it to a string
src_IP = str(RandIP())
print(src_IP)
print(src_IP)
print(src_IP)
And the output is just as intended
232.119.133.38
232.119.133.38
232.119.133.38

Related

Python: wrong ip is shown in packet header

I'm forwarding a machine's packets through mine. I tested with tcpdump host <machine_ip> to see if everything is alright, and it is. Now I need to capture these packets. I chose to do this with Python. Right now I'm trying to filter the packets, but the ip that is printed is different from the right one. It should've been 192.168.0.8:
import socket
from struct import *
print("Started")
with socket.socket(socket.AF_PACKET,socket.SOCK_RAW, socket.ntohs(0x0003)) as s:
while True:
packet=s.recvfrom(65565)
content=packet[0]
ip_header=unpack('!BBHHHBBH4s4s', content[:20])
source_ip=socket.inet_ntoa(ip_header[8])
print(source_ip)
The printed ones are 8.0.69.0 and 8.0.69.16, which none of these matches the expected form.
This is because in front of the raw data is the MAC header.
If You change the line:
ip_header=unpack('!BBHHHBBH4s4s', content[:20])
to
ip_header=unpack('!BBHHHBBH4s4s', content[14:34])
You will probably get your ip address. I said probably becase it really depends on the link layer, as there might be a vlan tag present, thus shifting the ip header even further.

Cannot print CDP Packet IP Address, but LLDP works fine

I am having an issue where I am trying to use Python's pyshark to read in IP addresses. I was able to print out the IP address of an LLDP packet just fine, using packet.lldp.mgn_addr_ip4. However packet.cdp... does not seem to have an equivalent, besides packet.cdp which returns a sequence of bytes.
I have tried packet.cdp.nrgyz.ip_address and nothing is printed out. I tried every other field from this link as well and nothing will return.
for packet in cap:
try:
if packet.cdp:
print(packet.cdp.nrgyz.ip_address)
elif packet.lldp:
print(packet.lldp.mgn_addr_ip4)
except AttributeError as e:
pass
I'd really appreciate any kind of guidance since not a single one of the fields that says it returns an IPv4 address will print out.
I figured it out. Apparently you can't use cdp.nrgyz(DOT)ip_address, and instead have to use cdp.nrgyz(UNDERSCORE)ip_address. So it becomes cdp.nrgyz_ip_address, even though Wireshark documentation says it should be cdp.nrgyz.ip_address

How fragments are implied for ICMP in scapy

Generally I can send a ICMP packet as mentioned below
srp(Ether(src=u'd2:ff:90:c5:1f:21', dst=u'9c:22:14:4f:6c:ac', type=2048)/IP(src=u'238.166.15.14', dst=u'70.74.2.83')/ICMP(type=8)/Raw(load='UZe5ICdH'),timeout=10,iface="ens192.50")
For example to send a fragmented packet can i do it as,
srp(fragment(Ether(src=u'd2:ff:90:c5:1f:21', dst=u'9c:22:14:4f:6c:ac', type=2048)/IP(src=u'238.166.15.14', dst=u'70.74.2.83')/ICMP(type=8)/Raw(load='UZe5ICdH'),fragsize=2),timeout=10,iface="ens192.50")
I got this from one of the blogs. But am not sure whether am doing it properly or not.
fragment() should be used on an IP packet and return a list of fragments. You should change your code to send each fragment one by one:
frags = fragment(IP(src='238.166.15.14', dst='70.74.2.83')/ICMP(type=8)/Raw(load='UZe5ICdH'),fragsize=2)
l2 = Ether(src='d2:ff:90:c5:1f:21', dst='9c:22:14:4f:6c:ac', type=2048)
for f in frags:
srp(l2/f, timeout=10,iface="ens192.50")
maybe helpful for someone looking this topic, this code snippet given in question work fine.
srp(fragment(Ether(src=u'60:36:dd:3f:5f:c5', dst=u'7c:c3:85:30:8c:24', type=2048)/IP(src=u'192.168.18.24', dst=u'192.168.18.1')/ICMP(type=8)/Raw(load='UZe5ICdH'),fragsize=2),timeout=1,iface="wlp2s0")

How to combine decoded packet data and header output into a single variable/dictionary for string searches

I'm somewhat of a Python novice, but I've taken up a small personal project to teach myself a bit more. Basically, I'm writing a packet sniffer using sockets and impacket. However, where I am getting stuck at is one particular point: combining the output from header and packet into one variable (I was thinking of a dictionary, but it didn't like that...) so that I can simply search out the IP header for one particular partial source IP (i.e., the first two octets). Or would there be a more efficient way of handling this? Any help is appreciated. :-)
EDIT: When I was trying the dictionary, I was doing
ip_dict = { header: packet }
However, the output I get is akin to this:
{<impacket.ImpactPacket.IP instance at 0x02563440>: <impacket.ImpactPacket.Data instance at 0x02563530>}
As opposed to the actual output of said IP header and data.
HOST = socket.gethostbyname(socket.gethostname())
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 0))
while True:
# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
# receive a packet
packet = s.recvfrom(42028)[0]
# look at IP info
h_decode = ImpactDecoder.IPDecoder()
header = h_decode.decode(packet)
# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
decoder = ImpactDecoder.DataDecoder()
packet = decoder.decode(packet)
print header
print packet
time.sleep(1)
Dictionaries are sets of key/value pairs. When you used
ip_dict = { header: packet }
You told it to build a dictionary with the header instance as the key and the packet instance as the value, which is what it did:
{<impacket.ImpactPacket.IP instance at 0x02563440>: <impacket.ImpactPacket.Data instance at 0x02563530>}
If you want something from inside those instances, you have to extract it yourself. For example, although I've never used the impacket library before, the objects seem to have lots of methods living inside them. For example [suppressing the real numbers and data and replacing them with nonsense]:
In [25]: z
Out[25]: <impacket.ImpactPacket.IP instance at 0xb6151fac>
In [26]: z.[here I hit TAB in the IPython interpreter]
z.add_option z.get_ip_offmask z.set_bytes_from_string
z.auto_checksum z.get_ip_p z.set_checksum_from_data
z.calculate_checksum z.get_ip_rf z.set_ip_address
z.child z.get_ip_src z.set_ip_df
z.compute_checksum z.get_ip_sum z.set_ip_dst
z.contains z.get_ip_tos z.set_ip_hl
z.ethertype z.get_ip_ttl z.set_ip_id
z.fragment_by_list z.get_ip_v z.set_ip_len
z.fragment_by_size z.get_long z.set_ip_mf
z.get_buffer_as_string z.get_packet z.set_ip_off
z.get_byte z.get_pseudo_header z.set_ip_offmask
z.get_bytes z.get_size z.set_ip_p
z.get_data_as_string z.get_word z.set_ip_rf
z.get_header_size z.is_BSD z.set_ip_src
z.get_ip_address z.list_as_hex z.set_ip_sum
z.get_ip_df z.load_header z.set_ip_tos
z.get_ip_dst z.normalize_checksum z.set_ip_ttl
z.get_ip_hl z.packet_printable z.set_ip_v
z.get_ip_id z.parent z.set_long
z.get_ip_len z.protocol z.set_parent
z.get_ip_mf z.set_byte z.set_word
z.get_ip_off z.set_bytes
In [26]: z.get_ip_src()
Out[26]: '1.2.3.4' # fake
In [27]: z.get_ip_dst()
Out[27]: '5.6.7.8' # fake
In [29]: z.get_data_as_string()
Out[29]: '\x00abcde' # fake
I have no idea what half of the methods do, or which of them are important, but you can easily build a dictionary out of whatever you like:
In [31]: {(z.get_ip_src(), z.get_ip_dst()): z.get_bytes()}
Out[31]:
{('1.2.3.4',
'5.6.7.8'): array('B', [1,2,3,4,5,6,7,8])} # fake
or combine bits from the IPDecoder and the DataDecoder, whatever. The point is that the issue isn't about Python dictionaries, it's about the impacket library's data structures, and what information you want to extract from them. The docs will probably describe how to get what you need.

Scapy: fields to recompute when forging packets

I'm forging with Scapy the TTL value in the IP header in some data packet that I captured. Besides the checksum in both IP and transport layer headers, is there anything else I should recompute?
Right now I'm doing:
for p in myPackets:
p[IP].ttl = targetTTL
del(p[IP].chksum)
del(p[IP].payload.chksum)
for i in range(len(myPackets)):
myPackets[i] = myPackets[i].__class__(str(myPackets[i]))
I'm asking this because Scapy's sr function, which matches packets with their responses (ICMP in my case) has been returning data with a few RTTs > 1 second, which is absurd since I'm using ttl=1.
Have you tried just sending the packet? Scapy should recompute the checksums for you automatically.You could also try setting them to None, but I don't believe that's necessary.
I believe scapy will automatically recalculate the checksums if you call the show2() command on the packet. So if you have a packet at index 0 in the object pckt, you should call pckt.show2() and the checksum should be correct. At least that's my understanding.
pkt.show2() same as show but on the assembled packet (checksum is calculated, for instance) Source

Categories