之前为了自己做一套SSH,先自己实现了一套telnet。但经过这么多天的苦逼,发现以前的工作都是徒劳。ssh的协议很繁杂,核心的内容在于密码算法,而且自己很难在网上找到周全的细节讲解与详细的实现,只有靠自己刷RFC和问大神还有就是靠强X我的服务器艰难地完成。
现计算了下时间,自己做SSH耗费了进两个月的时间,虽然期间也夹着其他的繁杂事物,但自己在这方面确是是耗费了非常大的精力。因为这方面详细资料的匮乏,自己以前也几乎没有接触过密码学方面的东西,很多只有靠自己摸索,所以我得经常拿我自己的服务器来做黑盒测试,我现在服务器上的ss服务器日志全是一些非法连接的记录(—_—|||)。早知当初就不那么作死非要自己实现他的加密算法和过程,用openssl就很快搞定了。但我还是觉得这次做SSH的精力是我受益匪浅,不仅熟悉了各种加密,并且能靠自己实现并熟练应用了。可能这些对自己帮助不大,但至少和信安的小伙伴也有点吹牛的谈资了~
这篇文章希望能帮助到想了解ssh2.0协议或是亲手实现ssh协议的小伙伴。
首先对数据包的格式进行说明:
数据包由包长度(Packet Length)、填充长读(Padding Length)、信息代码(Msg code)、信息内容与填充值(Padding String) 这5部分组成。信息内容中的一些字符串以4字节长度+该长度数量的字符组成,数值按照网络序排列,例如:abc: 00 00 00 03 (char)a (char)b (char)c 。另外有一种大整数的情况,负数和字符串的表示方式一样,正数需要前导0,例如 4b64: 00 00 00 03 00 4b 64 。
ssh头的结构体:
struct sshhead
{
unsigned int tlen;
unsigned char plen;
unsigned char msgcode;
sshhead(){tlen=6;}
};
就拿通过ssh远程控制的一个完整个过程来讲,ssh的过程可分为以下3部分:
一、版本协商
二、算法协商与密钥交换
三、加密通信(可能含有2、3部分)
这其中第二部分是ssh最为核心的过程,该过程决定了以后通信所要使用的密钥,下面按顺序对每个部分对比着数据包进行详细的讲解并给出实现的过程。
一、版本协商:
在建立连接后,客户端与服务器分别向对方发送自己ssh的版本信息(这里的数据格式不同于其他包,只有一行版本号),以\r\n结束。版本的格式如下:
SSH-ssh协议版本-详细版本\r\n (几乎只有ssh协议版本之前的信息有效)
比如我linux上的就是:SSH-2.0-OpenSSH_5.3\r\n
Putty的是: SSH-2.0-PuTTY_Release_0.63\r\n
一般来说,在建立连接后,是先由服务器发版本号过来,单线程处理版本协商的朋友需要注意下。
在双方收到对方发来的版本号后,会根据两者之中最小的版本来进行接下来的通讯。
二、算法协商与秘钥交换:
这部分的内容将会占该文章总篇幅的一半以上。
首先给大家看下整个过程的数据包大概:
整个部分是从第6条开始到第15条结束,除去中间的非协议部分,总共有7条数据包。看起来只有这么几条数据包,但其中包含了非常多的过程与隐秘的信息。
1、算法协商:
位第6、9数据,分别为双发向对法发送的自己在不同密码需求上支持的算法。
该数据包的格式:
按顺序分别是:
cookie(随机的值,16byte)
kex_algorithms(秘钥租交换算法)
server_host_key_algorithms(服务器主机秘钥,正常情况用处不大,甚至可以不用)
encryption_algorithms_client_to_server(两端通信使用的加密算法)
encryption_algorithms_server_to_client
mac_algorithms_client_to_server(数据校验用的hash算法)
mac_algorithms_server_to_client
compression_algorithms_client_to_server(压缩算法)
compression_algorithms_server_to_client
languages_client_to_server
languages_server_to_client
first_kex_packet_follows
0(4byte整数,扩展用的)
每个算法类型可能会有多个不同的算法,这些算法之间使用逗号隔开。