Can anyone tell me the most basic approach to generate UDP, TCP, and IP Packets with Python?
As suggested by jokeysmurf, you can craft packets with scapy
If you you want to send/receive regular, i.e. non-custom, packets then you should use socket or socketserver:
http://docs.python.org/library/socket.html#module-socket
http://docs.python.org/library/socketserver.html#module-SocketServer
For example, to send a TCP HTTP GET request to Google's port 80 use:
import socket
HOST = 'google.com' # The remote host
PORT = 80 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('GET / HTTP/1.1\r\nHost: google.com\r\n\r\n')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
To send UDP instead of TCP change SOCK_STREAM to SOCK_DGRAM.
You can do interactive packet manipulation with scapy.
This article is going to get you started on gluing together an IP packet.
Construction of a tcp packet is as easy as:
packet = IP(src="10.0.0.10")
Related
I have the following UDP / DGRAM socket in Python:
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print "received message:", data
This code is running in a proxy server, so destination IP and port is not matching the socket. I'm using tproxy to intercept the packets.
How can I get the destination IP and port, not the source IP and port?
from the docs of
socket.getsockname():
Return the socket’s own address. This is useful to find out the port number of an IPv4/v6 socket, for instance.
so you'd want to print out sock.getsockname()
I have a UDP communication between a server and client on localhost
according to this code:
https://pymotw.com/2/socket/udp.html
Echo Server:
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 12321)
sock.bind(server_address)
while True:
data, address = sock.recvfrom(4096)
if data:
sent = sock.sendto(data, address)
echo Client
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 12321)
message = 'This is the message. It will be repeated.'
try:
for i in range 4:
sent = sock.sendto(message, server_address)
data, server = sock.recvfrom(4096)
finally:
sock.close()
now let's say I got some MITM attack, and a specific packet doesn't arrive at the server, and the client is still waiting for a response from the server,
I get a deadlock.
how can I overcome this? is there some timeout parameter for UDP socket?
Yes, there is a timeout for UDP sockets. See socket.settimeout() in https://docs.python.org/2/library/socket.html and read up on non-blocking sockets in general.
Note that UDP packets can be dropped, duplicated, and/or re-ordered, even if there is no man-in-the-middle attacker. This is because UDP is (by design) an unreliable datagram protocol.
If you need a reliable protocol use TCP (or QUIC).
If you need assurance that no man-in-the-middle can modify or (optionally) observe the data, use TLS (or QUIC).
With python, I have compiled the following script:
from socket import *
socket = socket(AF_INET, SOCK_DGRAM)
socket.bind(("127.0.0.1", 80))
while True:
data, addr = socket.recvfrom(1024)
print addr[1]
It is supposed to receive all incoming traffic from port 80. However, if I load a webpage, it does not lot anything. Is there a problem with my script?
If you truly want to listen to all incoming traffic on all interfaces, perhaps try to bind to 0.0.0.0 instead of 127.0.0.1?
And as just stated, your socket pairing is a bit odd. This should get you started:
from socket import *
s = socket(AF_INET, SOCK_STREAM)
s.bind(('0.0.0.0', 80))
s.listen(1)
while True:
print s.accept()[1]
There seem to be some misconceptions here, and wanted to make clear for future visitors. When you visit a website you don't send packets out of port 80, you send packets from a random port to the port 80 of a different machine. In this case you are expecting to have packets on your port 80 when you are visiting website: this can't happen. This would only apply if you are hosting a website or listening on that port.
This following is a straightforward IPv4 UDP broadcast, followed by listening on all interfaces.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
sock.bind(("", 1337))
sock.sendto("hello world", ("255.255.255.255", 1337))
while True:
data, addr = sock.recvfrom(0x100)
print "received from {0}: {1!r}".format(addr, data)
I want to adjust this to send and receive both IPv4 and IPv6.
I've poked around and read as much as I can and believe the following is roughly the route I need to take:
Create an IPv6 socket.
Add the socket to a link or site local multicast group.
Send the UDP packets to the multicast address for the group in use.
Further info I have is that I may need to bind to several interfaces, and tell the socket using setsockopt() that it should also receive multicast packets. Lastly getaddrinfo() can be used across the board to gracefully "drop back" to IPv4 where IPv6 isn't available.
I have much of this implemented, but stumble primarily on the multicasting parts. A complete code example in Python, or vivid description of the constants and addresses needed are preferred.
Here's a link to python mcast demo, does both IPv4 and IPv6.
I'm currently asking a question over here that involves getting the multicast address of a received message, but the source code answers your question!
To listen:
# Initialise socket for IPv6 datagrams
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# Allows address to be reused
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Binds to all interfaces on the given port
sock.bind(('', 8080))
# Allow messages from this socket to loop back for development
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
# Construct message for joining multicast group
mreq = struct.pack("16s15s".encode('utf-8'), socket.inet_pton(socket.AF_INET6, "ff02::abcd:1"), (chr(0) * 16).encode('utf-8'))
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
data, addr = sock.recvfrom(1024)
and to send:
# Create ipv6 datagram socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
# Allow own messages to be sent back (for local testing)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
sock.sendto("hello world".encode('utf-8'), ("ff02::abcd:1", 8080))
This is for python3.6, with python 2.7 I don't think the encodes are necessary. Also in the struct.pack line, I've seen variations of "16s15s" such as "4s", but I don't know what it is and what I have worked for me!
I have set up a server socket (plain raw socket) listening on port A. A client now connects to this server. OS opens up a port for the client for this purpose. Say port B is allocated to this client. Now my question is, can a 3rd script connect to this port B and send data. Or in other words can I spoof a response to the client as if it was coming from the server? I tried spoofing it using scapy, but it wasnt working.
server.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("localhost", A))
s.listen(10)
ns, cli_addr = s.accept()
time.sleep(30) # so that i can trigger my 3rd script
goodclient.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", A))
print s.getsockname() # to get the local port of client - B
s.recv(1024)
badboy.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", B)) # connection refused error
s.send("hihihi")
scapybadboy.py
pack = IP(src="localhost", dst="localhost") / TCP(sport=A, dport=B) / "Hello"
send(pack) # Packet sent but not received by the client
Because server and client using SOCK_STREAM sockets, they both aware of TCP session(including port, IP and (SEQ_NUMBER,ACK_NUMBER)), so when session is already in process, you will have to perform TCP hikacking and IP spoofing in order to send messages in stream.
In other words, you will have to guess(or steal) ACK number of server in order to send fake messages to client using badclient.
However, if you will make somehow goodclient answer you and not a server you should run the following:
iptables -A FORWARD -j NFQUEUE --queue-num 1 , because your operating system doesn't know about session that you just "opened" with goodclient and it will send RST packet. This command will prevent it.