I have been working on a program lately for raw packets. We recently had a lecture about raw packets so I have been trying to learn and do exactly what my professor told me. I have a problem with my program it comes up with an error saying destination address required, its raw so I don't want to do socket.connect(destaddr) even though that will fix the error. Here is my code:
Here is the class and function:
#not real mac address to protect privacy also removed preamble
class packet(object):
b = ""
def __init__(self, payload):
self.payload = payload
def ether(self):
#preamble = "55555555555555D5"
macdest = "123456789101" #my mac address - needed to remove colons
macsource = "123456789101" #router mac address without colons
ethertype = "0800" #removed 0x because it is not needed
fcs = "" #frame check sequence none so far
frame = macdest+macsource+ethertype
return frame
def ip(self): #in hexadecimal
version = "4" #ipv4 hex
ihl = "5" #header length hex
dscp = "00" #default
ecn = "00" #default
length = "36" #ether-24 + ip-20 + tcp-30 = 54 to hexa = 35
idip="0000" #random id
flags = "40" #dont fragment flag is 2 to hex is 4
offset = "00" #space taker
ttl = "40"#hex(64) = 40
protocol = "06" #for tcp
checksum = "0000"
ipaddrfrom = "c0a8010a"
ipaddrto = "c0a80101"
datagram = version+ihl+dscp+ecn+length+idip+flags+offset+ttl+protocol+checksum+ipaddrfrom+ipaddrto
return datagram
def tcp(self):
portsrc = "15c0" #5568
portdest = "0050" #80
syn = "00000000"
ack = "00000000"
nonce = "80"
fin = "10"
windowscale = "813b"
checksum = "0000"
segment = portsrc+portdest+syn+ack+nonce+fin+windowscale + checksum
return segment
def getpacket(self):
frame = self.ether()
datagram = self.ip()
segment = self.tcp()
payload = self.payload
packet = frame+datagram+segment+payload
a = 0
b = ""
for char in packet:
a = a+1
b = b + char
if a == 4:
b = b + " "
a=0
self.fmtpacket = b
return packet
def raw():
s = socket(AF_INET, SOCK_RAW, IPPROTO_IP)
s.bind(('192.168.1.10', 0))
pckt = packet("")
netpacket = pckt.getpacket()
print "Sending: " + pckt.fmtpacket
print ""
s.sendall(netpacket)
data = s.recv(4096)
print data
If your professor is okay with it, you may find Scapy a lot easier to work with in creating raw packets in python.
From their website:
Scapy is a powerful interactive packet manipulation program. It is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. It can easily handle most classical tasks like scanning, tracerouting, probing, unit tests, attacks or network discovery (it can replace hping, 85% of nmap, arpspoof, arp-sk, arping, tcpdump, tethereal, p0f, etc.)
Is there a reason for binding to '0.0.0.0'? When you create a raw socket, you'll need to bind it to an interface.
One thing I notice is that you'll need the '\x' prefix for hex.
Right now, you're stringing together chars.
For example, in ip(), version + ihl = '45'. That's a string, not a hex value. When you're sending this along, as a raw packet, that's two bytes instead of the one that you want. You want to send '\x45', not '45'.
packet to be sent should contain the actual bytes and not the string.
Related
I have 2 programs comunicating with each other via ethernet. Sending one is using scapy to encode port, ip and payload before sending it as ethernet frame. My problem is that in payload im sending counter and when reciving that it's sometimes changed to symbol.
\x00\x00\x00\x00\x00\x00\x00\x07
\x00\x00\x00\x00\x00\x00\x00\x08 is fine but next
\x00\x00\x00\x00\x00\x00\x00\t
\x00\x00\x00\x00\x00\x00\x00\n
\x00\x00\x00\x00\x00\x00\x00\x0b its fine again
later they are changed to next asci symbols
My question is how to stop converting bytes to asci?
sender.py
import socket
from scapy.all import *
PADDING_VALUE = b'\xd1'
ETH_P_ALL = 3
DST_IP = "127.0.0.12"
IFACE = "lo"
SRC_IP = "127.0.0.11"
class FpgaMockup:
def __init__(self, setup_iface):
self.setup_sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
self.setup_sock.bind((setup_iface, 0))
self.padding = 16
def send(self, pkt):
self.setup_sock.send(pkt)
if __name__ == "__main__":
testing_fpga = FpgaMockup(IFACE)
for i in range(100):
packet = IP(dst=DST_IP, src=SRC_IP)/UDP(sport=12666, dport=12666)/Raw(load=int(i).to_bytes(8, "big")+PADDING_VALUE*testing_fpga.padding)
pkt = Ether(packet)
testing_fpga.send(raw(pkt))
print("Finished sending.")
reciever.py
import socket
ETH_P_ALL = 3
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
s.bind(("lo", 0))
while(True):
pkt = s.recv(4096)
print(pkt)
These are not "changed". \x09 is exactly the same as \t, \x0a is the same as \n. These are just printed differently but nevertheless are the same:
>>> print(b'\x08\x09\x0a\x0b')
b'\x08\t\n\x0b'
>>> b'\x08\x09\x0a\x0b' == b'\x08\t\n\x0b'
True
For more information see the documentation to the syntax of String and Bytes literals.
If you don't want to have this conversation simply enforce writing as a hexadecimal sequence instead of characters:
>>> b'\x08\t\n\x0b'.hex()
'08090a0b'
For a networking project, I'm using UDP Multicast to build an overlay network with my own implementation of IP.
I use the following to parse and build my Header first, then append the payload:
def __init__(buffer_size_bytes):
self.__buffer = bytearray(buffer_size_bytes)
def read_sock(self, listening_socket):
n_bytes, addr = listening_socket.recvfrom_into(self.__buffer, Packet.HEADER_SIZE)
packet = Packet.parse_header(self.__buffer)
if packet.payload_length is not 0:
packet.payload = parse_payload(packet.payload_length, listening_socket)
self.__router.add_to_route_queue(packet, listening_socket.locator)
def parse_payload(to_read, socket):
payload = bytearray(to_read)
view = memoryview(payload)
while to_read:
n_bytes, addr = socket.recvfrom_into(view, to_read)
view = view[n_bytes:]
to_read -= n_bytes
return payload
The header seems to be parsed correctly, but the payload gets corrupted every time. I can't figure out what I'm doing wrong when parsing the payload, and I can confirm I'm sending a bytearray from the other side.
For example, when I send a packet with the payload "Hello World" encoded in utf-8, I receive the following:
b'`\x00\x00\x00\x00\x0b\x00\x1f\x00\x00\x00'
The Packet.parse_header method:
def parse_header(cls, packet_bytes):
values = struct.unpack(cls.ILNPv6_HEADER_FORMAT, packet_bytes[:cls.HEADER_SIZE])
flow_label = values[0] & 1048575
traffic_class = (values[0] >> 20 & 255)
version = values[0] >> 28
payload_length = values[1]
next_header = values[2]
hop_limit = values[3]
src = (values[4], values[5])
dest = (values[6], values[7])
return Packet(src, dest, next_header, hop_limit, version, traffic_class, flow_label, payload_length)
For reference, the entire sent packet looks like this:
b'`\x00\x00\x00\x00\x0b\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01Hello World'
On receiving the first packet, the socket.recvfrom_into blocks when reading for the payload, and doesn't return until I send another message. It then seems to discard the payload of the previous message and use the second packet received as the payload...
Found my explanation here.
So the key thing was that I'm using UDP. And UDP sockets discard anything that doesn't fit in the buffer you give it.
TCP sockets however behave more like the bytestream I was expecting.
Fun!
I have a problem with my packet sniffer. The destination port and source port seems to be wrong in my sniffer. In wireshark the ports is totally different from my sniffers. No result contains port 443 expected from TLS. (The whole tcp-fragment might be wrong.)
Does it have to do something to do with the router?
I also know that there is some problems doing sniffing in windows. Or is my unpacking code just wrong? Am i missing some offset between ip-header and tcp-fragment ?
Socket code: https://pastebin.com/tMuHgz0R
Unpacking code: https://pastebin.com/9ZVfYNEE (full code)
# Unpack tcp fragment
def tcp_fragment(raw_data):
tcp_header = struct.unpack('!HHLLBBHHH', raw_data[:20])
source_port = tcp_header[0]
destionation_port = tcp_header[1]
sequence_number = tcp_header[2]
acknowledgement_number = tcp_header[3]
offset = tcp_header[4] >> 4
reserved = tcp_header[4] & 0xF
flags = get_tcp_flags(tcp_header[5])
window = tcp_header[6]
checksum = tcp_header[7]
pointer = tcp_header[8]
return {
TCP_SOURCE_PORT: source_port,
TCP_DESTINATION_PORT: destionation_port,
TCP_SEQUENCE_NUMBER: sequence_number,
TCP_ACKNOWLEDGEMENT_NUMBER: acknowledgement_number,
TCP_OFFSET: offset,
TCP_RESERVED: reserved,
TCP_FLAGS: flags,
TCP_WINDOW: window,
TCP_CHECKSUM: checksum,
TCP_POINTER: pointer,
TCP_PAYLOAD_DATA: raw_data[20:]
}
TCP header result: https://pastebin.com/7xhaEGer
Wireshark result for same packets:
Thanks in advance for any help you can provide.
Okay so i managed to solve it. It was a quite stupid error. I forgot to account for the ip-header bits when unpacking tcp.
Fixed code would look something like this:
# Unpack tcp & ip
def ip_tcp(raw_data):
iph = ip_header(raw_data)
iph_length = iph[IP_IHL] * 4
tcp = tcp_fragment(raw_data, iph_length)
return (iph, tcp)
# Unpack tcp fragment
def tcp_fragment(raw_data, iph_length):
tcp_header = struct.unpack('!HHLLBBHHH', raw_data[iph_length:iph_length + 20])
source_port = tcp_header[0]
destionation_port = tcp_header[1]
sequence_number = tcp_header[2]
acknowledgement_number = tcp_header[3]
offset = tcp_header[4] >> 4
reserved = tcp_header[4] & 0xF
flags = get_tcp_flags(tcp_header[5])
window = tcp_header[6]
checksum = tcp_header[7]
pointer = tcp_header[8]
return {
TCP_SOURCE_PORT: source_port,
TCP_DESTINATION_PORT: destionation_port,
TCP_SEQUENCE_NUMBER: sequence_number,
TCP_ACKNOWLEDGEMENT_NUMBER: acknowledgement_number,
TCP_OFFSET: offset,
TCP_RESERVED: reserved,
TCP_FLAGS: flags,
TCP_WINDOW: window,
TCP_CHECKSUM: checksum,
TCP_POINTER: pointer,
TCP_PAYLOAD_DATA: raw_data[iph_length + 20:]
}
I'm using the below script for injecting an ARP packet request. When I keep the source (MAC and IP) as my machine, I can happily see the packets in the wire and receive ARP replies however on changing the source to a different machine in the LAN, the ARP requests don't get back the ARP replies.
I am dicey if the RAW sockets can only frame up an ARP request for the base machine or am I going wrong somewhere ?
Below is the code ...
#!/usr/bin/python
import sys
import socket
import binascii
import struct
from itertools import chain
try:
iFace = raw_input("Enter the interface using which the Injection needs to be done ...\n")
rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW,socket.htons(0x0800))
rawSocket.bind((iFace, socket.htons(0x0800)))
print "Raw Socket got created .... with the Ethernet Protocol Id : 0x0806 at interface %s"%str(iFace)
except:
print "Something unexpected happened during the Program execution."
else:
def checkMac(mac):
if len(mac.split(":")) != 6:
print "The MAC is in correct. It should be in Hexadecimal Format with each byte separated with colon...\n"
sys.exit(0)
else:
macList = mac.split(":")
macLen = len(macList)
return tuple ([int(macList[index],16) for index in range(macLen)])
def checkIp(ip):
ipList = ip.split(".")
ipLen = len(ipList)
return int( "".join( [ "{:02X}".format(int(ele)) for ele in ipList ] ), 16 )
dMac = raw_input("Enter the Destination MAC .. hexadecimal charaters separated with ':' \n")
# dMac = "0X:XX:XX:XX:XX:4X"
dMacTup = checkMac(dMac)
# sMac = raw_input("Enter the Source MAC .. hexadecimal charaters separated with ':' \n")
sMac = "XX:XX:XX:XX:XX:XX"
sMacTup = checkMac(sMac)
type = 0x0806
# Creating an Ethernet Packet .... using dMac, sMac, type
etherPack = struct.pack ("!6B6BH",*tuple(chain(dMacTup,sMacTup,[type])))
# Creating an ARP Packet .... now
hardwareType = 0x0001
protocolType = 0x0800
hln = 0x06
pln = 0x04
op = 0x0001
# srcIp = raw_input("Enter the Source IP ':' \n")
srcIp = "10.0.2.216"
intSrcIp = checkIp(srcIp)
destIp = raw_input("Enter the Destination IP .. \n")
# destIp = "10.0.2.1"
intDestIp = checkIp(destIp)
arpPack = struct.pack("!HHBBH6BI6BI", *tuple(chain( [hardwareType,protocolType,hln,pln,op], sMacTup,[intSrcIp], dMacTup,[intDestIp] )))
# Framing the final Packet
finalPack = etherPack + arpPack
for i in range(50):
rawSocket.send(finalPack + "Hacker in the wires ...")
print "Sending Packet %d"%i
finally:
print "Closing the created Raw Socket ..."
rawSocket.close()
Okay, so I'm running Ubunutu 14.04 LTS, and I'm trying to poison my own ARP Cache, by doing this,
my private IP address is 10.0.0.1.
My phone's private IP address is 10.0.0.8.
for this example only let's say my MAC address is axaxaxaxaxax.
I've wrote the following python code:
from binascii import *
from struct import *
import socket;
class ethernetframe:
def __init__(self, destmac, srcmac, ethrtype):
self.destmac = unhexlify(destmac)
self.srcmac = unhexlify(srcmac)
self.ethrtype = unhexlify(ethrtype)
def uniteframe(self, payload):
frame = ''
frame = frame + self.destmac
frame = frame + self.srcmac
frame = frame + self.ethrtype
frame = frame + payload
frame = frame + unhexlify("00000000")
return frame
class arppacket:
def __init__(self,opcode,srcmac,srcip,dstmac,dstip):
if opcode == 1:
dstmac = "000000000000"
opcode = "0001"
else:
opcode = "0002"
self.opcode = unhexlify(opcode)
self.srcmac = unhexlify(srcmac)
self.srcip = pack('!4B',srcip[0],srcip[1],srcip[2],srcip[3])
self.dstmac = unhexlify(dstmac)
self.dstip = pack('!4B',dstip[0],dstip[1],dstip[2],dstip[3])
def unitepacket(self):
packet = ''
packet = packet + "\x00\x01\x08\x00\x06\x04"
packet = packet + self.opcode
packet = packet + self.srcmac
packet = packet + self.srcip
packet = packet + self.dstmac
packet = packet + self.dstip
return packet
e1 = ethernetframe("axaxaxaxaxax","axaxaxaxaxax","0800")
arp1 = arppacket(2,"axaxaxaxaxax",(10,0,0,8),"axaxaxaxaxax",(10,0,0,1))
arpacket = arp1.unitepacket()
fullethframe = e1.uniteframe(arpacket)
s = socket.socket(socket.AF_PACKET,socket.SOCK_RAW,socket.htons(0x0806))
s.bind(("eth0",0))
s.send(fullethframe)
now, I'm monitoring this whole process with Wireshark, the ARP packet is being send and it is formed correctly, In wire shark I see the following line:
10.0.0.8 is at axaxaxaxaxax
This means that I have successfully sent an ARP reply! to my own computer, stating that the MAC address that is resolved for 10.0.0.8 is axaxaxaxaxax
since ARP cache automatically update if a reply is received REGARDLESS if a request was sent, this means that in my NIC driver's arp cache there should've been a line added stating that
10.0.0.8 is resolved with axaxaxaxaxax
however, when I run inside my ubunutu's terminal
arp - a
or
arp - an
it doesn't show up....., which means I've failed to poison my own ARP cache, any ideas how to fix this?
Just a thought here - did you try
arp -an
Without the -n, arp will try to do a reverse name lookup on the hostname(s).