负载均衡下的IP伪造

admin 2024年1月4日09:35:45评论52 views字数 4390阅读14分38秒阅读模式
概述


        在当前的网络架构中,负载均衡技术已经被广泛采用以提高系统性能和可靠性。然而,与此同时,我们也面临着一个不可避免的需求,在如防薅羊毛、防账密爆破等场景下,都需要准确地获取客户端IP。这就使得如何下准确地获取并透传客户端IP成为了一个挑战。因此,本文将深入探讨在负载均衡下如何透传客户端IP,并在这个过程中如何有效地防止IP伪造的问题。

01


负载均衡分类



1.1

数据链路层(二层)

简介:负载均衡服务器对外依然提供一个 VIP(虚拟IP),集群中不同的机器采用相同 IP地址,但机器的 MAC 地址不一样。当负载均衡服务器接受到请求之后,通过改写报文的目标 MAC 地址的方式将请求转发到目标机器实现负载均衡。

应用:交换机

1.2

网络层(三层)


简介:和二层负载均衡类似,负载均衡服务器对外依然提供一个 VIP(虚拟IP),但集群中不同的机器采用不同的 IP 地址。当负载均衡服务器接受到请求之后,根据不同的负载均衡算法,通过 IP 将请求转发至不同的真实服务器。

应用:路由器


1.3

传输层(四层)


简介:四层负载均衡工作在 OSI 模型的传输层,由于在传输层,只有 TCP/UDP 协议,这两种协议中除了包含源 IP、目标 IP 以外,还包含源端口号及目的端口号。四层负载均衡服务器在接受到客户端请求后,以后通过修改数据包的地址信息( IP+端口号 )将流量转发到应用服务器。

应用:F5、LVS、Nginx、Haproxy


1.4

应用层(七层)


简介:七层负载均衡工作在 OSI 模型的应用层,应用层协议较多,常用HTTP、FTP、DNS等。七层负载就可以基于这些协议来负载。

应用:Nginx、Haproxy、Apache


02


四层转发模式



2.1

NAT


Network Address Translation(网络地址转换)

SNAT:

SIP(来源IP)变,DIP(目的IP)不变(常见于家庭路由器)

负载均衡下的IP伪造

出现问题:

  • 客户端为何将包发给路由器

解决问题

  • 客户端判断目的IP跟自己是否同一个子网,不是则将目的MAC改成网关MAC发给网关


DNAT:

SIP不变,DIP变

负载均衡下的IP伪造

出现问题:

  • Server直接返回给Client,暴露Server真实IP

  • Client不接受不认识的IP

解决问题:

  • Server先发给LB(负载均衡器),再由LB发给Client

出现问题:

  • Server的目的IP为客户端IP,如何将包发给LB

解决问题:

  • 将DMAC改成LB MAC

存在弊端:

  • 对LB本身性能要求高

  • LB和后端服务必须在同一个子网下


Full NAT:

SIP、DIP都变

负载均衡下的IP伪造

存在弊端:

  • 对LB本身性能要求高

  • 服务端无法获取客户端真实IP


2.2

DSR


Direct Server Return(服务直接返回)

SIP和DIP都不能变,Server直接回复给Client IP

负载均衡下的IP伪造

出现问题:

  • MAC不对如何发给Server

解决问题:

  • 将DMAC改成Server MAC

出现问题:

  • Server发现IP非自己IP进行丢弃

解决问题:

  • 将Server IP和LB IP设置一致

出现问题:

  • LB和Server有相同的IP,如何确保请求冲突问题

解决问题:

  • 让Server完全忽略ARP请求(相当于只自我欺骗不丢包)

存在弊端:

  • LB和Server必须部署在同一个LAN下,LB要通过二层MAC寻址找到Server,不支持走三层

2.3

IP Tunnel


保持源IP包不变,新建一个IP数据包,将原来的IP数据包整体放进新IP数据包内,支持跨网段

负载均衡下的IP伪造

存在弊端:

  • 回包流量不经过LB,LB只有单边流量,导致无法获得TCP完整状态

  • 封装和解封装存在额外的开销

03


透传IP


3.1

四层负载均衡


        如上所述,在四层负载均衡下,如果采用DSR、IP Tunnel、DNAT的负载模式,后端服务器可直接获取到客户端IP,不需要进行IP的透传,而当使用了类似Full NAT的模式,如何透传IP成为了问题,常见有以下两种解决方案。

TOA/UOA:

Tcp Option Address/Udp Option Address

        这里以TOA为例,TOA是一种内核模块,它可以在TCP选项字段中添加一个包含客户端真实IP和端口的选项。

优势:没有变更协议,不会有兼容性问题。

劣势:这需要在负载均衡器和所有后端服务器上安装TOA模块。

流程:

  • 客户端用户请求数据包到达L4(四层LB)时,L4在数据包的tcp option中插入Client IP和Client Port信息

  • 数据包到达后端服务器(装有TOA模块)后,应用程序正常调用getpeername系统函数来获取连接的源端IP地址

  • 由于在toa代码中hook了toa_init相关函数(getpeername系统调用对应的内核处理函数),该函数会从tcp option中获取L4填充的Client信息

  • 只需要在第3次握手ack数据包中插入toa选项即可,后端服务器从ack数据包中解析并获取即可

格式:

        Client IP就是放在tcp option字段中。option字段最长40字节,每个选项由三部分组成:op-kind、op-length、op-data。目前 option 使用的op-kind并不多,我们只需要构建一个不冲突的op-kind就可以把Client IP填充进去。IPv4 地址占用 4 个字节,IPv6占用16字节,填充到option中是没有问题的。

负载均衡下的IP伪造

以IPv4的toa格式为例:

+----------+----------+--------------------+|  opcode  |  opsize  |         port       |+----------+----------+--------------------+|                clientIP                  |+------------------------------------------+

源码:

/* module init */static int __inittoa_init(void){    ...    /* hook funcs for parse and get toa */    hook_toa_functions();    ...}
/* replace the functions with our functions */static inline inthook_toa_functions(void){    /* hook inet_getname for ipv4 */    struct proto_ops *inet_stream_ops_p =            (struct proto_ops *)&inet_stream_ops;        /* hook tcp_v4_syn_recv_sock for ipv4 */    struct inet_connection_sock_af_ops *ipv4_specific_p =            (struct inet_connection_sock_af_ops *)&ipv4_specific;    ...    inet_stream_ops_p->getname = inet_getname_toa;    ...    ipv4_specific_p->syn_recv_sock = tcp_v4_syn_recv_sock_toa;    return 0;}

PROXY Protocol:

        最早于 2010 年被提出,并首先运用于 HAProxy,后续越来越多厂商进行兼容如:Nginx、CDN厂商等。

        Proxy Protocol有v1和v2两个版本,v1版本以明文的字符串发送数据,v2版本以二进制格式发送,以下我们以v1为例进行讨论。

        实现主要是在建立 TCP 连接后, 在发送应用数据之前先将用户的 IP 信息发送到服务端,如v1版本iPv4格式:

PROXY TCP4 [Client IP] [LB IP] [Client Port] [LB Port]rn

红圈:proxy protocol信息

绿圈:真实应用层交互

负载均衡下的IP伪造


3.2

七层负载均衡


        对于七层负载均衡来说,主要通过HTTP的请求头进行透传IP。

X-Forwarded-For:

        当负载均衡器接收到客户端的请求时,它可以在请求的HTTP头部添加一个X-Forwarded-For字段,并将客户端的IP地址放入这个字段。后端服务器可以从X-Forwarded-For字段中读取客户端的真实IP。


X-Real-IP:

        这是另一种常见的方法,类似于X-Forwarded-For。负载均衡器在转发请求时,将客户端的IP地址放入HTTP头部的X-Real-IP字段。

04


利用&防御


4.1

TOA/UOA


利用:

条件:

  • L4产品使用Full NAT模式传递客户端IP

  • 服务器主机启用TOA模块获取IP

原理:L4发现存在TOA不进行覆盖直接传给后端服务

POC:https://gitee.com/vulkey/FakeToa

负载均衡下的IP伪造

成功将IP伪造成8.8.8.8


防御:

TOA由L4进行写入覆盖,不信任用户传来的TOA


4.2

PROXY Protocol


利用:

echo -en "PROXY TCP4 1.2.3.4 1.2.3.4 11 11rnHello World" | nc  -v

黄圈:proxy protocol信息

绿圈:伪造的信息

负载均衡下的IP伪造

防御:

严格按照协议的规定,只取业务数据中最开始的字段


4.3

X-Real-IP


利用:

条件:后端服务通过请求头X-Real-IP中进行获取,而LB未配置

方式:请求时加X-Real-IP头进行伪造。


防御:

Nginx应设置:

proxy_set_header X-Real-IP $remote_addr;


4.4

X-Forwarded-For


利用:nginx配置如下

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

原理:

  • X-Forwarded-For头格式为:X-Forwarded-For: client, proxy1, proxy2

  • 通过X-Forwarded-For中进行获取左一IP作为Client IP

方式:请求时加X-Forwarded-For头进行伪造


防御:

方式一(后端服务角度):从右向左遍历,遍历时可以根据正则表达式剔除掉内网IP和已知的代理服务器本身的IP(例如192.168开头的),那么拿到的第一个非剔除IP就会是一个可信任的客户端IP

方式二(第一层LB角度):Nginx配置为:

proxy_set_header X-Forwarded-For $remote_addr;


总结


        在本文中,我们从四层和七层负载均衡的角度深入探讨了如何透传客户端IP以及如何防止IP伪造的问题。为了确保网络环境的安全性,我们不能盲目信任客户端传过来的信息,而需加以判断,必要时进行覆盖以免影响后端服务。


参考文章:

  • https://gitee.com/vulkey/FakeToa


负载均衡下的IP伪造




负载均衡下的IP伪造





欢迎关注 Asimov攻防实验室


原文始发于微信公众号(Asimov攻防实验室):负载均衡下的IP伪造

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月4日09:35:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   负载均衡下的IP伪造http://cn-sec.com/archives/2349961.html

发表评论

匿名网友 填写信息