Packet injection is the process of disrupting an established network connection by constructing arbitrary protocols (TCPâŚUDPâŚ) and then sending them using raw sockets. This method is widely used in network penetration testing, such as DDOS, port scanning, etc.
A packet consists of IP header information, TCP/UDP header information, and data:
Packet = IP Header + TCP/UDP Header + Data
Most operating systemsâ socket APIs support packet injection (especially those based on Berkeley Sockets). Microsoft has restricted the capabilities of raw sockets in Windows XP and later to prevent packet sniffing. This article only applies to UNIX/Unix-like systems.
The TCP protocol is widely used for data transmission on the Internet. It is a connection-oriented, reliable, IP-based transport layer protocol.
TCP Header Format:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Source Port | Destination Port |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Sequence Number |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Acknowledgment Number |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Data | |U|A|P|R|S|F| || Offset| Reserved |R|C|S|S|Y|I| Window || | |G|K|H|T|N|N| |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Checksum | Urgent Pointer |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Options | Padding |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| data |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
âSource Port is the source port, 16 bits.
âDestination Port is the destination port, 16 bits.
âSequence Number is the sequence number of the first byte in the packet, 32 bits.
âAcknowledgment Number is the acknowledgment sequence number, 32 bits.
âData Offset is the data offset, 4 bits, and the value of this field is the length of the TCP header (including options) multiplied by 4.
âFlags: 6 bits, URG indicates that the Urgent Pointer field is significant:
ACK indicates that the Acknowledgment Number field is significant
PSH indicates the Push function, RST indicates resetting the TCP connection
SYN indicates a SYN packet (used when establishing a TCP connection)
FIN indicates no more data to send (used when closing a TCP connection)
Window indicates the free space in the receive buffer, 16 bits, used to tell the TCP connection peer the maximum data length it can receive.
âChecksum is the checksum, 16 bits.
âUrgent Pointer is the urgent pointer, 16 bits, and this field is significant only when the URG flag is set, indicating the offset of the urgent data relative to the sequence number (the value of the Sequence Number field).
More detailed information about the TCP protocol can be easily found online, and will not be elaborated here.
To create a packet where we can construct our own data, we use the âSOCK_RAWâ socket format with the âIPPROTO_RAWâ protocol, which tells the system that we will provide the network layer and transport layer.
s = socket.socket(socket.AF_INET,socket.SOCK_RAW,)
Through this simple class, we can construct IP header information
class ip(object):
def __init__(self, source, destination):
self.version = 4
self.ihl = 5 # Internet Header Length
self.tos = 0 # Type of Service
self.tl = 0 # total length will be filled by kernel
self.id = 54321
self.flags = 0 # More fragments
self.offset = 0
self.ttl = 255
self.protocol = socket.IPPROTO_TCP
self.checksum = 0 # will be filled by kernel
self.source = socket.inet_aton(source)
self.destination = socket.inet_aton(destination)
def pack(self):
ver_ihl = (self.version << 4) + self.ihl
flags_offset = (self.flags << 13) + self.offset
ip_header = struct.pack("!BBHHHBBH4s4s",
ver_ihl,
self.tos,
self.tl,
self.id,
flags_offset,
self.ttl,
self.protocol,
self.checksum,
self.source,
self.destination)
The âpackâ method will pack the IP header elements and return it
ipobj = ip("127.0.0.1", "127.0.0.2") # Creating an ip object instancei
pobj.source = "localhost" # Changing IP element value
Constructing TCP Header Information
The TCP class allows us to easily manipulate TCP header elements and pack them
class tcp(object):
def __init__(self, srcp, dstp):
self.srcp = srcp
self.dstp = dstp
self.seqn = 0
self.ackn = 0
self.offset = 5 # Data offset: 5x4 = 20 bytes
self.reserved = 0
self.urg = 0
self.ack = 0
self.psh = 1
self.rst = 0
self.syn = 0
self.fin = 0
self.window = socket.htons(5840)
self.checksum = 0
self.urgp = 0
self.payload = ""
def pack(self, source, destination):
data_offset = (self.offset << 4) + 0
flags = self.fin + (self.syn << 1) + (self.rst << 2) + (self.psh << 3) + (self.ack << 4) + (self.urg << 5)
tcp_header = struct.pack('!HHLLBBHHH',
self.srcp,
self.dstp,
self.seqn,
self.ackn,
data_offset,
flags,
self.window,
self.checksum,
self.urgp)
#pseudo header fields
source_ip = source
destination_ip = destination
reserved = 0
protocol = socket.IPPROTO_TCP
total_length = len(tcp_header) + len(self.payload)
# Pseudo header
psh = struct.pack("!4s4sBBH",
source_ip,
destination_ip,
reserved,
protocol,
total_length)
psh = psh + tcp_header + self.payload
tcp_checksum = checksum(psh)
tcp_header = struct.pack("!HHLLBBH",
self.srcp,
self.dstp,
self.seqn,
self.ackn,
data_offset,
flags,
self.window)
tcp_header+= struct.pack('H', tcp_checksum) + struct.pack('!H', self.urgp)
We know that the TCP protocol is a connection-oriented, reliable, IP-based transport layer protocol that provides a connection-oriented, reliable byte stream service. Connection-oriented means that two applications using TCP (usually a client and a server) must establish a TCP connection before exchanging packets with each other.
The forged header information has five different areas and includes the source IP and destination IP
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Source IP address |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Destination IP address |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Reserved | Protocol | Total Length |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
â˘Source IP address (32 bits): Sender's IP addressâ˘Destination IP address (32 bits): Receiver's IP addressâ˘Reserved (8 bits): Zeroedâ˘Protocol (8 bits): Transport protocol (6 for TCP, 17 for UDP)
In the TCP header checksum calculation, the checksum field must be zeroed. Once the value is calculated, it must be inserted into the field before sending the packet.
Constructing Header Fields
source_ip = source
destination_ip = destination
reserved = 0
protocol = socket.IPPROTO_TCP
Pack the forged header and insert it into the TCP header and data:
# Forged header
psh = struct.pack("!4s4sBBH",
source_ip,
destination_ip,
reserved,
protocol,
total_length)
psh = psh + tcp_header + self.payload
Checksum Function:
def checksum(data):
s = 0
n = len(data) % 2
for i in range(0, len(data)-n, 2):
s+= ord(data[i]) + (ord(data[i+1]) << 8)
if n:
s+= ord(data[i+1])
while (s >> 16):
print("s >> 16: ", s >> 16)
s = (s & 0xFFFF) + (s >> 16)
print("sum:", s)
s = ~s & 0xffff
A small example:
s = socket.socket(socket.AF_INET,
socket.SOCK_RAW,
socket.IPPROTO_RAW)
src_host = "10.0.2.15"
dest_host = socket.gethostbyname("www.reddit.com")
data = "TEST!!"# IP Header
ipobj = ip(src_host, dest_host)
iph = ip_object.pack()# TCP Header
tcpobj = tcp(1234, 80)
tcpobj.data_length = len(data) # Used in pseudo header
tcph = tcpobj.pack(ipobj.source,
ipobj.destination)# Injection
packet = iph + tcph + data
Pinject.py Running the script: python pinject.py --src=10.0.2.15 --dst=www.reddit.com [+] Local Machine: 10.0.2.15[+] Remote Machine: 198.41.209.142[+] Raw socket created [+] Data to inject: TEST!![+] Constructing IP Header[+] Constructing TCP Header
Screenshot from Wireshark:

Project Address:https://github.com/offensive-python/Pinject