热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用Python进行TCP数据包注入(伪造)

数据包注入是对已经建立的网络连接通过构建任意协议(TCP…UDP…)然后用原始套接字发送的方式进行妨碍的过程,这种方法被广泛使用在网络渗透测试中,比如DDOS,端口扫描等。一个数据包由IP头部信息、T

数据包注入是对已经建立的网络连接通过构建任意协议(TCP…UDP…)然后用原始套接字发送的方式进行妨碍的过程,这种方法被广泛使用在网络渗透测试中,比如DDOS,端口扫描等。

一个数据包由IP头部信息、TCP/UDP头部信息和数据构成:

Packet = IP Header + TCP/UDP Header + Data

大多数操作系统的socket API都支持包注入(尤其是基于Berkeley Sockets的),微软在windows xp之后为了避免包嗅探限制了原始套接字的能力。这篇文章只适用于UNIX/类UNIX系统。

TCP协议被广泛运用于互联网上的数据传输,它是一种面向连接(连接导向)的、可靠的、基于IP的传输层协议。

TCP的首部格式:

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是源端口,16位。

—Destination Port是目的端口,16位。

—Sequence Number是发送数据包中的第一个字节的序列号,32位。

—Acknowledgment Number是确认序列号,32位。

—Data Offset是数据偏移,4位,该字段的值是TCP首部(包括选项)长度乘以4。

—标志位: 6位,URG表示Urgent Pointer字段有意义:

ACK表示Acknowledgment Number字段有意义

PSH表示Push功能,RST表示复位TCP连接

SYN表示SYN报文(在建立TCP连接的时候使用)

FIN表示没有数据需要发送了(在关闭TCP连接的时候使用)

Window表示接收缓冲区的空闲空间,16位,用来告诉TCP连接对端自己能够接收的最大数据长度。

—Checksum是校验和,16位。

—Urgent Pointers是紧急指针,16位,只有URG标志位被设置时该字段才有意义,表示紧急数据相对序列号(Sequence Number字段的值)的偏移。

更多TCP协议的详细信息可以在网上轻易找到,在这里不再赘述。

为了建立一个可以自己构造数据的包,我们使用"SOCK_RAW"这种socket格式,使用"IPPROTO_RAW"协议,它会告诉系统我们将提供网络层和传输层。

= socket.socket(socket.AF_INET,socket.SOCK_RAW,)

通过这个简单的类,我们可以进行IP头部信息构造

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)

"pack"方法会对IP头部元素进行打包并返回它

ipobj = ip("127.0.0.1", "127.0.0.2") # Creating an ip object instancei 
pobj
.source = "localhost" # Changing IP element value

构造TCP头部信息

TCP类允许我们轻易地操作TCP头部元素并打包它们

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(&#039;!HHLLBBHHH&#039;,
                     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(&#039;H&#039;, tcp_checksum) + struct.pack(&#039;!H&#039;, self.urgp)

我们知道,TCP协议是一种面向连接(连接导向)的、可靠的、基于IP的传输层协议,提供一种面向连接的、可靠的字节流服务,面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据包之前必须先建立一个TCP连接。

伪造的头部信息有五个不同的区域且包含了source ip和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): 发送者的IP地址
Destination IP address (32 bits): 接受者的IP地址
Reserved (8 bits): 清零
Protocol (8 bits): 传输协议(6TCP, 17UDP)

在TCP头部校验计算中,校验和字段必须清零。一旦值被计算出,在发送包之前必须插入字段中。

构造头部字段

source_ip = source
destination_ip 
= destination
reserved 
= 0
protocol 
= socket.IPPROTO_TCP

打包伪造的头部并且将它插入TCP头部和数据中:

# 伪造头部
psh 
= struct.pack("!4s4sBBH",
              source_ip
,
              destination_ip
,
              reserved
,
              protocol
,
              total_length
)
psh 
= psh + tcp_header + self.payload

校验函数:

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 (>> 16):
        
print("s >> 16: ", s >> 16)
        s 
= (& 0xFFFF) + (>> 16)
    
print("sum:", s)
    s 
= ~& 0xffff

一个小列子: 

= 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 scoket created
[+] Data to inject: TEST!!
[+] Constructing IP Header
[+] Constructing TCP Header

wireshark的截图:

项目地址:https://github.com/offensive-python/Pinject


推荐阅读
author-avatar
笑不评j
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有