0x00 前言

之前搞蜜罐项目,领导提了一个部署方案:主机器部署蜜罐,其他节点能否在不部署蜜罐的情况下,监听对应端口,能否直接将端口流量转发到蜜罐机器。大致流程如下图所示,故如果有端口的恶意请求到达A/B/C机器,流量转到蜜罐机器,蜜罐机器能记录到相关恶意请求,且蜜罐机器能获取到恶意请求的原始ip

该方案的好处是能做到蜜罐的轻量部署,增加节点也很便捷——直接监听端口然后做转发。但是该方案也带来了新的问题,一个最实际的问题是:A/B/C的恶意请求转发到蜜罐机器后,蜜罐机器如何获取到而已请求的原始ip(攻击者ip)(A/B/C如何透传ip到蜜罐机器),故而解决这个问题是最迫切的。

故笔者花了很长时间对几类端口转发方案进行调研测试。本文对每个方案的部署和配置方法及实践测试结果进行记录。希望能给也在做类似蜜罐方案及在研究端口流量转发透传ip的师傅们一些参考。

0x01 端口流量转发方案调研

文中涉及的机器及ip地址:
Client:192.168.45.36
A-机器:192.168.40.147
B-蜜罐机器:192.168.40.148

1.1 rinetd

官网地址: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蜜罐日志都收集起来,做关联。可达到我们的方案需求。

1.2 haproxy

HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。

1.2.1 haproxy部署(A机器)

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

1.2.2 haproxy实现ip透传

(1) 重新编译haproxy

# 加上关键选项 USE_LINUX_TPROXY=1,打开透传用户IP的代码
make -j $(nproc) PREFIX=/home/ha/haproxy TARGET=linux-glibc USE_LINUX_TPROXY=1 USE_NS=
make install

(2) 配置 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

(3) 配置返回包路由

蜜罐机器路由配置:

# 通过添加这条路由,让后端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

1.2.3 总结

haproxy通过重新编译,以及蜜罐机器修改相关路由,可实现透传效果。但是该方案有两个缺陷:

(1)haproxy目前只支持tcp、http、https等,不支持udp。

(2)该方案需要在蜜罐机器更改路由表,操作起来对蜜罐机器网络会有一定影响,会造成其他更多问题。

1.3 nginx

1.3.1 nginx安装配置

# 安装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

1.3.2 tcp/udp端口转发测试

(1) 测试udp端口连通性

# 转发的目标机器监听udp端口
nc -lu 10000

# 本地扫描机器扫描转发机器的udp端口
netcat -u 192.168.40.148 10000
# 也可用nmap扫描udp端口
nmap -sU -p 10000 192.168.40.148

(2) tcp端口继续用nmap扫描测试

1.3.3 ip透传测试

方案参考这篇文章: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透传。

1.3.4 总结

该方案可实现tcp/udp的ip透传,但是也涉及修改蜜罐机器的相关路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题。

1.4 iptables

1.4.1 iptables 配置

(1) 开启机器的转发功能(A机器):

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

(2) 加入iptables规则(A机器):

源地址发送数据--> {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

1.4.2 本地测试

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

1.4.3 透传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

1.4.4 总结

该方案可实现ip透传,但是涉及修改蜜罐机器默认路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题。

1.5 iptables + gre隧道

1.5.1 开启路由转发及加载内核模块(A机器)

# 开启ipv4路由转发
echo 1 > /proc/sys/net/ipv4/ip_forward

# 加载GRE内核模块
modprobe --first-time ip_gre

1.5.2 开启隧道及添加iptables规则(A机器)

# 开启隧道
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

1.5.3 开启隧道及配置路由(蜜罐机器)

# 开启隧道
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透传效果。参考链接如下:

参考链接:https://superuser.com/questions/1357440/iptables-forwarding-port-s-to-a-external-ip-transparently-remote-end-should-see

1.5.4 总结

该方案算是对蜜罐机器影响较小的一个方案。可尝试在该方案上进行拓展。

0x02 调研结果汇总

序号 方案 特征或缺陷
1 rinetd 无法实现ip透传,无法获取到原始ip(攻击者ip)
2 haproxy (1)haproxy目前只支持tcp、http、https等,不支持udp;
(2)该方案需要在蜜罐机器更改路由表,操作起来对蜜罐机器网络会有一定影响,会造成其他更多问题。
3 nginx 涉及修改蜜罐机器默认路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题
4 iptables 涉及修改蜜罐机器默认路由,操作起来也会对蜜罐机器网络会有一定影响,会造成其他更多问题
5 iptables+gre隧道 该方案算是对蜜罐机器影响较小的一个方案,可尝试在该方案上进行拓展

0x03 后记

方案调研完成后,本想在开源蜜罐上进行实践。但由于目前流行的蜜罐方案(T-Pot、HFish等)便捷的部署方案都是docker部署。容器内都有其独立网络,特别是T-POT,部署完成后,有多个容器,每个容器都是独立网络。若使用上文中可行的端口流量转发方案,T-POT应该是不可行的。配置和处理各个容器的网络非常复杂及繁琐(当然有懂行的大佬觉得可行,虚心请教)。

目前我也没有很好的将端口流量转发与蜜罐进行实践,目前的蜜罐项目也停滞不前了。本文权当一个思路分享吧,并根据这个思路衍生出的一些方案对比测试。也打个广告:如果有在做相关蜜罐项目或使用该方案的师傅们,希望能一起交流一下,迫切想有一个可落地的方案。

点击收藏 | 2 关注 | 2
登录 后跟帖