当前位置: 首页 > >

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

发布时间:

数据包注入是对已经建立的网络连接通过构建任意协议(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"协议,它会告诉系统我们将提供网络层和传输层。


s?=?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?<????????flags_offset?=?(self.flags?<????????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?<????????flags?=?self.fin?+?(self.syn?<????????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)

我们知道,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):?传输协议(6为TCP,?17为UDP)

在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])?<????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

一个小列子:?


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

wireshark的截图:



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



友情链接: