Find LAN router IP address with Scapy? - python

I am attempting to find my router's IP address with Scapy.
I am running a distro of Linux and fully understand that I could use system calls or subprocess to get to the routing tables and find the gateway. However, I am trying to do this without system calls.
I imagine there is a way to do there is a way to do this with Scapy, does anyone know?

FTR, see https://scapy.readthedocs.io/en/latest/routing.html
Get router IP address
>>> gw = conf.route.route("0.0.0.0")[2]
>>> gw
'10.0.0.1'

I used the knowledge that if i send a packet to a distant IP adress with ttl = 0, I will get an ICMP packet from the first router i pass(my default gateway), all i'll need to do later is get the IP from that packet
from scapy.all import *
p = sr1(IP(dst="www.slashdot.org", ttl = 0)/ICMP()/"XXXXXXXXXXX")
print p.src

Related

Simple scapy script not sending packet

I have the most simple scapy script possible but It is not working. Please help:
import scapy.all as scapy
def scan(ip):
scapy.arping(ip)
scan("192.169.11.117")
When it runs I get this:
Begin emission:
Finished sending 1 packets.
Received 0 packets, got 0 answers, remaining 1 packets
How can I fix this and actually get answers?
Problem #1
You are likely using the wrong subnet. Private subnets (RFC 1918) are
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
You probably meant to do this, which is a private IP address
scan("192.168.11.117")
and not this
scan("192.169.11.117")
which is a public IP address. It's also possible that you own this public subnet, in which case this is not relevant.
Problem #2
The remote host may not be responding because it doesn't exist at that address. Make sure to double check that the target whose IP you are using in arping is online and accessible.
You can check arp mappings on *nix and windows by using arp -a on your command line
$ arp -a
? (192.168.1.111) at 0:1b:78:20:ee:40 on en0 ifscope [ethernet]
? (192.168.1.112) at a4:77:33:88:92:62 on en0 ifscope [ethernet]
? (192.168.1.117) at 6c:33:a9:42:6a:18 on en0 ifscope [ethernet]
...
for the target IP to make sure that a scapy arping should resolve.
If you are trying to do an ARP scan, then you should look at Cukic0'ds answer.
That's not how you use it.
Have a look at the doc:
https://scapy.readthedocs.io/en/latest/usage.html#arp-ping
arping("192.169.11.*")
You should look up what an ARP scan is. You don't just send a packet to a single IP, but to a range (using a submask).

generating a spoofed UDP packet in python

