在漫天风沙里望着你远去,我竟悲伤得不能自已,多盼能送君千里,直到山穷水尽,一生和你相依。——《漂洋过海来看你》
昨天去面试,被问如何写一个SSH爆破的检测规则,我当时有点懵逼,一时间不知道该怎么写。
学习一下吧。
什么是SSH
Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。SSH通过在网络中创建安全隧道来实现SSH客户端与服务器之间的连接。虽然任何网络服务都可以通过SSH实现安全传输,SSH最常见的用途是远程登录系统,人们通常利用SSH来传输命令行界面和远程执行命令。使用频率最高的场合类Unix系统,但是Windows操作系统也能有限度地使用SSH。2015年,微软宣布将在未来的操作系统中提供原生SSH协议支持,Windows 10 1809 版本已提供可手动安装的 OpenSSH工具。——《维基百科》
SSH是运行在TCP协议上的应用层协议。
SSH协议是建立在不安全的网络之上的进行远程安全登陆的协议。它是一个协议族,其中有三个子协议,分别是:
- 传输层协议[SSH-TRANS]:提供服务器验证、完整性和保密性功能,建立在传统的TCP/IP协议之上。
- 验证协议[SSH-USERAUTH]:向服务器验证客户端用户,有基于用户名密码和公钥两种验证方式,建立在传输层协议[SSH-TRANS]之上。
- 连接协议[SSH-CONNECT]:将加密隧道复用为若干逻辑信道。它建立在验证协议之上。
SSH认证方式
基于口令的认证
SSH的publish key和private key都是自己生成的,没法公证。通过Client端自己对公钥进行确认。通常在第一次登录的时候,系统会出现下面提示信息:
1 | The authenticity of host '192.168.31.177 (192.168.31.177)' can't be established. |
上面这段话的意思是,无法确认192.168.1.4主机的真实性,只知道它的公钥指纹,问你还想继续连接吗?这样我们就可以看到,SSH是将这个问题抛给了SSH使用者,让SSH使用者自己来确定是否相信远程主机。但是这样对于用户来说,就存在一个难题,用户怎么知道远程主机的公钥指纹是多少;这的确是一个问题,此时就需要远程主机必须公开自己的公钥指纹,以便用户自行核对。
如下已经获取远程主机认可:
1 | Warning: Permanently added '192.168.31.177' (ECDSA) to the list of known hosts. |
输入密码即可。
当远程主机的公钥被接受以后,它就会被保存在文件~/.ssh/known_hosts之中。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。
基于公钥的认证
- Client将自己的公钥存放在Server上,追加在文件authorized_keys中。
- Server端接收到Client的连接请求后,会在authorized_keys中匹配到Client的公钥pubKey,并生成随机数R,用Client的公钥对该随机数进行加密得到pubKey(R),然后将加密后信息发送给Client。
- Client端通过私钥进行解密得到随机数R,然后对随机数R和本次会话的SessionKey利用MD5生成摘要Digest1,发送给Server端。
- Server端会也会对R和SessionKey利用同样摘要算法生成Digest2。
- Server端会最后比较Digest1和Digest2是否相同,完成认证过程
可以参考往GitHub上传自己的SSH keys。
SSH爆破
爆破工具网上有很多,也可以使用 nmap + hydra 的方式进行爆破。
TODO: Golang爆破工具。
Suricata检测SSH爆破
关于Suricata可以参考之前的文章Suricata基础。
针对暴力破解,嵌入了这种能力(例如flowint)。这是因为在Suricata上已经通过使用flowint进行了手动警报规则配置。规则如下:
1 | alert tcp any any -> any any (msg:"Counting Failed Logins"; content:"incorrect"; flowint: username, notset; flowint:username, =, 1; noalert; sid:1;) |
设置阈值
1 | alert tcp any any -> $MY_SSH_SERVER 22 (msg:"Connection to SSH server"; threshold: type threshold, track by_src, count 10, seconds 60,flow:to_server; flags:S,12; sid:888;) |
这条规则的意思是说当同一源在1分钟内有5次ssh,就会产生告警
如何限制SSH爆破
iptables规则限制SSH登录
iptables的原理主要是对数据包的控制。
通过设定时间内限制SSH的连接次数,超过次数之后直接丢弃该包。一次连接的允许的密码错误尝试次数在另外的SSH SERVER设置文件里。
使用:
通过两条规则进行限制:
- iptables -A INPUT -m limit –limit-burst 5
用来比对瞬间大量封包的数量,上面的例子是用来比对一次同时涌入的封包是否超过 5 个(这是默认值),超过此上限的封将被直接丢弃。使用效果同上。
- iptables -A INPUT -m limit –limit 3/hour
用来比对某段时间内数据包的平均流量,上面的例子是用来比对:每小时平均流量是否超过一次3个数据包。 除了每小时平均次外,也可以每秒钟、每分钟或每天平均一次,默认值为每小时平均一次,参数如后: /second、 /minute、/day。 除了进行数据包数量的比对外,设定这个参数也会在条件达成时,暂停数据包的比对动作,以避免因洪水攻击法,导致服务被阻断。
参考: