Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ##
- # Uses a raw socket to create a TCP/IP packet
- import socket
- from struct import *
- import sys
- import time
- import random
- class Header:
- ##
- # Creates a header structure that is encoded/decoded using
- # encodestr. Fields of this header are identified by strings
- # stored in enc_keys, the ordering of this list specifies
- # the ordering of data in the header.
- # @param encodestr Str Format encoding string
- # @param enc_keys List of Str that are names of fields in this
- # header. If an element is a list and not a str, it indicates
- # that the given element is a single byte split into pieces. The
- # inner list should contain only lists. Each of those lists contain
- # two elements, the name of the field and the number of bits it occupies.
- def __init__(self, encodestr, enc_keys):
- self.encodestr = encodestr
- self.enc_keys = enc_keys
- self.fields = {}
- ##
- # Allows struct like transparency
- def __getattr__(self, key):
- return self.get(key)
- def __repr__(self):
- mystr = ""
- for key in enc_keys:
- if isinstance(key, list):
- for k2, bits in key:
- mystr += "{} = {}, ".format(k2, self.fields[k2])
- else:
- mystr += "{} = {}, ".format(key, self.fields[key])
- return mystr
- ##
- # Set a given field to a given value
- def set(self, key, value):
- self.fields[key] = value
- ##
- # Set multiple field's values at once
- def sets(self, values):
- for key in values:
- self.set(key, values[key])
- ##
- # Get a single field's value
- def get(self, key):
- return self.fields[key]
- def gets(self):
- return self.fields
- ##
- # Decodes the encoded string hdr into this header
- def decode(self, hdr):
- hdrvals = unpack (self.encodestr, hdr)
- for idx,key in enumerate(self.enc_keys):
- # Represents a byte split into pieces
- if isinstance(key, list):
- rshift = sum(map(lambda x: x[1], key))
- for index, lst in enumerate(key):
- k2, length = lst
- rshift -= length
- mask = 2**length - 1
- val = (hdrvals[idx] >> rshift) & mask
- self.set(k2, val)
- else:
- self.set(key, hdrvals[idx])
- ##
- # Encodes self into a header string as specified by
- # self.encodestr
- def encode(self):
- values = []
- for key in self.enc_keys:
- if isinstance(key, list):
- sumbits = sum([x[1] for x in key])
- value = 0
- for k2, bits in key:
- sumbits -= bits
- value += (self.get(k2) << sumbits)
- values.append(value)
- else:
- values.append(self.get(key))
- print ("Packing: {}\n{}".format(self.encodestr, values))
- return pack(self.encodestr, *values)
- ##
- # Defines some instance variables and special methods to
- # help with reading and writing IP Headers
- class IPHeader(Header):
- ##
- # Constructor.
- # @param values Dict of values to set for this header
- def __init__(self, values=None):
- super().__init__(None, None)
- self.encodestr = "!BBHHHBBH4s4s"
- self.enc_keys = [[["version", 4], ["length", 4]], "tos", "total_len", "ident",
- [["flags", 3], ["offset", 13]], "ttl", "protocol", "checksum",
- "s_addr", "d_addr"]
- if values != None:
- self.sets(values)
- self.fields["checksum"] = 0
- ##
- # Takes a raw packet (that begins with the IP Header) and
- # strips off the IP Header into this object.
- # @param hdr Raw IP Packet to decode
- # @post self is populated to contain data read from the packet
- def decode(self, hdr):
- super().decode(hdr[:20])
- if self.length > 5:
- toAdd = self.length - 5
- decstr = "!"
- added = ["L" for i in range(toAdd)]
- decstr += "".join(added)
- op_fields = ["options{}".format(i) for i in range(toAdd)]
- iph_ops = Header(decstr, op_fields)
- iph_ops.decode(hdr[20:20+(toAdd*4)])
- self.sets(iph_ops.gets())
- ##
- # Encodes the values stored in self.fields into a network
- # ready IP Header.
- # @return Bytes array containing self encoded as an IP Header
- def encode(self):
- self.fields["checksum"] = 0
- encData = super().encode()
- halves = int(len(encData) / 2)
- if len(encData) % 2 != 0:
- halves+=1
- decstr = "!"
- decstr += "".join(["H" for i in range(halves)])
- halves = unpack(decstr, encData)
- checksum = 0
- for half in halves:
- checksum += half
- while checksum >= 2**16:
- additive = 0xFF00 & checksum
- checksum &= 0xFF
- checksum += additive
- checksum = checksum ^ 0xFF
- self.set("checksum", checksum)
- return super().encode()
- ##
- # Defines some instance variables and special methods to
- # help with reading and writing TCP Headers
- class TCPHeader(Header):
- def __init__(self, values=None):
- super().__init__(None, None)
- self.encodestr = "!HHLLHHHH"
- self.enc_keys = ["s_port", "d_port", "seq", "ack",
- [["offset", 4], ["reserved", 3], ["flags", 9]],
- "window", "checksum", "urgent_ptr"]
- self.options = pack("!BBBB",
- 0x02, 0x04, 0x40, 0x0c)
- if values is not None:
- self.sets(values)
- self.fields['offset'] += int(len(self.options) / 4)
- def decode(self, hdr):
- super().decode(hdr[:20])
- if self.offset > 5:
- toAdd = self.offset - 5
- decstr = "!"
- added = ["L" for i in range(toAdd)]
- decstr += "".join(added)
- decfields = ["options{}".format(i) for i in range(toAdd)]
- tcp_ops = Header(decstr, decfields)
- tcp_ops.decode(hdr[20:20+toAdd*4])
- self.sets(tcp_ops.gets())
- def encode(self, iph, payload):
- ipdata = Header.encode(iph)
- self.fields["checksum"] = 0
- encData = ipdata + super().encode() + self.options + payload
- halves = int(len(encData) / 2)
- if len(encData) % 2 != 0:
- halves+=1
- decstr = "!"
- decstr += "".join(["H" for i in range(halves)])
- halves = unpack(decstr, encData)
- checksum = 0
- for half in halves:
- checksum += half
- while checksum >= 2**16:
- additive = 0xFF00 & checksum
- checksum &= 0xFF
- checksum += additive
- checksum = checksum ^ 0xFF
- self.set("checksum", checksum)
- return super().encode() + self.options
- def configure_socket():
- s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
- # Tells the kernel not to put IP Headers on packets from this socket
- s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
- return s
- def encodemsg (msg, src, dst):
- iph = IPHeader({
- "version": 4,
- "length": 5,
- "tos": 0, #Not real sure about this one
- "total_len": 0,# 20+40+len(msg),
- "flags": 2, # Don't fragment
- "offset": 0,
- "ttl": 64,
- "protocol": 6,
- "ident": 62546,#random.randint(0, 2**14-1),
- "s_addr": socket.inet_aton(src[0]),
- "d_addr": socket.inet_aton(dst[0]),
- })
- tcph = TCPHeader({
- "s_port": src[1],
- "d_port": dst[1],
- "seq": random.randint(0, 2**32-1),
- "ack": 0,
- "offset": 5,
- "reserved": 0,
- "flags": 2,
- "window": 32792, # Arbitrarily large so no backoff
- "urgent_ptr": 0,
- "checksum": 0, # Filled in shortly
- })
- encstr = "!"
- toAdd = ["B" for i in range(len(msg))]
- encstr += "".join(toAdd)
- payload = pack(encstr, *bytes(msg, "utf-8")) if len(msg) > 0 else b''
- tcpdata = tcph.encode(iph, payload)
- return iph.encode() + tcpdata + payload
- def decodemsg(msg):
- iph = IPHeader()
- iph.decode(msg)
- msg = msg[iph.length*4:]
- iph_values = iph.gets()
- iph_values['s_addr'] = socket.inet_ntoa(iph_values['s_addr'])
- iph_values['d_addr'] = socket.inet_ntoa(iph_values['d_addr'])
- print ("IP HEADER")
- print (iph_values)
- print ("\n")
- tcph = TCPHeader()
- tcph.decode(msg)
- msg = msg[tcph.offset*4:]
- print ("TCP HEADER")
- print (tcph.gets())
- print ("\n")
- print ("PAYLOAD:")
- print (msg)
- def sniff():
- s = configure_socket()
- s.bind(("localhost", 0))
- while True:
- msg = s.recv(66565)
- decodemsg(msg)
- s.close()
- def main(src, dst):
- s = configure_socket()
- msg = input("$ ")
- while msg != "exit":
- payload = encodemsg(msg, src, dst)
- s.sendto(payload, (dst[0], 0))
- msg = input("$ ")
- def usage():
- print (
- """
- Usage: {} [<<src-host> <src-port> <dst-host> <dst-port>>]
- If arguments are supplied, they must all be supplied. They
- specify to open a connection as <src-host>:<src-port> connected
- to <dst-host>:<dst-port>.
- If no arguments are supplied, the program acts as a sniffer
- """.format(sys.argv[0]))
- if __name__ == '__main__':
- if len(sys.argv) == 5:
- main((sys.argv[1], int(sys.argv[2])), (sys.argv[3], int(sys.argv[4])))
- elif len(sys.argv) == 1:
- sniff()
- else:
- usage()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement