之前搞蜜罐项目,领导提了一个部署方案:主机器部署蜜罐,其他节点能否在不部署蜜罐的情况下,监听对应端口,能否直接将端口流量转发到蜜罐机器。大致流程如下图所示,故如果有端口的恶意请求到达A/B/C机器,流量转到蜜罐机器,蜜罐机器能记录到相关恶意请求,且蜜罐机器能获取到恶意请求的原始ip。
该方案的好处是能做到蜜罐的轻量部署,增加节点也很便捷——直接监听端口然后做转发。但是该方案也带来了新的问题,一个最实际的问题是:A/B/C的恶意请求转发到蜜罐机器后,蜜罐机器如何获取到而已请求的原始ip(攻击者ip)(A/B/C如何透传ip到蜜罐机器),故而解决这个问题是最迫切的。
故笔者花了很长时间对几类端口转发方案进行调研测试。本文对每个方案的部署和配置方法及实践测试结果进行记录。希望能给也在做类似蜜罐方案及在研究端口流量转发透传ip的师傅们一些参考。
文中涉及的机器及ip地址:
Client:192.168.45.36
A-机器:192.168.40.147
B-蜜罐机器:192.168.40.148
官网地址:https://boutell.com/rinetd/
实践于蜜罐参考文章:https://www.cnblogs.com/Eleven-Liu/p/9204244.html
但是文中说明:蜜罐收集到的日志的访问源IP是我们诱捕节点的ip,不是攻击者所在服务器的ip。文中的思路是:通过syslog的方式把端口转发(rinetd.log)和蜜罐(kippo.log)这两份日志都实时同步至splunk服务器,做关联。
调研结果:由于上述提到的文章中,作者已对rinetd进行测试,无法获取到原始ip,故没有在本地再部署测试。文中说明:A机器经过rinetd将端口转发到蜜罐机器,蜜罐机器收到的攻击ip是A机器的,并非原始ip(攻击者ip)。但文章中的思路还是不错的,将rinetd日志与kippo蜜罐日志都收集起来,做关联。可达到我们的方案需求。
HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。
wget http://www.haproxy.org/download/2.1/src/haproxy-2.1.5.tar.gz tar -xzf haproxy-2.1.5.tar.gz cd haproxy-2.1.5/ # 编译 make -j $(nproc) PREFIX=/home/ha/haproxy TARGET=linux-glibc USE_NS= # 安装 make install
/etc/下新建haproxy目录,目录下新建haproxy.cfg配置文件:
vim /etc/haproxy/haproxy.cfg
配置文件内容如下(监听10000端口转发到192.168.40.148的10000端口):
global
defaults
log global
mode tcp
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend name-in
# 监听10000端口
bind *:10000
default_backend name-out
backend name-out
# 转发
server server1 192.168.40.148 maxconn 20480
运行:
./haproxy -D -f /etc/haproxy/haproxy.cfg
运行结果如下:
可以看到,192.168.40.148的10000端口收到的请求同样是来自40.147的,并不是原始ip。
# 加上关键选项 USE_LINUX_TPROXY=1,打开透传用户IP的代码 make -j $(nproc) PREFIX=/home/ha/haproxy TARGET=linux-glibc USE_LINUX_TPROXY=1 USE_NS= make install
haproxy.cfg
global
defaults
log global
mode tcp
# 加上下行关键配置项
source 0.0.0.0 usesrc clientip
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend name-in
bind *:10000
default_backend name-out
backend name-out
server server1 192.168.40.148 maxconn 20480
蜜罐机器路由配置:
# 通过添加这条路由,让后端server将返回包路由到proxy节点,192.168.40.147为proxy的Ip route add -net 192.168.0.0/16 gw 192.168.40.147
蜜罐机器Proxy路由配置:
/sbin/iptables -F /sbin/iptables -t mangle -N DIVERT /sbin/iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT /sbin/iptables -t mangle -A DIVERT -j MARK --set-mark 1 /sbin/iptables -t mangle -A DIVERT -j ACCEPT /sbin/ip rule add fwmark 1 lookup 100 /sbin/ip route add local 0.0.0.0/0 dev lo table 100 # 通过以上配置,将所有发往Proxy的tcp包,重定向到本地环路(lo)上。然后由TProxy内核补丁来对这些网络包进行处理,进而成功将后端server返回包路由回源客户端
运行结果如下:
可以看到,蜜罐机器拿到的攻击ip是原始ip,可达到透传效果。
原理参考这篇文章:https://blog.csdn.net/frockee/article/details/78641188
haproxy通过重新编译,以及蜜罐机器修改相关路由,可实现透传效果。但是该方案有两个缺陷:
(1)haproxy目前只支持tcp、http、https等,不支持udp。
(2)该方案需要在蜜罐机器更改路由表,操作起来对蜜罐机器网络会有一定影响,会造成其他更多问题。
# 安装nginx yum install nginx # 编辑nginx配置文件 vim /etc/nginx/nginx.conf
nginx.conf
内容如下:
stream { upstream master { # 转发到40.147的10000端口 server 192.168.40.147:10000; } server { # 监听tcp端口9999 listen 9999; # 监听udp端口10000 listen 10000 udp; proxy_timeout 20s; proxy_pass master; proxy_buffer_size 512k; } }
运行nginx:
service nginx start
# 运行后,本地监听了tcp端口9999和udp端口10000
# 转发的目标机器监听udp端口 nc -lu 10000 # 本地扫描机器扫描转发机器的udp端口 netcat -u 192.168.40.148 10000 # 也可用nmap扫描udp端口 nmap -sU -p 10000 192.168.40.148
方案参考这篇文章:https://cloud.tencent.com/developer/article/1449427
在HTTP协议中,可通过X-Forwarded-For
头部传递客户端IP,而TCP与UDP则不行。Proxy protocol
本是一个好的解决方案,它通过在传输层header之上添加一层描述对端的ip和port来解决问题,但nginx目前对Proxy protocol
的支持仅限于tcp协议,并不支持udp协议。
使用文章中的第一种方法(适用于udp和tcp)进行ip透传测试:
蜜罐机器nginx配置:
stream { upstream dns_master { server 192.168.40.147:10000; } server { listen 9999; # listen 10000 udp; proxy_responses 1; proxy_timeout 2s; # 之前使用的nginx/1.10.3版本不支持该配置,会报错: # [emerg] invalid number of arguments in "proxy_bind" directive,故需升级 proxy_bind $remote_addr transparent; proxy_pass dns_master; # proxy_buffer_size 512k; } }
A机器配置:
# 删除原默认网关 route del default gw 192.168.40.1 # 增加默认网关为蜜罐机器ip route add default gw 192.168.40.148
蜜罐机器配置相关路由:
ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100 iptables -t mangle -A PREROUTING -p tcp -s 192.168.0.0/16 --sport 10000 -j MARK --set-xmark 0x1/0xffffffff
该方案可实现ip透传。
该方案可实现tcp/udp的ip透传,但是也涉及修改蜜罐机器的相关路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题。
sysctl net.ipv4.ip_forward # 如果已经启动则显示 > net.ipv4.ip_forward = 1 # 如果没有启动则显示(请按照下面步骤进行开启) > net.ipv4.ip_forward = 0 # CentOS 6/Debian/Ubuntu 开启方式: echo “net.ipv4.ip_forward = 1” >> /etc/sysctl.conf sysctl -p # CentOS 7 开启方式: echo “net.ipv4.ip_forward = 1” >> /usr/lib/sysctl.d/cloudiplc.conf sysctl -p /usr/lib/sysctl.d/cloudiplc.conf
源地址发送数据--> {PREROUTING-->路由规则-->POSTROUTING} -->目的地址接收到数据
iptables -t nat -A PREROUTING -p tcp --dport 10000 -j DNAT --to-destination 192.168.40.148 iptables -t nat -A PREROUTING -p udp --dport 10000 -j DNAT --to-destination 192.168.40.148 iptables -t nat -A POSTROUTING -p tcp -d 192.168.40.148 --dport 10000 -j SNAT --to-source 192.168.40.147 iptables -t nat -A POSTROUTING -p udp -d 192.168.40.148 --dport 10000 -j SNAT --to-source 192.168.40.147 # 说明: # DNAT是destination networkaddress translation的缩写,即目标网络地址转换。 # SNAT是source networkaddress translation的缩写,即源地址目标转换。 # MASQUERADE,地址伪装,算是snat中的一种特例,可以实现自动化的snat。 # 修改后重启生效: # CentOS6: service iptables restart # CentOS7: systemctl restart iptables.service
A机器(192.168.40.147)的10000端口流量转发到B机器(192.168.40.148)的10000端口,配置好相关iptables策略,重启iptables服务:
在B机器(192.168.40.148)监听10000端口,本地请求(telnet)A机器的1000端口会被转发到B机器的10000端口:
可以看到B机器收到了请求,但是请求源ip是A机器的ip,并非本地的原始请求ip。
如下配置可实现ip透传:
# A机器 iptables -t nat -F iptables -t nat -A PREROUTING -p tcp -d 192.168.40.147 --dport 10000 -j DNAT --to 192.168.40.148 iptables -t nat -A POSTROUTING -s 192.168.40.148 SNAT --to 192.168.40.147 # 蜜罐机器 ip route del default ip route add default via 192.168.40.1
该方案可实现ip透传,但是涉及修改蜜罐机器默认路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题。
# 开启ipv4路由转发 echo 1 > /proc/sys/net/ipv4/ip_forward # 加载GRE内核模块 modprobe --first-time ip_gre
# 开启隧道 ip link add gre-y type gre local 192.168.40.147 remote 192.168.40.148 ttl 64 ip link set gre-y up ip addr add 192.168.40.1/24 dev gre-y # 添加iptables DNAT规则 iptables -t nat -I PREROUTING -p tcp --dport 10000 -j DNAT --to-destination 10.1.1.3:10000
# 开启隧道 ip link add gre-x type gre local 192.168.40.148 remote 192.168.40.147 ttl 64 ip link set gre-x up ip addr add 192.168.40.148/24 dev gre-x # 配置策略路由,答复数据包(仅答复数据包)通过隧道 ip route add default via 192.168.40.147 dev gre-x table 1111 ip rule add pref 1000 from 192.168.40.148 lookup 1111
测试结果如下图所示:
可达ip透传效果。参考链接如下:
该方案算是对蜜罐机器影响较小的一个方案。可尝试在该方案上进行拓展。
序号 | 方案 | 特征或缺陷 |
---|---|---|
1 | rinetd | 无法实现ip透传,无法获取到原始ip(攻击者ip) |
2 | haproxy | (1)haproxy目前只支持tcp、http、https等,不支持udp; (2)该方案需要在蜜罐机器更改路由表,操作起来对蜜罐机器网络会有一定影响,会造成其他更多问题。 |
3 | nginx | 涉及修改蜜罐机器默认路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题 |
4 | iptables | 涉及修改蜜罐机器默认路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题 |
5 | iptables+gre隧道 | 该方案算是对蜜罐机器影响较小的一个方案,可尝试在该方案上进行拓展 |
方案调研完成后,本想在开源蜜罐上进行实践。但由于目前流行的蜜罐方案(T-Pot、HFish等)便捷的部署方案都是docker部署。容器内都有其独立网络,特别是T-POT,部署完成后,有多个容器,每个容器都是独立网络。若使用上文中可行的端口流量转发方案,T-POT应该是不可行的。配置和处理各个容器的网络非常复杂及繁琐(当然有懂行的大佬觉得可行,虚心请教)。
目前我也没有很好的将端口流量转发与蜜罐进行实践,目前的蜜罐项目也停滞不前了。本文权当一个思路分享吧,并根据这个思路衍生出的一些方案对比测试。也打个广告:如果有在做相关蜜罐项目或使用该方案的师傅们,希望能一起交流一下,迫切想有一个可落地的方案。