什么是SSH?
简单说,SSH是一种 网络协议,用于计算机之间的 加密登录。
如果一个用户从本地计算机,使用SSH协议 登录 另一台远程计算机,我们就可以认为,这种登录是 安全 的,即使 被中途截获,密码也 不会泄露。
最早的时候,互联网通信都是 明文通信,一旦被截获,内容就 暴露无疑。1995年,芬兰学者Tatu Ylonen设计了SSH协议,将登录信息 全部加密,成为互联网安全的一个 基本解决方案,迅速在全世界获得推广,目前已经成为Linux系统的 标准配置。
需要指出的是,SSH只是一种 协议,存在 多种实现,既有 商业实现,也有 开源实现。本文针对的实现是OpenSSH,它是 自由软件,应用非常广泛。
此外,本文只讨论SSH在Linux Shell中的用法。如果要在Windows系统中使用SSH,会用到另一种软件PuTTY,本文不做介绍。
SSH如何工作
该协议在 客户端-服务器 模型中工作,这意味着连接是由连接到SSH服务器的SSH客户端建立的。
SSH 客户端驱动连接设置过程并使用公钥加密来验证SSH服务器的身份。在设置阶段之后,SSH协议使用 强对称加密和散列算法 来确保 客户端 和 服务器 之间交换的数据的 隐私性 和 完整性。
下图显示了安全 shell 连接的简化设置流程。
最基本的用法
SSH 主要用于 远程登录。假定你要以用户名user,登录远程主机host,只要一条简单命令就可以了。
  $ ssh user@host
如果 本地用户名 与 远程用户名 一致,登录时可以 省略 用户名。
  $ ssh host
SSH 的默认端口是22,也就是说,你的登录请求会送进远程主机的22端口。使用p参数,可以修改这个端口。
  $ ssh -p 2222 user@host
上面这条命令表示,ssh直接连接远程主机的2222端口。
中间人攻击
SSH 之所以能够 保证安全,原因在于它采用了 公钥加密。
整个过程是这样的:
-
远程主机收到用户的 登录请求,把 自己的公钥 发给用户。
-
用户使用这个公钥,将 登录密码加密后,发送给远程主机。
-
远程主机用自己的 私钥,解密 登录密码,如果 密码正确,就 同意用户 登录。
这个过程本身是 安全 的,但是实施的时候存在 一个风险:
如果有人 截获 了 登录请求,然后 冒充远程主机,将 伪造 的 公钥 发给用户,那么用户 很难辨别真伪。
因为不像https协议,SSH协议的 公钥 是没有证书中心(CA)公证的,也就是说,都是 自己签发 的。
可以设想,如果 攻击者 插在 用户与远程主机 之间(比如在 公共的wifi区域),用 伪造的公钥,获取用户的 登录密码。
再用这个密码 登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的 中间人攻击(Man-in-the-middle attack)。
SSH 协议是如何应对的呢?
口令登录
如果你是 第一次 登录对方主机,系统会出现下面的提示:
  $ ssh user@host
  The authenticity of host host (12.18.429.21) cant be established.
  RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.
  Are you sure you want to continue connecting (yes/no)?
这段话的意思是,无法确认host主机的真实性,只知道它的 公钥指纹,问你还想 继续连接吗?
所谓 公钥指纹,是指 公钥长度较长(这里采用RSA算法,长达1024位),很难比对,所以对其进行MD5计算,将它变成一个128位的指纹。上例中是98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d,再进行比较,就容易多了。
很自然的 一个问题 就是,用户怎么知道 远程主机 的 公钥指纹 应该是多少?回答是 没有好办法,远程主机 必须在自己的 网站上 贴出 公钥指纹,以便用户 自行核对。
假定经过风险衡量以后,用户 决定接受 这个远程主机的 公钥。
  Are you sure you want to continue connecting (yes/no)? yes
系统会出现一句提示,表示host主机已经得到认可。
  Warning: Permanently added host,12.18.429.21 (RSA) to the list of known hosts.
然后,会要求输入 密码。
Password: (enter password)
如果密码 正确,就可以登录了。
当远程主机的公钥被接受以后,它就会被保存在本地主机文件 $HOME/.ssh/known_hosts 之中。
下次 再连接 这台主机,系统就会认出它的 公钥 已经保存在本地了,从而跳过警告部分,直接提示输入密码。
每个SSH用户都有自己的known_hosts文件,此外系统也有一个这样的文件,通常是/etc/ssh/ssh_known_hosts,保存一些对 所有用户 都可信赖的远程主机的公钥。
公钥登录
使用 密码登录,每次都 必须输入密码,非常麻烦。好在SSH还提供了 公钥登录,可以 省去输入密码 的步骤。
所谓 公钥登录,原理很 简单,就是用户将自己的 公钥 储存在 远程主机上。
登录的时候,远程主机会向用户 发送一段随机字符串,用户用自己的 私钥加密后,再发回来。
远程主机用事先储存的 公钥 进行 解密,如果成功,就证明用户是 可信的,直接允许登录shell,不再要求密码。
这种方法要求用户必须 提供自己的公钥。如果 没有 现成的,可以直接用ssh-keygen 生成一个:
  $ ssh-keygen
运行 上面的命令 以后,系统会出现 一系列提示,可以 一路回车。
其中有一个问题是,要不要对 私钥设置口令(passphrase),如果担心 私钥的安全,这里可以 设置一个。
运行结束以后,在$HOME/.ssh/目录下,会新生成两个文件:id_rsa.pub和id_rsa。
前者 是你的 公钥,后者 是你的 私钥。
这时再输入下面的命令,将公钥传送到远程主机host上面:
  $ ssh-copy-id user@host
好了,从此你再登录,就不需要输入密码了。
如果 还是不行,就打开远程主机的/etc/ssh/sshd_config这个文件,检查下面几行前面 # 注释是否取掉。
  RSAAuthentication yes
  PubkeyAuthentication yes
  AuthorizedKeysFile .ssh/authorized_keys
然后,重启远程主机 的ssh服务。
  # ubuntu系统
  service ssh restart
  # debian系统
  /etc/init.d/ssh restart
authorized_keys文件
远程主机 将 用户 的 公钥,保存在 登录后的用户主目录 的$HOME/.ssh/authorized_keys文件中。
公钥 就是 一段字符串,只要把它追加在authorized_keys文件的 末尾 就行了。
这里不使用上面的ssh-copy-id命令,改用下面的命令,解释公钥的保存过程:
  $ ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
我们来分析一下这条命令:
-
$ ssh user@host
表示登录远程主机; -
单引号中的
mkdir -p .ssh && cat >> .ssh/authorized_keys
表示登录后在远程shell上执行的命令 -
$ mkdir -p .ssh 如果用户主目录中的.ssh目录不存在,就创建一个;
-
cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
作用是,将本地的公钥文件~/.ssh/id_rsa.pub,重定向追加到远程文件authorized_keys的末尾。
写入authorized_keys文件后,公钥登录的设置就完成了。
SSH密码暴力破解
我们明白了SSH的登录原理,那么我们就可以来制作工作来暴力破解SSH密码啦。当然,所有的暴力破解都需要 破解字典 的支持
对于 应用层 以下的协议,scapy是绝对的 神器,但是对于应用层,它就有点吃力啦。。。
现在又要给大家安利一个SSH的Python神器啦,paramiko
- 安装
pip3 install paramio
- 建立
ssh连接
import paramiko
ssh_client=paramiko.SSHClient()
ssh_client.connect(hostname=’hostname’,username='username',password=’mypassword’)
如果不出意料,即使 用户名 和 密码 都正确
还是会报错:
Raises BadHostKeyException,AuthenticationException,
SSHException,socket error
我们回顾一下上面我们讲到的,当2台机器第一次进行SSH连接时候,
远程主机要需要 用户 确认是否信任远程主机的 指纹:
The authenticity of host hostname cant be established.
RSA key fingerprint is key. Are you sure you want to
continue connecting (yes/no)?
用户可以手动选择 是 时,就可以远程连接。
Paramiko 同样要求验证用户对机器的信任。
我们通过调用SSHClient上的set_missing_host_key_policy()并传递在访问新远程计算机时要实现的策略来处理此验证。
默认 情况下,paramiko.SSHclient将策略设置为RejectPolicy。
如上所述,该政策拒绝连接而未经验证。
然而,Paramiko确实为您提供了一种 信任所有 关键策略AutoAddPolicy的方法。
将AutoAddPolicy的实例解析为set_missing_host_key_policy()会将其更改为允许任何主机。
那么代码就如下:
-
我们在
connect方法中加入了cmd可以在登录成功后执行相关 命令 -
执行命令的输入,输出都传入到一个元组保存
-
如果登录成功,返回密码以及执行命令的结果;
-
如果失败,就以另外的
code提示 -
使用 字典 爆破
- 准备一个爆破字典,互联网可以找到很多
- 使用爆破字典的密码进行爆破
相关代码如下:
使用爆破测试一下:
我们 爆破 出了远程主机的密码,并且通过远程 执行命令,发现了对方的 操作系统版本。。但是,实际运用中,这种技术还是 不靠谱的。很大程度上依赖于字典的作用,而且对于 复杂密码,相当 费时。
所以就有了另外的攻击方式,钓鱼攻击 ,之后笔者会与大家分享。
关注笔者公众账号[mindev],并回复 ssh,就能得到 ssh爆破源码 哟~~
愿意与大家分享交流各种技术,个人公众账号[mindev],以及 知识星球[ 极客世界 ]
欢迎订阅公众账号,日更哟~~~