- 论坛徽章:
- 0
|
芝麻开门,芝麻关门 Port knocking 简介
需求来源:
家里的Linux主机平时对internet开放着ssh。
经常有人尝试来暴力破解,曾改过ssh的port,好多了,不过这只是模糊安全。也装了fail2ban来限制攻击者的IP,但是攻击者频繁换IP的话fail2ban也没辙。
这次找到了新的方式:Port Knocking,原理很简单,不过挺有创意的。
Port Knocking 简介
为了开放ssh,一般我们让iptables允许ssh进入,不管来自哪里的ip。其实我们只需要为要登录的IP开iptables就可以了(白名单),封锁其他地址对ssh的访问。
可是很多时候不同的外网访问,我们是动态IP,需要让iptables对动态的IP开放SSH如何来实现呢,下面就介绍Port knocking(端口试探/端口碰撞):
Port knocking类似于一次地下组织秘密接头,一种最基本的方式:发送一定序列的UDP、TCP数据包。当运行在主机上的daemon程序捕捉到数据包以后,如果这个序列正确,则开启相应的端口,或者防火墙允许客户端通过。
一次简单的“敲门”流程
1.sshd开放中默认22端口,但是目前防火墙iptables还未允许我的IP通过。
2.Port knocking服务端初始化接头暗号(先敲端口7000再敲8000,TCP协议)和对应操作(对了就对此IP开通ssh的访问)
3.客户端对服务器不同端口进行knock(先7000再8000),发送SYN连接请求。
4.这些端口的连接对上了服务器端就会做些预定义操作为此IP开SSH端口。
5.这时我客户端就可以去连ssh的22端口了。
上面的接头暗号可以是TCP,UDP甚至是ICMP。
借用http://www.portknocking.org/view/about的图示,比较生动形象:
1.默认情况下客户端对服务器的应用由于防火墙不能访问
2.客户端敲正确的端口序列
3.服务器端Port Knocking(PK)程序打开防火墙端口
4.客户端可以访问了
Port Knocking 技术原理
Port knocking会在数据链路层监听所有的网络数据,类似嗅探程序,所以在不开端口,防火墙不允许此端口都可以接受到一定状态的数据包(如TCP SYN,为TCP三次握手第一个报文),当符合规则的报文出现时,规则开始记录,接下去的报文为正确下一个序列继续,错误就清空。当满足一次正确序列时就可以认为是一次event,触发一个action。
Port Knocking 优缺点
优点:
Port knocking 没监听端口,而且也不需要防火墙先开放这些Knock端口,可以隐藏你开放的服务,别人没法知道你是否使用了Port Knocking。
信息是由一定的端口访问顺序来传输的,而不是网络报文内容,所以不容易被报文嗅探工具截获。
阻止0day攻击。当服务器bug还没补丁前,Port Knocking可以做为一层防护。
Port Knocking增加了一层保护,即使在PK和防火墙都失效的情况下,ssh本身的安全验证机制也能很好的保护系统。
缺点:
如果port knocking Daemon挂了话相当于你家的门坏了,有钥匙也进不了。这个称为单点故障,即此服务停止的话整个系统不能工作。不过新的实现一般都检测daemon是否正常。
不是很方便,连ssh前需要先knock下,要使用专门软件,当然很多能发送连接请求的程序都可以的,客户端要对这个端口序列的保密工作,
Port Knocking不能用于Web,Mail。
Port knocking 实践
好,现在是实践下的时候了,search了下yum,发现有个叫knockd软件包(port knocking的实现其实很多的,这里有个列表: http://www.portknocking.org/view/implementations)。
1.ssh管理,根据鸟哥的文章做了下面的配置:
主要思想:
敲对了开端口,敲开门后cmd_timeout超时后再关闭。因为SSH只要在这个时间连接后防火墙关闭SSH端口对已有连接不会有影响。
/etc/knockd.conf
- [options]
- UseSyslog
- [opencloseSSH]
- sequence = 44440:udp,44442:udp,44441:udp
- seq_timeout = 30
- tcpflags = syn,ack
- start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport ssh -j ACCEPT
- cmd_timeout = 300
- stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport ssh -j ACCEPT
复制代码
iptable未开放SSH
- [root@CentOS1 ~]# iptables -nL INPUT
- Chain INPUT (policy ACCEPT)
- target prot opt source destination
- RH-Firewall-1-INPUT all -- 0.0.0.0/0 0.0.0.0/0
复制代码
启动port knocking daemon,这里开了调试和Verbose选项。
- [root@CentOS1 ~]# knockd -D -v
- config: new section: 'options'
- config: usesyslog
- config: new section: 'opencloseSSH'
- config: opencloseSSH: sequence: 44440:udp,44442:udp,44441:udp
- config: opencloseSSH: seq_timeout: 30
- config: tcp flag: SYN
- config: tcp flag: ACK
- config: opencloseSSH: start_command: /sbin/iptables -I INPUT -s %IP% -p tcp --dport ssh -j ACCEPT
- config: opencloseSSH: cmd_timeout: 300
- config: opencloseSSH: stop_command: /sbin/iptables -D INPUT -s %IP% -p tcp --dport ssh -j ACCEPT
- ethernet interface detected
- Local IP: 192.168.1.111
- listening on eth0...
复制代码
客户端来敲下,使用了windows下的程序:
knock的Win32客户端程序:
http://www.zeroflux.org/proj/knock/files/knock-win32.zip
- C:\>knock.exe -v 192.168.1.111 44440:udp 44442:udp 44441:udp
- hitting udp 192.168.1.111:44440
- hitting udp 192.168.1.111:44442
- hitting udp 192.168.1.111:44441
复制代码
服务器端监视到了正确的端口序列,触发动作,OPEN SESAME(芝麻开门!) 开放了SSH端口。
- 2009-09-12 00:27:25: udp: 192.168.1.110:54204 -> 192.168.1.111:44440 60 bytes
- 192.168.1.110: opencloseSSH: Stage 1
- 2009-09-12 00:27:25: udp: 192.168.1.110:54205 -> 192.168.1.111:44442 60 bytes
- 192.168.1.110: opencloseSSH: Stage 2
- 2009-09-12 00:27:25: udp: 192.168.1.110:54206 -> 192.168.1.111:44441 60 bytes
- 192.168.1.110: opencloseSSH: Stage 3
- 192.168.1.110: opencloseSSH: OPEN SESAME
- opencloseSSH: running command: /sbin/iptables -I INPUT -s 192.168.1.110 -p tcp --dport ssh -j ACCEPT
复制代码
iptables中已经加了允许条目。
- [root@CentOS1 ~]# iptables -nL INPUT
- Chain INPUT (policy ACCEPT)
- target prot opt source destination
- ACCEPT tcp -- 192.168.1.110 0.0.0.0/0 tcp dpt:22
- RH-Firewall-1-INPUT all -- 0.0.0.0/0 0.0.0.0/0
复制代码
这个时候我的ssh客户端就可以登录了。
超过门敲开后的时间自动关闭。很安全的自动门吧。
- 192.168.1.110: opencloseSSH: command timeout
- opencloseSSH: running command: /sbin/iptables -D INPUT -s 192.168.1.110 -p tcp --dport ssh -j ACCEPT
复制代码
2.ftp管理:ftp这个古老的协议虽然不安全,但是传输效率无疑是比较高的。
这里vsftpd命令端口监听在默认的21端口,数据传输使用passive模式,开放在5000~50010,初始情况下iptables不允许对21的访问。
建立两个port knocking序列,一个开,一个关。
/etc/knockd.conf
- [options]
- UseSyslog
- [openFTPControl]
- sequence = 55540:tcp,55542:tcp,55541:tcp
- seq_timeout = 30
- tcpflags = syn
- command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport ftp -j ACCEPT
- [closeFTPControl]
- sequence = 55541:tcp,55542:tcp,55540:tcp
- seq_timeout = 30
- tcpflags = syn
- command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport ftp -j ACCEPT
复制代码
Port knock服务器启动:
- [root@CentOS1 ~]# knockd -D -v
- config: new section: 'options'
- config: usesyslog
- config: new section: 'openFTPControl'
- config: openFTPControl: sequence: 55540:tcp,55542:tcp,55541:tcp
- config: openFTPControl: seq_timeout: 30
- config: tcp flag: SYN
- config: openFTPControl: start_command: /sbin/iptables -I INPUT -s %IP% -p tcp --dport ftp -j ACCEPT
- config: new section: 'closeFTPControl'
- config: closeFTPControl: sequence: 55541:tcp,55542:tcp,55540:tcp
- config: closeFTPControl: seq_timeout: 30
- config: tcp flag: SYN
- config: closeFTPControl: start_command: /sbin/iptables -D INPUT -s %IP% -p tcp --dport ftp -j ACCEPT
- ethernet interface detected
- Local IP: 192.168.1.111
- listening on eth0...
复制代码
客户端knock下
- C:\>knock -v 192.168.1.111 55540:tcp 55542:tcp 55541:tcp
- hitting tcp 192.168.1.111:55540
- hitting tcp 192.168.1.111:55542
- hitting tcp 192.168.1.111:55541
复制代码
服务器收到正确序列,执行动作,打开ftp端口。
- 2009-09-12 22:42:22: tcp: 192.168.1.110:51808 -> 192.168.1.111:55540 66 bytes
- 192.168.1.110: openFTPControl: Stage 1
- 2009-09-12 22:42:22: tcp: 192.168.1.110:51809 -> 192.168.1.111:55542 66 bytes
- 192.168.1.110: openFTPControl: Stage 2
- 2009-09-12 22:42:22: tcp: 192.168.1.110:51810 -> 192.168.1.111:55541 66 bytes
- 192.168.1.110: openFTPControl: Stage 3
- 192.168.1.110: openFTPControl: OPEN SESAME
- openFTPControl: running command: /sbin/iptables -I INPUT -s 192.168.1.110 -p tcp --dport ftp -j ACCEPT
复制代码
这个时候客户端可以ftp登录,通过原来开放的数据传输端口传文件。
使用完毕,通过另一个knock序列关闭ftp端口
- C:\>knock -v 192.168.1.111 55541:tcp 55542:tcp 55540:tcp
- hitting tcp 192.168.1.111:55541
- hitting tcp 192.168.1.111:55542
- hitting tcp 192.168.1.111:55540
复制代码
服务器端关闭ftp端口。
- removing successful knock attempt (192.168.1.110)
- 192.168.1.110: closeFTPControl: Stage 1
- 2009-09-12 22:49:08: tcp: 192.168.1.110:51917 -> 192.168.1.111:55542 66 bytes
- 192.168.1.110: closeFTPControl: Stage 2
- 2009-09-12 22:49:08: tcp: 192.168.1.110:51918 -> 192.168.1.111:55540 66 bytes
- 192.168.1.110: closeFTPControl: Stage 3
- 192.168.1.110: closeFTPControl: OPEN SESAME
- closeFTPControl: running command: /sbin/iptables -D INPUT -s 192.168.1.110 -p tcp --dport ftp -j ACCEPT
复制代码
家庭实际使用中,一般会有路由器,典型的网络拓扑:
knock服务器是运行在最好直接运行在路由器上,比如我刷dd-wrt的linksys WRT54G就可以。
参见: http://www.dd-wrt.com/wiki/index.php/Knockd
另一种适合大家的方法是在路由器做NAT,knock服务器程序运行在内网Linux中。
以ssh为例,我们就需要为外网能knock到CentOS1(IP:192.168.1.111),成功后能访问ssh,需在路由器中设定NAT(Port forwarding)。
SSH, knock port 44440~44442
当然你自己内网访问就不需要每次连接前knock下这么麻烦了,在防火墙规则里加条允许内网的ssh和ftp的连接。
- iptables -I INPUT -s 192.168.1.0/24 -p tcp --dport 21 -j ACCEPT
- iptables -I INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT
复制代码
可以将knockd配置成initd service的方式以方便开机启动,这个就交给大家自己实现了。
文中提到的有些信息就不细讲了,请参考:
1) 一般sshd 安全配置:
http://www.foogazi.com/2006/11/2 ... -maximize-security/
2) fail2ban使用
http://www.fail2ban.org/wiki/index.php/Main_Page
3) portknocking介绍
http://www.portknocking.org/view/about
4) 本文使用的Port knocking实现
http://www.zeroflux.org/projects/knock
5) 鸟哥图文并茂的介绍:
http://linux.vbird.org/linux_security/knockd.php
[ 本帖最后由 可可火山 于 2009-10-14 13:10 编辑 ] |
|