how can i create a spoofed UDP packet using python sockets,without using scapy library.
i have created the socket like this
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
sock.sendto(bytes('', "utf-8"), ('192.168.1.9', 7043))# 192.168.1.9dest 7043 dest port
This is one of the first results for google searches like "spoofing udp packet python" so I am going to expand #Cukic0d's answer using scapy.
Using the scapy CLI tool (some Linux distributions package it separately to the scapy Python library ):
pkt = IP(dst="1.1.1.1")/UDP(sport=13338, dport=13337)/"fm12abcd"
send(pkt)
This sends a UDP Packet to the IP 1.1.1.1 with the source port 13338, destination port 13337 and the content fm12abcd.
If you need to a certain interface for some reason (like sending over a VPN that isn't your default route) you can use send(pkt, iface='tun0') to specify it.
One difference to #Cukic0d's answer is that this solution is more flexible by sending a layer 3 packet with send instead of a layer 2 packet with sendp. So it isn't necessary to prepend the correct Ethernet header with Ether() which can cause issues in some scenarios, e.g.:
WARNING: Could not get the source MAC: Unsupported address family (-2) for interface [tun0]
WARNING: Mac address to reach destination not found. Using broadcast.
I think you mean changing the source and destination addresses from the IP layer (on which the UDP layer is based).
To do so, you will need to use raw sockets. (SOCK_RAW), meaning that you have to build everything starting from the Ethernet layer to the UDP layer.
Honestly, without scapy, that’s a lot of hard work. If you wanted to use scapy, it would take 2 lines:
pkt = Ether()/IP(src=“...”, dst=“...”)/UDP()/...
sendp(pkt)
I really advice you to use scapy. The code itself is quite small so I don’t see a reason not to use it. It’s defiantly the easiest in python

Sending scapy IP packet with no interface IP error

I'm currently trying to send an IP packet to an interface using the send(pkt, iface="eth0") function and I'm getting the error:
WARNING: Mac address to reach destination not found. Using broadcast
The interface I am trying to send out on doesn't have an IP address, and thats the way I would prefer it. And if it makes a difference, the interface is a bridge (created with brctl)
There is an ARP entry for the host that is in the IP packet however it seems scapy isn't doing the lookup required to get the MAC from the ARP table...
Thoughts?!
I would say this is normal, since making a valid ARP request requires an IP address (and Scapy maintains its own ARP table, independent from the OS one).
You can set the destination address yourself: srp(Ether(dst="[MAC address]")/[...]). If you need to get the MAC address first, create and send an ARP request the same way.
To query Scapy's ARP table, access the element conf.netcache.arp_cache, which is a Scapy-specific dict subclass (called CacheInstance).
For example, to add an entry for your host (and then use sr([...]) instead of srp(Ether(dst="[MAC address])/[...])), use:
conf.netcache.arp_cache['[IP address]'] = '[MAC address]'
The default dst address (MAC address) of an Ethernet frame in scapy is broadcast. This warning is generated whenever you send an Ethernet frame to the broadcast address (ff:ff:ff:ff:ff:ff), as far as I'm concerned. You can see this by creating the packet like this:
Ether()/IP() or Ether()/ARP()
instead of just IP() or ARP().

Python - Twisted - Simple UDP forwarder. Preserve source IP?

I have this basic UDP forward script in Python 3.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
class Forward(DatagramProtocol):
def __init__(self, targetTuples):
print ('in init, targetTuples are ', targetTuples)
self._targetTuples = targetTuples
def datagramReceived(self, data, hostAndPort):
print ('self._targetTuples is ', self._targetTuples)
for (targetHost, targetPort) in self._targetTuples:
self.transport.write(data, (targetHost, targetPort))
reactor.listenUDP(5005, Forward([('10.35.203.24', 5000), ('10.35.200.251', 5005)]))
reactor.run()
So I'm listening on port 5005 UDP, and forwarding those packets to the two IP addresses and different ports.
My question is this -
How do I preserve the original IP address that twisted gets while listening on port 5005?
Source IP (10.1.1.1) --> Twisted (10.30.1.1) --> Multiple Destinations
How can I get Multiple Destinations to see the packet source preserved from the Source IP of (10.1.1.1) ?
When sending UDP datagrams using the BSD socket API (around which, as a first approximation, Twisted is a wrapper), the source address is set to the address the socket is bound to. You can specify the IP of the bind address for a UDP socket in Twisted by passing a value for the interface argument to reactor.listenTCP. However, you are typically restricted in what addresses you are allowed to bind to. Typically the only values allowed are addresses which are assigned to a local network interface. If you are forwarding traffic for 10.1.1.1 but you are on host 10.30.1.1 then you probably cannot set the source address of the UDP packets you send to 10.1.1.1 because that address isn't assigned to a network interface on the host doing the forwarding. If you assigned it to one, routing on your network would probably break in weird ways because then two different hosts would have the same IP address.
This doesn't mean it's not possible to do what you want - but it does mean you probably cannot do it using Twisted's basic UDP support. There are a number of other approaches you could take. For example, you can rewrite source addresses using iptables on Linux. Or you can operate on the IP level and parse and generate full UDP datagrams yourself letting you specify any source address you want (you can do this with Twisted on Linux, too, using twisted.pair.tuntap). There are probably a number of other ways. The best solution for you may depend on which platforms you're targeting and the particular reasons you want to do this kind of forwarding.

Capture destination IP in TCP Python SocketServer

I have a Python script that is running on a Linux server that has a dozen IP addresses associated with it. I implemented a TCPSServer from Python's socketserver library and had it listen on all network interfaces.
Several devices will be connecting to this server, and we need to be able to somehow capture the ip address of the destination (not the IP address of the client, but the IP address of the server that the client thinks it is connecting to). Right now, I can receive client connections, I can see the client IP, but I cannot figure out a method for obtaining the destination IP.
Does anyone know a method for capturing the destination IP on the socketserver class? It would seem if I can listen to multiple interfaces, there would be a way to tell which interface was hit.
This will be installed on several servers eventually, each with an unknown number of network interfaces. However, we do know that this will only exist on Linux bases systems. So if there was an OS specific way to do this, I would be fine with that as well.
If you have a socket object, you can use socket.getsockname() to obtain the IP address it's bound to. So something along the lines of:
# IPv4
client = listening_socket.accept()
(ipv4,port) = client.getsockname()
# IPv6
client = listening_socket.accept()
(address, port, flow_info, scope_id) = client.getsockname()
Never tested it on a multihomed server with a socket bound to all interfaces though - might return IPv4 0.0.0.0 or the IPv6 equivalent, for all I know, which wouldn't be all that useful.

Categories