涉及知识
1.握手和挥手的本质
这里的数据仅仅指的是应用层http里携带的的数据,不包括TCP和IP包头。
知识点1
假设你在发送数据,你常见的大致有以下可能:
1,起始的syn包,对于这个包,算它携带1字节长度数据
2,ack包,校验包,接收到消息后回复对方以收到的的包,算它不携带数据
3,psh_ack包,推送数据包,专门携带数据,和确认上次接收的数据无误
4,fin_psh_ack包,用于最后一次传输推送数据,和确认上次接收的数据无误(注意:是上一次接收数据哦,不是上一个包,tcp协议灵活就灵活在这里)
这个算它携带数据再加一字节数据
总结:发送的是带有syn,fin的包都算一字节数据,ack包不算数据,psh包要计算自身携带的数据长度
知识点2
对于发送方(你自己),你发多少数据,你的序列号就增加多少,验证号不变
对于接收方(你自己),你接多少数据,你的验证号就增加多少,序列号不变
所以在处理验证号和序列号时,仅在在自己的角度去想就行,如设置全局变量,发送线程和接收线程两个线程去修改自己的序列号和验证号,实现时要注意控制好两个线程的执行顺序。
2其他知识
2.py threading模块
主要是要用线程事件来控制两个线程之间的执行顺序。
threading里有一个事件类Event(),生成一个全局实例对象后,可用其中的wait()方法使当前线程阻塞,让CPU去执行另一个线程,当在另一个线程里出现该对象的set()方法时,将切换到刚刚阻塞的wait()方法处去执行
3.scapy解析数据包
构建或者sniff()的数据包pkt
,是分层的,seq = pkt[TCP].seq
表示取数据包内的序列号;data = pkt[TCP].payload
表示是取数据包的负载,也就是应用层的http数据
4.数据包里的flags
有好几种类型的包,其值取决于数据包的类型,如psh_ack
其值就取“PA”
代码
之前写的一个关于scapy的帖子,用它自带的sr()发送和接收数据,没弄太懂怎么解析sr()方法返回的数据包的内容,就想着用sniff()另开一个线程试试
from scapy.all import *
from threading import *
from random import *
dport = 80
dst = "192.168.1.1"
sport = randrange(10241,22535)
seq=0
ack=0
###############便捷构造数据包模块函数#########
def createpkt(flags,data=""):
global seq,ack #####引入全局变量############
return IP(dst = dst)/TCP(dport=dport,sport=sport,seq=seq,ack=ack,flags=flags)/data
#################处理接收数据包####################
def a_handle(pkt):
pass
def sa_handle(pkt):
global ack
ack = pkt[TCP].seq+1
def pa_handle(pkt):
global ack
ack += len(pkt[TCP].payload)
def fpa_handle(pkt):
global ack
ack += len(pkt[TCP].payload)+1
################选择哪一个处理方式##################
def handleflag(pkt):
flags=pkt[TCP].flags
print(flags)
if flags == "A":
a_handle(pkt)
elif flags == "SA":
sa_handle(pkt)
event1.set()
elif flags == "PA":
pa_handle(pkt)
elif flags == "FPA":
fpa_handle(pkt) #####发送fin_psh_ack包,开始挥手
event2.set() ####转跳到even2.wait()执行
elif flags == "R":
print("jianting 错误")
#############监听线程入口###################
def sniffdata():
sniff(filter = "src host 192.168.1.1 and tcp port 80",prn = handleflag,iface = 'Ethernet0')
##############设置两个线程事件############
event1 = Event()
event2 = Event()
Thread(target=sniffdata).start() ######开启监听线程
syn = createpkt(flags="S") ######获取第一个包
seq += 1 ####趁监听线程没有回调处理函数(收到数据)之前,修改序列号
send(syn)
event1.wait() ####设置阻塞,等待监听线程回调函数处理接收数据包————修改到正确的确认号,便于下次发包
send(createpkt(flags="A")) #### ack数据包序列号,确认号都不修改,可直接发包
data = "GET / HTTP/1.0/ \r\n\r\n"
psh_ack = createpkt(flags="PA",data=data)
seq += len(data) ###构造数据,计算自己增长多少序列号,然后发包并阻塞
send(psh_ack)
event2.wait()
send(createpkt(flags="A")) ###挥手ack确认
fin_ack = createpkt(flags = "FA")
seq += 1
send(fin_ack) ###发送挥手
####还有一个包,目标机的挥手ack确认包
实现环境
目标机192.168.1.1,80端口,http服务
本机192.168.1.16,python环境,成功安装scapy
wireshark抓包
也不是尽善尽美,不知道为啥挥手时给我发了两次fin包,不过无关紧要,逻辑上没问题即可。
如果有收获就多多关注我吧,哎,一个粉丝都没有,太可怜了。
声明:仅用于技术分享,若私自用于违法活动,与本人无关。
另外:转载请注明出处,创作不易,谢谢啦
ps:本人胆小,怕被警察叔叔请去喝茶。如有不妥,请私信本人,本人立刻删除此贴