SSH 协议分析和 wireshark 数据包分析
ssh中文名称叫安全外壳协议,是一种加密的网络传输协议。SSH 在 TCP 和 UDP 中都被分配了端口 22。 但是,由于需要可靠的通信、正确的数据包排序等,该协议主要在 TCP 上运行。
为什么需要SSH?
SSH 和 telnet 之间的主要区别在于 SSH 提供完全加密和经过身份验证的会话。而telnet缺少安全的认证方式,而且传输过程采用TCP进行明文传输,存在很大的安全隐患。单纯提供telnet服务容易招致DoS、主机IP地址欺骗、路由欺骗等。所以在远程登陆上SSH替代telnet,提供更安全可靠的服务。
如何实现数据的安全呢?
我们肯定会想,对于数据,我使用加密就行啦,没错。对于加密机制,主要有两种:
对称密钥加密
非对称密钥加密
广义地说,根据使用的密钥,如果加密与解密使用相同的密钥,则称为对称密钥加密,如果加密与解密使用不同的密钥我们称为非对称密钥加密。
对于对称密钥加密和非对称密钥加密。实际应用过程中会面临一个问题:我们如何确保安全的保存密钥呢?或者说Client端如何保证接受到的公钥就是目标Server端的?下面我们接着讲。
Client端如何保证接受到的公钥就是目标Server端的?
图片来源网上,如果一个攻击者中途拦截Client的登录请求,向其发送自己的公钥。而中间人用自己的假公钥替换掉server的真公钥,这就窃取了Client的登录信息了。这就是中间人攻击。
认证:私钥加密公钥解密;
主要用于身份验证,判断某个身份的真实性。使用私钥加密之后,用对应的公钥解密从而验证身份真实性。
A要验证B是否是真实用户
1、B将自己公钥给A
2、B将文件用自己私钥加密传送给A
3、A根据B的公钥解密,如果成功则为真实身份用户
识别数据发送者和接收者身份客户端验证SSH服务端的身份:防止攻击者仿冒SSH服务端身份,避免中间人攻击和重定向请求的攻击。
OpenSSH 通过在 know-hosts 中存储主机名和 host key 对服务端身份进行认证。
authorized_keys:保存已授权的客户端公钥
id_rsa:保存私钥
id_rsa.pub:保存公钥
known_hosts:保存已认证的远程主机ID
聊一聊SSH的基本框架
SSH协议框架中最主要的部分是三个协议:
- 传输层协议:提供服务器认证,数据机密性,信息完整性等的支持;
- 用户认证协议: 则为服务器提供客户端的身份鉴别;有两种方式,方式一:口令(密码);方式二:证书(公钥)。建立在传输层协议(SSH-TRANS)基础之上。
- 连接协议:连接协议将加密的信息隧道复用成若干个逻辑通道,提供给更高层的应用协议使用。它建立在用户认证协议之上。
下面我们先通过wireshire抓包分析SSH协议。
wireshire抓包分析SSH协议
分析SSH协议上述三个流程,先上个图来瞅一瞅。
TCP三次握手
所有基于TCP的通信都需要从两台主机的握手开始,这样=个握手过程主要希望达到的这样一些目的。
- 保证传输主机可以确定目的主机在线并且进行通信。
- 让传输主机确定目标主机在监听传输主机试图连接的端口。
- 允许传输主机向目标主机发送它的起始序列号,使得两台主机可以将这一个会话保存得井然有序。
主动向通信的设备向目标发送一个TCP数据包,这个数据包的TCP头设置了SYN标志。主机B向这个数据包回复一个类似的SYN和ACK标志以及包含的它的初始序列号的数据包。
最后,主机A向主机B发送最后一个设置ACK标志的数据包,这样就具备所需要正常通信所需的信息。
这个过程属于传输阶段。
SSH版本协商
服务器将自己的SSH协议版本发送到客户端。客户端将自己的SSH协议版本发送到服务器,这些协议是以 ASCII 字符串表示。
如果一个只使用 SSH-1 的客户端连接到一个只使用 SSH-2 的服务器上,那么客户端就会断开连接并打印一条错误消息。
密钥交换
密钥协商过程从客户端和服务器相互发出Key Exchange Init请求开始,主要是告诉对方自己支持的相关加密算法列表、MAC算法列表等。
客户端发送D-H公钥,服务端与客户端使用D-H算法生成会话密钥key。服务端回复,服务端与客户端使用D-H算法生成会话密码key
DH回复包:
- 一个服务端的公钥,即证书,客户端会将该公钥与本地公钥对比,看是否是被信任的服务器,如过是第一次访问则会询问用户是否信任这样的公钥。
- 服务端回复的D-H公钥
- 签名
这个时候,服务端端还会回复一个new Key包 用于表明服务端可以使用会话密码key加密消息了。
客户端要回复服务端的new key包
以表明双方构建了一个加密通道,可以使用会话密码key加密来传输信息了。
这个时候服务器就有了会话密码。接下来就是加密后的数据了,我们无法从中看出任何有用信息。
ssh协议的复杂度也是远超于此的,这里就讲到这里。我们写个代码识别一下SSH协议。
static int ssh_dissect_protocol(u_char *ssh_data,int offset,unsigned int *version,
bool *need_desegmentation,int PayloadLen)
{
int protolen = 0;
int line1 = PayloadLen-1;
int line2 = PayloadLen-2;
if (ssh_data[line2] == 0x0d && ssh_data[line1] == 0x0a)
protolen = PayloadLen - 2;
else
protolen = PayloadLen - 1;
if (strstr((const char *)ssh_data, "SSH-") == NULL){
printf( "Encrypted packet (len=%d)\n", PayloadLen);
offset += PayloadLen;
return offset;
}
if (strstr((const char *)ssh_data, "SSH-2.") == 0)
{
*version = SSH_VERSION_2;
}
else if (strstr((const char *)ssh_data,"SSH-1.99-") == 0)
{
*version = SSH_VERSION_2;
}
else if (strstr((const char *)ssh_data, "SSH-1.") == 0)
{
*version = SSH_VERSION_1;
}
g_version = *version;
char *Proto = (char*)malloc(protolen);
if (Proto == NULL)
{
printf("Failed to apply for memory\n");
return -1;
}
memcpy(Proto, ssh_data + offset,protolen);
Proto[protolen] = '\0';
printf("Protocol (%s)\n",Proto);
offset += protolen;
return offset;
}
void dissect_ssh(u_char *ssh_data,int PayloadLen)
{
int offset = 0;
int i = 0;
unsigned int version = 0;
bool need_desegmentation = false;
if (PayloadLen <= 0)
return;
if (strstr((const char *)ssh_data, "SSH-") != NULL)
{
offset = ssh_dissect_protocol(ssh_data,
offset,&version, &need_desegmentation,PayloadLen);
}
else
{
printf("g_version: %d\n",g_version);
switch(g_version)
{
case SSH_VERSION_UNKNOWN:
printf("Encrypted packet (len=%d)\n", PayloadLen);
break;
case SSH_VERSION_1:
break;
case SSH_VERSION_2:
break;
}
}
}
编译运行:
总结
我在使用SSH登录服务器的时候,即使被中途截获,密码也不会泄露。SSH实现的目的是实现安全远程登录以及其它安全网络服务。对SSH感兴趣的朋友结合SSH协议RFC文档研究。
欢迎关注微信公众号【程序猿编码】,需要SSH源码和报文的添加本人微信号(17865354792)
参考:密码学与网络安全
上一篇: SSH 隧道(SSH 通道)指南
推荐阅读
-
【2022新手指南】Java编程进阶之路 - 六、技术架构篇 ### MySQL索引底层解析与优化实战 - 你会讲解MySQL索引的数据结构吗?性能调优技巧知多少? - Redis深度揭秘:你知道多少?从基础到哨兵、主从复制全梳理 - Redis持久化及哨兵模式详解,还有集群搭建和Leader选举黑箱打开 - Zookeeper是个啥?特性和应用场景大公开 - ZooKeeper集群搭建攻略及 Leader选举、读写一致性、共享锁实现细节 - 探究ZooKeeper中的Leader选举机制及其在分布式环境中的作用 - Zab协议深入剖析:原理、功能与在Zookeeper中的核心地位 - RabbitMQ全方位解读:工作模式、消费限流、可靠投递与配置策略 - 设计者视角:RabbitMQ过期时间、死信队列与延时队列实践指南 - RocketMQ特性和应用场景揭示:理解其精髓与差异化优势 - Kafka详细介绍:特性及广泛应用于实时数据处理的场景解析 - ElasticSearch实力揭秘:特性概述与作为搜索引擎的广泛应用 - MongoDB认知升级:非关系型数据库的优势阐述,安装与使用实战教学 - BIO/NIO/AIO网络模型对比:掌握它们的区别与在网络编程中的实际应用 - Netty带你飞:理解其超快速度背后的秘密,包括线程模型分析 - 网络通信黑科技:Netty编解码原理与常用编解码器的应用,Protostuff实战演示 - 解密Netty粘包与拆包现象,怎样有效应对这一常见问题 - 自定义Netty心跳检测机制,轻松调整检测间隔时间的艺术 - Dubbo轻骑兵介绍:核心特性概览,服务降级实战与其实现益处 - Dubbo三大神器解读:本地存根与本地伪装的实战运用与优势呈现 ----------------------- 七、结语与回顾
-
第 20 课 SPI 协议细节和裸机程序开发分析
-
RTP 协议分析和详情
-
Linux 网络协议栈:NAPI 机制和处理流分析(图解)
-
AXI 协议(V)-AXI-STREAM 和访问思路分析
-
QUIC 协议分析和 HTTP/3.0
-
PKI 和 SSL 协议分析实验报告
-
BGP 协议详细分析和配置华为 (eNSP)
-
BGP 协议概述和数据包分析
-
OpsnSSH 抓包器分析 | SSH 协议分析