SSH爆破检测规则

在漫天风沙里望着你远去,我竟悲伤得不能自已,多盼能送君千里,直到山穷水尽,一生和你相依。——《漂洋过海来看你》

昨天去面试,被问如何写一个SSH爆破的检测规则,我当时有点懵逼,一时间不知道该怎么写。

学习一下吧。

什么是SSH

Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。SSH通过在网络中创建安全隧道来实现SSH客户端与服务器之间的连接。虽然任何网络服务都可以通过SSH实现安全传输,SSH最常见的用途是远程登录系统,人们通常利用SSH来传输命令行界面和远程执行命令。使用频率最高的场合类Unix系统,但是Windows操作系统也能有限度地使用SSH。2015年,微软宣布将在未来的操作系统中提供原生SSH协议支持,Windows 10 1809 版本已提供可手动安装的 OpenSSH工具。——《维基百科

SSH是运行在TCP协议上的应用层协议。

SSH协议是建立在不安全的网络之上的进行远程安全登陆的协议。它是一个协议族,其中有三个子协议,分别是:

  1. 传输层协议[SSH-TRANS]:提供服务器验证、完整性和保密性功能,建立在传统的TCP/IP协议之上。
  2. 验证协议[SSH-USERAUTH]:向服务器验证客户端用户,有基于用户名密码和公钥两种验证方式,建立在传输层协议[SSH-TRANS]之上。
  3. 连接协议[SSH-CONNECT]:将加密隧道复用为若干逻辑信道。它建立在验证协议之上。

SSH认证方式

基于口令的认证

SSH的publish key和private key都是自己生成的,没法公证。通过Client端自己对公钥进行确认。通常在第一次登录的时候,系统会出现下面提示信息:

1
2
3
The authenticity of host '192.168.31.177 (192.168.31.177)' can't be established.
ECDSA key fingerprint is SHA256:z0zrUwb0IOaQesVyNdZ8b5A/HKgdNSy1HnM8sWo1u6E.
Are you sure you want to continue connecting (yes/no)?

上面这段话的意思是,无法确认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之中。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。

基于公钥的认证

  1. Client将自己的公钥存放在Server上,追加在文件authorized_keys中。
  2. Server端接收到Client的连接请求后,会在authorized_keys中匹配到Client的公钥pubKey,并生成随机数R,用Client的公钥对该随机数进行加密得到pubKey(R),然后将加密后信息发送给Client。
  3. Client端通过私钥进行解密得到随机数R,然后对随机数R和本次会话的SessionKey利用MD5生成摘要Digest1,发送给Server端。
  4. Server端会也会对R和SessionKey利用同样摘要算法生成Digest2。
  5. Server端会最后比较Digest1和Digest2是否相同,完成认证过程

可以参考往GitHub上传自己的SSH keys。

SSH爆破

爆破工具网上有很多,也可以使用 nmap + hydra 的方式进行爆破。

TODO: Golang爆破工具。

Suricata检测SSH爆破

关于Suricata可以参考之前的文章Suricata基础

针对暴力破解,嵌入了这种能力(例如flowint)。这是因为在Suricata上已经通过使用flowint进行了手动警报规则配置。规则如下:

1
2
alert tcp any any -> any any (msg:"Counting Failed Logins"; content:"incorrect"; flowint: username, notset; flowint:username, =, 1; noalert; sid:1;)
alert tcp any any -> any any (msg:"More than two Failed Logins!"; content:"incorrect"; flowint: username, isset; flowint:username, +, 1; flowint:username, >, 2; sid:2;)

设置阈值

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设置文件里。

使用:

通过两条规则进行限制:

  1. iptables -A INPUT -m limit –limit-burst 5

用来比对瞬间大量封包的数量,上面的例子是用来比对一次同时涌入的封包是否超过 5 个(这是默认值),超过此上限的封将被直接丢弃。使用效果同上。

  1. iptables -A INPUT -m limit –limit 3/hour

用来比对某段时间内数据包的平均流量,上面的例子是用来比对:每小时平均流量是否超过一次3个数据包。 除了每小时平均次外,也可以每秒钟、每分钟或每天平均一次,默认值为每小时平均一次,参数如后: /second、 /minute、/day。 除了进行数据包数量的比对外,设定这个参数也会在条件达成时,暂停数据包的比对动作,以避免因洪水攻击法,导致服务被阻断。

参考: