diff -Nru openssh-7.5p1/debian/changelog openssh-7.5p1/debian/changelog --- openssh-7.5p1/debian/changelog 2017-09-01 10:17:19.000000000 +0000 +++ openssh-7.5p1/debian/changelog 2018-01-26 05:48:29.000000000 +0000 @@ -1,3 +1,20 @@ +openssh (1:7.5p1-10ubuntu0.1ppa1+obfuscated~artful1) artful; urgency=medium + + * Add handshake obfuscation + - debian/patches/obfuscated-handshake.patch + - debian/openssh-server.postinst + + -- zinglau Fri, 26 Jan 2018 13:47:29 +0800 + +openssh (1:7.5p1-10ubuntu0.1) artful-security; urgency=medium + + * SECURITY UPDATE: DoS via zero-length file creation in readonly mode + - debian/patches/CVE-2017-15906.patch: disallow creation of empty files + in sftp-server.c. + - CVE-2017-15906 + + -- Marc Deslauriers Tue, 16 Jan 2018 08:28:47 -0500 + openssh (1:7.5p1-10) unstable; urgency=medium * Tell haveged to create the pid file we expect. diff -Nru openssh-7.5p1/debian/control openssh-7.5p1/debian/control --- openssh-7.5p1/debian/control 2017-08-28 11:14:20.000000000 +0000 +++ openssh-7.5p1/debian/control 2018-01-16 13:28:47.000000000 +0000 @@ -1,7 +1,8 @@ Source: openssh Section: net Priority: standard -Maintainer: Debian OpenSSH Maintainers +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian OpenSSH Maintainers Build-Depends: autotools-dev, debhelper (>= 9~), dh-autoreconf, diff -Nru openssh-7.5p1/debian/patches/CVE-2017-15906.patch openssh-7.5p1/debian/patches/CVE-2017-15906.patch --- openssh-7.5p1/debian/patches/CVE-2017-15906.patch 1970-01-01 00:00:00.000000000 +0000 +++ openssh-7.5p1/debian/patches/CVE-2017-15906.patch 2018-01-16 13:28:45.000000000 +0000 @@ -0,0 +1,27 @@ +Backport of: + +From a6981567e8e215acc1ef690c8dbb30f2d9b00a19 Mon Sep 17 00:00:00 2001 +From: djm +Date: Tue, 4 Apr 2017 00:24:56 +0000 +Subject: [PATCH] disallow creation (of empty files) in read-only mode; + reported by Michal Zalewski, feedback & ok deraadt@ + +--- + usr.bin/ssh/sftp-server.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: openssh-7.5p1/sftp-server.c +=================================================================== +--- openssh-7.5p1.orig/sftp-server.c 2018-01-16 08:28:42.554824134 -0500 ++++ openssh-7.5p1/sftp-server.c 2018-01-16 08:28:42.550824131 -0500 +@@ -691,8 +691,8 @@ process_open(u_int32_t id) + logit("open \"%s\" flags %s mode 0%o", + name, string_from_portable(pflags), mode); + if (readonly && +- ((flags & O_ACCMODE) == O_WRONLY || +- (flags & O_ACCMODE) == O_RDWR)) { ++ ((flags & O_ACCMODE) != O_RDONLY || ++ (flags & (O_CREAT|O_TRUNC)) != 0)) { + verbose("Refusing open request in read-only mode"); + status = SSH2_FX_PERMISSION_DENIED; + } else { diff -Nru openssh-7.5p1/debian/patches/obfuscated-handshake.patch openssh-7.5p1/debian/patches/obfuscated-handshake.patch --- openssh-7.5p1/debian/patches/obfuscated-handshake.patch 1970-01-01 00:00:00.000000000 +0000 +++ openssh-7.5p1/debian/patches/obfuscated-handshake.patch 2018-01-26 05:47:12.000000000 +0000 @@ -0,0 +1,880 @@ +Description: Add handshake obfuscation +Author: zinglau +Index: openssh-7.5p1/Makefile.in +=================================================================== +--- openssh-7.5p1.orig/Makefile.in ++++ openssh-7.5p1/Makefile.in +@@ -93,7 +93,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ + kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ + kexgssc.o \ +- platform-pledge.o platform-tracing.o ++ platform-pledge.o platform-tracing.o obfuscate.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o +Index: openssh-7.5p1/kex.c +=================================================================== +--- openssh-7.5p1.orig/kex.c ++++ openssh-7.5p1/kex.c +@@ -392,9 +392,12 @@ kex_send_newkeys(struct ssh *ssh) + debug("SSH2_MSG_NEWKEYS sent"); + debug("expecting SSH2_MSG_NEWKEYS"); + ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); +- if (ssh->kex->ext_info_c) ++ if (ssh->kex->ext_info_c) { ++ sshpkt_disable_obfuscation(); + if ((r = kex_send_ext_info(ssh)) != 0) + return r; ++ sshpkt_enable_obfuscation(); ++ } + return 0; + } + +@@ -457,6 +460,7 @@ kex_input_newkeys(int type, u_int32_t se + kex->flags &= ~KEX_INIT_SENT; + free(kex->name); + kex->name = NULL; ++ sshpkt_disable_obfuscation(); + return 0; + } + +Index: openssh-7.5p1/obfuscate.c +=================================================================== +--- /dev/null ++++ openssh-7.5p1/obfuscate.c +@@ -0,0 +1,216 @@ ++#include "includes.h" ++#include ++#include ++#include ++#include ++#include "atomicio.h" ++#include "canohost.h" ++#include "xmalloc.h" ++#include "log.h" ++#include "packet.h" ++#include "obfuscate.h" ++ ++static RC4_KEY rc4_input; ++static RC4_KEY rc4_output; ++ ++static const char *obfuscate_keyword = NULL; ++ ++#define OBFUSCATE_KEY_LENGTH 16 ++#define OBFUSCATE_SEED_LENGTH 16 ++#define OBFUSCATE_HASH_ITERATIONS 6000 ++#define OBFUSCATE_MAX_PADDING 8192 ++#define OBFUSCATE_MAGIC_VALUE 0x0BF5CA7E ++ ++struct seed_msg { ++ u_char seed_buffer[OBFUSCATE_SEED_LENGTH]; ++ u_int32_t magic; ++ u_int32_t padding_length; ++ u_char padding[]; ++}; ++ ++static void generate_key_pair(const u_char *, u_char *, u_char *); ++static void generate_key(const u_char *, const u_char *, u_int, u_char *); ++static void set_keys(const u_char *, const u_char *); ++static void initialize(const u_char *, int); ++static void read_forever(int); ++ ++ ++/* ++ * Server calls this ++ */ ++void ++obfuscate_receive_seed(struct ssh *ssh, int sock_in) ++{ ++ struct seed_msg seed; ++ ++ u_char padding_drain[OBFUSCATE_MAX_PADDING]; ++ u_int len; ++ u_int32_t padding_length; ++ ++ len = atomicio(read, sock_in, &seed, sizeof(struct seed_msg)); ++ ++ debug2("obfuscate_receive_seed: read %d byte seed message from client", len); ++ if(len != sizeof(struct seed_msg)) ++ fatal("obfuscate_receive_seed: read failed"); ++ ++ initialize(seed.seed_buffer, 1); ++ obfuscate_input((u_char *)&seed.magic, 8); ++ ++ if(OBFUSCATE_MAGIC_VALUE != ntohl(seed.magic)) { ++ logit("Magic value check failed (%u) on obfuscated handshake " ++ "from %.200s port %d", ntohl(seed.magic), ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); ++ read_forever(sock_in); ++ } ++ padding_length = ntohl(seed.padding_length); ++ if(padding_length > OBFUSCATE_MAX_PADDING) { ++ logit("Illegal padding length %d for obfuscated handshake " ++ "from %.200s port %d", ntohl(seed.padding_length), ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); ++ read_forever(sock_in); ++ } ++ len = atomicio(read, sock_in, padding_drain, padding_length); ++ if(len != padding_length) ++ fatal("obfuscate_receive_seed: read failed"); ++ debug2("obfuscate_receive_seed: read %d bytes of padding from client.", len); ++ obfuscate_input(padding_drain, padding_length); ++} ++ ++/* ++ * Client calls this ++ */ ++void ++obfuscate_send_seed(int sock_out) ++{ ++ struct seed_msg *seed; ++ int i; ++ u_int32_t rnd = 0; ++ u_int message_length; ++ u_int padding_length; ++ ++ padding_length = arc4random() % OBFUSCATE_MAX_PADDING; ++ message_length = padding_length + sizeof(struct seed_msg); ++ seed = xmalloc(message_length); ++ ++ for(i = 0; i < OBFUSCATE_SEED_LENGTH; i++) { ++ if(i % 4 == 0) ++ rnd = arc4random(); ++ seed->seed_buffer[i] = rnd & 0xff; ++ rnd >>= 8; ++ } ++ seed->magic = htonl(OBFUSCATE_MAGIC_VALUE); ++ seed->padding_length = htonl(padding_length); ++ for(i = 0; i < (int)padding_length; i++) { ++ if(i % 4 == 0) ++ rnd = arc4random(); ++ seed->padding[i] = rnd & 0xff; ++ } ++ initialize(seed->seed_buffer, 0); ++ obfuscate_output(((u_char *)seed) + OBFUSCATE_SEED_LENGTH, ++ message_length - OBFUSCATE_SEED_LENGTH); ++ debug2("obfuscate_send_seed: Sending seed message with %d bytes of padding", padding_length); ++ atomicio(vwrite, sock_out, seed, message_length); ++ free(seed); ++ ++} ++ ++void ++obfuscate_set_keyword(const char *keyword) ++{ ++ debug2("obfuscate_set_keyword: Setting obfuscation keyword to '%s'", keyword); ++ obfuscate_keyword = keyword; ++} ++ ++void ++obfuscate_input(u_char *buffer, u_int buffer_len) ++{ ++ RC4(&rc4_input, buffer_len, buffer, buffer); ++} ++ ++void ++obfuscate_output(u_char *buffer, u_int buffer_len) ++{ ++ RC4(&rc4_output, buffer_len, buffer, buffer); ++} ++ ++static void ++initialize(const u_char *seed, int server) ++{ ++ u_char client_to_server_key[OBFUSCATE_KEY_LENGTH]; ++ u_char server_to_client_key[OBFUSCATE_KEY_LENGTH]; ++ ++ generate_key_pair(seed, client_to_server_key, server_to_client_key); ++ ++ if(server) ++ set_keys(client_to_server_key, server_to_client_key); ++ else ++ set_keys(server_to_client_key, client_to_server_key); ++} ++ ++static void ++generate_key_pair(const u_char *seed, u_char *client_to_server_key, u_char *server_to_client_key) ++{ ++ generate_key(seed, "client_to_server", strlen("client_to_server"), client_to_server_key); ++ generate_key(seed, "server_to_client", strlen("server_to_client"), server_to_client_key); ++} ++ ++static void ++generate_key(const u_char *seed, const u_char *iv, u_int iv_len, u_char *key_data) ++{ ++ EVP_MD_CTX ctx; ++ u_char md_output[EVP_MAX_MD_SIZE]; ++ int md_len; ++ int i; ++ u_char *buffer; ++ u_char *p; ++ u_int buffer_length; ++ ++ buffer_length = OBFUSCATE_SEED_LENGTH + iv_len; ++ if(obfuscate_keyword) ++ buffer_length += strlen(obfuscate_keyword); ++ ++ p = buffer = xmalloc(buffer_length); ++ ++ memcpy(p, seed, OBFUSCATE_SEED_LENGTH); ++ p += OBFUSCATE_SEED_LENGTH; ++ ++ if(obfuscate_keyword) { ++ memcpy(p, obfuscate_keyword, strlen(obfuscate_keyword)); ++ p += strlen(obfuscate_keyword); ++ } ++ memcpy(p, iv, iv_len); ++ ++ EVP_DigestInit(&ctx, EVP_sha1()); ++ EVP_DigestUpdate(&ctx, buffer, OBFUSCATE_SEED_LENGTH + iv_len); ++ EVP_DigestFinal(&ctx, md_output, &md_len); ++ ++ free(buffer); ++ ++ for(i = 0; i < OBFUSCATE_HASH_ITERATIONS; i++) { ++ EVP_DigestInit(&ctx, EVP_sha1()); ++ EVP_DigestUpdate(&ctx, md_output, md_len); ++ EVP_DigestFinal(&ctx, md_output, &md_len); ++ } ++ ++ if(md_len < OBFUSCATE_KEY_LENGTH) ++ fatal("Cannot derive obfuscation keys from hash length of %d", md_len); ++ ++ memcpy(key_data, md_output, OBFUSCATE_KEY_LENGTH); ++} ++ ++static void ++set_keys(const u_char *input_key, const u_char *output_key) ++{ ++ RC4_set_key(&rc4_input, OBFUSCATE_KEY_LENGTH, input_key); ++ RC4_set_key(&rc4_output, OBFUSCATE_KEY_LENGTH, output_key); ++} ++ ++static void ++read_forever(int sock_in) ++{ ++ u_char discard_buffer[1024]; ++ ++ while(atomicio(read, sock_in, discard_buffer, sizeof(discard_buffer)) > 0) ++ ; ++ cleanup_exit(255); ++} +Index: openssh-7.5p1/obfuscate.h +=================================================================== +--- /dev/null ++++ openssh-7.5p1/obfuscate.h +@@ -0,0 +1,10 @@ ++#ifndef _OBFUSCATE_H ++#define _OBFUSCATE_H ++ ++void obfuscate_receive_seed(struct ssh *, int); ++void obfuscate_send_seed(int); ++void obfuscate_set_keyword(const char *); ++void obfuscate_input(u_char *, u_int); ++void obfuscate_output(u_char *, u_int); ++ ++#endif +Index: openssh-7.5p1/packet.c +=================================================================== +--- openssh-7.5p1.orig/packet.c ++++ openssh-7.5p1/packet.c +@@ -83,6 +83,7 @@ + #include "channels.h" + #include "ssh.h" + #include "packet.h" ++#include "obfuscate.h" + #include "ssherr.h" + #include "sshbuf.h" + +@@ -170,6 +171,8 @@ struct session_state { + /* Set to true if we are authenticated. */ + int after_authentication; + ++ int obfuscation; ++ + int keep_alive_timeouts; + + /* The maximum time that we will wait to send or receive a packet */ +@@ -838,6 +841,8 @@ ssh_packet_set_encryption_key(struct ssh + error("Warning: %s", wmsg); + state->cipher_warning_done = 1; + } ++ if(state->obfuscation) ++ sshpkt_disable_obfuscation(); + #endif /* WITH_SSH1 */ + } + +@@ -914,6 +919,8 @@ ssh_packet_send1(struct ssh *ssh) + sshbuf_ptr(state->outgoing_packet), + sshbuf_len(state->outgoing_packet), 0, 0)) != 0) + goto out; ++ if(state->obfuscation) ++ obfuscate_output(cp, sshbuf_len(state->outgoing_packet)); + + #ifdef PACKET_DEBUG + fprintf(stderr, "encrypted: "); +@@ -1274,6 +1281,8 @@ ssh_packet_send2_wrapped(struct ssh *ssh + if ((r = sshbuf_put(state->output, macbuf, mac->mac_len)) != 0) + goto out; + } ++ if(state->obfuscation) ++ obfuscate_output(cp, sshbuf_len(state->outgoing_packet)); + #ifdef PACKET_DEBUG + fprintf(stderr, "encrypted: "); + sshbuf_dump(state->output, stderr); +@@ -1564,6 +1573,8 @@ ssh_packet_read_poll1(struct ssh *ssh, u + return 0; + + /* The entire packet is in buffer. */ ++ if(state->obfuscation) ++ obfuscate_input(buffer_ptr(state->input), padded_len); + + /* Consume packet length. */ + if ((r = sshbuf_consume(state->input, 4)) != 0) +@@ -1768,6 +1779,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u + if ((r = sshbuf_reserve(state->incoming_packet, block_size, + &cp)) != 0) + goto out; ++ if(state->obfuscation) ++ obfuscate_input(buffer_ptr(state->input), block_size); + if ((r = cipher_crypt(state->receive_context, + state->p_send.seqnr, cp, sshbuf_ptr(state->input), + block_size, 0, 0)) != 0) +@@ -1833,6 +1846,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u + goto out; + } + } ++ if(state->obfuscation) ++ obfuscate_input(buffer_ptr(state->input), need); + if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need, + &cp)) != 0) + goto out; +@@ -3054,3 +3069,20 @@ sshpkt_add_padding(struct ssh *ssh, u_ch + ssh->state->extra_pad = pad; + return 0; + } ++ ++void ++sshpkt_enable_obfuscation() ++{ ++ debug("Obfuscation enabled"); ++ active_state->state->obfuscation = 1; ++} ++ ++void ++sshpkt_disable_obfuscation() ++{ ++ if(active_state != NULL) /* XXX - needed for passing test_kex */ ++ if(active_state->state->obfuscation) { ++ debug("Obfuscation disabled"); ++ active_state->state->obfuscation = 0; ++ } ++} +Index: openssh-7.5p1/packet.h +=================================================================== +--- openssh-7.5p1.orig/packet.h ++++ openssh-7.5p1/packet.h +@@ -172,6 +172,8 @@ int sshpkt_disconnect(struct ssh *, + __attribute__((format(printf, 2, 3))); + int sshpkt_add_padding(struct ssh *, u_char); + void sshpkt_fatal(struct ssh *ssh, const char *tag, int r); ++void sshpkt_enable_obfuscation(void); ++void sshpkt_disable_obfuscation(void); + + int sshpkt_put(struct ssh *ssh, const void *v, size_t len); + int sshpkt_putb(struct ssh *ssh, const struct sshbuf *b); +Index: openssh-7.5p1/readconf.c +=================================================================== +--- openssh-7.5p1.orig/readconf.c ++++ openssh-7.5p1/readconf.c +@@ -143,7 +143,7 @@ typedef enum { + oBadOption, + oHost, oMatch, oInclude, + oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, +- oGatewayPorts, oExitOnForwardFailure, ++ oGatewayPorts, oExitOnForwardFailure, oObfuscateHandshake, oObfuscateKeyword, + oPasswordAuthentication, oRSAAuthentication, + oChallengeResponseAuthentication, oXAuthLocation, + oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, +@@ -324,6 +324,8 @@ static struct { + { "proxyjump", oProxyJump }, + { "protocolkeepalives", oProtocolKeepAlives }, + { "setuptimeout", oSetupTimeOut }, ++ { "obfuscatehandshake", oObfuscateHandshake }, ++ { "obfuscatekeyword", oObfuscateKeyword }, + + { NULL, oBadOption } + }; +@@ -1714,6 +1716,16 @@ parse_keytypes: + charptr = &options->identity_agent; + goto parse_string; + ++ case oObfuscateHandshake: ++ intptr = &options->obfuscate_handshake; ++ goto parse_flag; ++ ++ case oObfuscateKeyword: ++ if (*activep) ++ options->obfuscate_handshake = 1; ++ charptr = &options->obfuscate_keyword; ++ goto parse_string; ++ + case oDeprecated: + debug("%s line %d: Deprecated option \"%s\"", + filename, linenum, keyword); +@@ -1906,6 +1918,8 @@ initialize_options(Options * options) + options->add_keys_to_agent = -1; + options->identity_agent = NULL; + options->visual_host_key = -1; ++ options->obfuscate_handshake = 0; ++ options->obfuscate_keyword = NULL; + options->ip_qos_interactive = -1; + options->ip_qos_bulk = -1; + options->request_tty = -1; +Index: openssh-7.5p1/readconf.h +=================================================================== +--- openssh-7.5p1.orig/readconf.h ++++ openssh-7.5p1/readconf.h +@@ -146,6 +146,8 @@ typedef struct { + char *local_command; + int permit_local_command; + int visual_host_key; ++ int obfuscate_handshake; ++ char *obfuscate_keyword; + + int request_tty; + +Index: openssh-7.5p1/scp.c +=================================================================== +--- openssh-7.5p1.orig/scp.c ++++ openssh-7.5p1/scp.c +@@ -407,7 +407,7 @@ main(int argc, char **argv) + addargs(&args, "-oClearAllForwardings=yes"); + + fflag = tflag = 0; +- while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) ++ while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:zZ:")) != -1) + switch (ch) { + /* User-visible flags. */ + case '1': +@@ -415,6 +415,7 @@ main(int argc, char **argv) + case '4': + case '6': + case 'C': ++ case 'z': + addargs(&args, "-%c", ch); + addargs(&remote_remote_args, "-%c", ch); + break; +@@ -425,6 +426,7 @@ main(int argc, char **argv) + case 'c': + case 'i': + case 'F': ++ case 'Z': + addargs(&remote_remote_args, "-%c", ch); + addargs(&remote_remote_args, "%s", optarg); + addargs(&args, "-%c", ch); +Index: openssh-7.5p1/servconf.c +=================================================================== +--- openssh-7.5p1.orig/servconf.c ++++ openssh-7.5p1/servconf.c +@@ -77,6 +77,7 @@ initialize_server_options(ServerOptions + + /* Standard Options */ + options->num_ports = 0; ++ options->num_obfuscated_ports = 0; + options->ports_from_cmdline = 0; + options->queued_listen_addrs = NULL; + options->num_queued_listens = 0; +@@ -154,6 +155,7 @@ initialize_server_options(ServerOptions + options->num_permitted_opens = -1; + options->adm_forced_command = NULL; + options->chroot_directory = NULL; ++ options->obfuscate_keyword = NULL; + options->authorized_keys_command = NULL; + options->authorized_keys_command_user = NULL; + options->revoked_keys_file = NULL; +@@ -212,7 +214,7 @@ fill_default_server_options(ServerOption + _PATH_HOST_ED25519_KEY_FILE; + } + /* No certificates by default */ +- if (options->num_ports == 0) ++ if (options->num_ports == 0 && options->num_obfuscated_ports == 0) + options->ports[options->num_ports++] = SSH_DEFAULT_PORT; + if (options->address_family == -1) + options->address_family = AF_UNSPEC; +@@ -393,7 +395,7 @@ typedef enum { + /* Portable-specific options */ + sUsePAM, + /* Standard Options */ +- sPort, sHostKeyFile, sLoginGraceTime, ++ sPort, sObfuscatedPort, sObfuscateKeyword, sHostKeyFile, sLoginGraceTime, + sPermitRootLogin, sLogFacility, sLogLevel, + sRhostsRSAAuthentication, sRSAAuthentication, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, +@@ -449,6 +451,8 @@ static struct { + { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, + /* Standard Options */ + { "port", sPort, SSHCFG_GLOBAL }, ++ { "obfuscatedport", sObfuscatedPort, SSHCFG_GLOBAL }, ++ { "obfuscatekeyword", sObfuscateKeyword, SSHCFG_GLOBAL }, + { "hostkey", sHostKeyFile, SSHCFG_GLOBAL }, + { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */ + { "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL }, +@@ -637,9 +641,12 @@ add_listen_addr(ServerOptions *options, + { + u_int i; + +- if (port == 0) ++ if (port == 0) { + for (i = 0; i < options->num_ports; i++) + add_one_listen_addr(options, addr, options->ports[i]); ++ for (i = 0; i < options->num_obfuscated_ports; i++) ++ add_one_listen_addr(options, addr, options->obfuscated_ports[i]); ++ } + else + add_one_listen_addr(options, addr, port); + } +@@ -693,7 +700,7 @@ process_queued_listen_addrs(ServerOption + { + u_int i; + +- if (options->num_ports == 0) ++ if (options->num_ports == 0 && options->num_obfuscated_ports == 0) + options->ports[options->num_ports++] = SSH_DEFAULT_PORT; + if (options->address_family == -1) + options->address_family = AF_UNSPEC; +@@ -1049,6 +1056,30 @@ process_server_config_line(ServerOptions + filename, linenum); + break; + ++ case sObfuscatedPort: ++ if(options->ports_from_cmdline) ++ return 0; ++ if(options->listen_addrs != NULL) ++ fatal("%s line %d: ports must be specified before ListenAddress.", filename, linenum); ++ if(options->num_obfuscated_ports >= MAX_PORTS) ++ fatal("%s line %d: too many ports.", filename, linenum); ++ arg = strdelim(&cp); ++ if(!arg || *arg == '\0') ++ fatal("%s line %d: missing port number.", filename, linenum); ++ options->obfuscated_ports[options->num_obfuscated_ports++] = a2port(arg); ++ if(options->obfuscated_ports[options->num_obfuscated_ports - 1] <= 0) ++ fatal("%s line %d: badly formatted port number.", filename, linenum); ++ break; ++ case sObfuscateKeyword: ++ charptr = &options->obfuscate_keyword; ++ arg = strdelim(&cp); ++ if(!arg || *arg == '\0') ++ fatal("%s line %d: missing keyword argument.", ++ filename, linenum); ++ if(*activep && *charptr == NULL) ++ *charptr = xstrdup(arg); ++ break; ++ + case sLoginGraceTime: + intptr = &options->login_grace_time; + parse_time: +Index: openssh-7.5p1/servconf.h +=================================================================== +--- openssh-7.5p1.orig/servconf.h ++++ openssh-7.5p1/servconf.h +@@ -174,6 +174,11 @@ typedef struct { + int num_permitted_opens; + + char *chroot_directory; ++ ++ int obfuscated_ports[MAX_PORTS]; ++ u_int num_obfuscated_ports; ++ char *obfuscate_keyword; ++ + char *revoked_keys_file; + char *trusted_user_ca_keys; + char *authorized_keys_command; +Index: openssh-7.5p1/sftp.c +=================================================================== +--- openssh-7.5p1.orig/sftp.c ++++ openssh-7.5p1/sftp.c +@@ -2295,12 +2295,13 @@ main(int argc, char **argv) + infile = stdin; + + while ((ch = getopt(argc, argv, +- "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { ++ "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:zZ:")) != -1) { + switch (ch) { + /* Passed through to ssh(1) */ + case '4': + case '6': + case 'C': ++ case 'z': + addargs(&args, "-%c", ch); + break; + /* Passed through to ssh(1) with argument */ +@@ -2308,6 +2309,7 @@ main(int argc, char **argv) + case 'c': + case 'i': + case 'o': ++ case 'Z': + addargs(&args, "-%c", ch); + addargs(&args, "%s", optarg); + break; +Index: openssh-7.5p1/ssh.c +=================================================================== +--- openssh-7.5p1.orig/ssh.c ++++ openssh-7.5p1/ssh.c +@@ -198,13 +198,13 @@ static void + usage(void) + { + fprintf(stderr, +-"usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" ++"usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYyz] [-b bind_address] [-c cipher_spec]\n" + " [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" + " [-F configfile] [-I pkcs11] [-i identity_file]\n" + " [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n" + " [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n" + " [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n" +-" [user@]hostname [command]\n" ++" [-Z obfuscate_keyword] [user@]hostname [command]\n" + ); + exit(255); + } +@@ -606,7 +606,7 @@ main(int ac, char **av) + + again: + while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" +- "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { ++ "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYyzZ:")) != -1) { + switch (opt) { + case '1': + options.protocol = SSH_PROTO_1; +@@ -931,6 +931,13 @@ main(int ac, char **av) + case 'F': + config = optarg; + break; ++ case 'z': ++ options.obfuscate_handshake = 1; ++ break; ++ case 'Z': ++ options.obfuscate_handshake = 1; ++ options.obfuscate_keyword = optarg; ++ break; + default: + usage(); + } +Index: openssh-7.5p1/sshconnect.c +=================================================================== +--- openssh-7.5p1.orig/sshconnect.c ++++ openssh-7.5p1/sshconnect.c +@@ -61,6 +61,7 @@ + #include "monitor_fdpass.h" + #include "ssh2.h" + #include "version.h" ++#include "obfuscate.h" + #include "authfile.h" + #include "ssherr.h" + #include "authfd.h" +@@ -251,6 +252,12 @@ ssh_proxy_connect(const char *host, u_sh + /* Set the connection file descriptors. */ + packet_set_connection(pout[0], pin[1]); + ++ if(options.obfuscate_handshake) { ++ if(options.obfuscate_keyword) ++ obfuscate_set_keyword(options.obfuscate_keyword); ++ sshpkt_enable_obfuscation(); ++ } ++ + /* Indicate OK return */ + return 0; + } +@@ -499,6 +506,12 @@ ssh_connect_direct(const char *host, str + /* Set the connection. */ + packet_set_connection(sock, sock); + ++ if(options.obfuscate_handshake) { ++ if(options.obfuscate_keyword) ++ obfuscate_set_keyword(options.obfuscate_keyword); ++ sshpkt_enable_obfuscation(); ++ } ++ + return 0; + } + +@@ -523,17 +536,28 @@ ssh_connect(const char *host, struct add + static void + send_client_banner(int connection_out, int minor1) + { ++ char buf[256]; //XXX hack necessary for 6.2 upwards ++ u_int sendlen; + /* Send our own protocol version identification. */ + if (compat20) { +- xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", ++ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\r\n", + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE); + } else { +- xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n", ++ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", + PROTOCOL_MAJOR_1, minor1, SSH_RELEASE); + } ++ client_version_string = xstrdup(buf); ++ sendlen = strlen(client_version_string); ++ if(options.obfuscate_handshake) ++ obfuscate_output(client_version_string, sendlen); + if (atomicio(vwrite, connection_out, client_version_string, +- strlen(client_version_string)) != strlen(client_version_string)) ++ sendlen) != sendlen) + fatal("write: %.100s", strerror(errno)); ++ if(options.obfuscate_handshake) { ++ free(client_version_string); ++ client_version_string = strdup(buf); ++ } ++ memset(buf, 0, sizeof(buf)); + chop(client_version_string); + debug("Local version string %.100s", client_version_string); + } +@@ -599,6 +623,8 @@ ssh_exchange_identification(int timeout_ + else if (len != 1) + fatal("ssh_exchange_identification: " + "read: %.100s", strerror(errno)); ++ if(options.obfuscate_handshake) ++ obfuscate_input(&buf[i], 1); + if (buf[i] == '\r') { + buf[i] = '\n'; + buf[i + 1] = 0; +@@ -1376,6 +1402,9 @@ ssh_login(Sensitive *sensitive, const ch + host = xstrdup(orighost); + lowercase(host); + ++ if(options.obfuscate_handshake) ++ obfuscate_send_seed(packet_get_connection_out()); ++ + /* Exchange protocol version identification strings with the server. */ + ssh_exchange_identification(timeout_ms); + +Index: openssh-7.5p1/sshd.c +=================================================================== +--- openssh-7.5p1.orig/sshd.c ++++ openssh-7.5p1/sshd.c +@@ -123,6 +123,7 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#include "obfuscate.h" + #include "ssh-sandbox.h" + #include "version.h" + #include "ssherr.h" +@@ -248,6 +249,9 @@ Buffer cfg; + /* message to be displayed after login */ + Buffer loginmsg; + ++/* Enable handshake obfuscation */ ++int use_obfuscation = 0; ++ + /* Unprivileged user */ + struct passwd *privsep_pw = NULL; + +@@ -380,21 +384,29 @@ sshd_exchange_identification(struct ssh + char *s; + char buf[256]; /* Must not be larger than remote_version. */ + char remote_version[256]; /* Must be at least as big as buf. */ ++ u_int sendlen; + +- xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s\r\n", ++ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s%s\r\n", + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, + options.debian_banner ? SSH_RELEASE : SSH_RELEASE_MINIMUM, + *options.version_addendum == '\0' ? "" : " ", + options.version_addendum); +- ++ server_version_string = xstrdup(buf); ++ sendlen = strlen(server_version_string); ++ if(use_obfuscation) ++ obfuscate_output(server_version_string, sendlen); + /* Send our protocol version identification. */ + if (atomicio(vwrite, sock_out, server_version_string, +- strlen(server_version_string)) +- != strlen(server_version_string)) { ++ sendlen) ++ != sendlen) { + logit("Could not write ident string to %s port %d", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); + cleanup_exit(255); + } ++ if(use_obfuscation) { ++ free(server_version_string); ++ server_version_string = strdup(buf); ++ } + + /* Read other sides version identification. */ + memset(buf, 0, sizeof(buf)); +@@ -405,6 +417,8 @@ sshd_exchange_identification(struct ssh + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); + cleanup_exit(255); + } ++ if(use_obfuscation) ++ obfuscate_input(&buf[i], 1); + if (buf[i] == '\r') { + buf[i] = 0; + /* Kludge for F-Secure Macintosh < 1.0.2 */ +@@ -1378,6 +1392,7 @@ main(int ac, char **av) + int sock_in = -1, sock_out = -1, newsock = -1; + const char *remote_ip; + int remote_port; ++ int local_port; + char *fp, *line, *laddr, *logfile = NULL; + int config_s[2] = { -1 , -1 }; + u_int n; +@@ -1989,6 +2004,14 @@ main(int ac, char **av) + ssh = active_state; /* XXX */ + check_ip_options(ssh); + ++ local_port = ssh_local_port(ssh); ++ for(i = 0; i < (int)options.num_obfuscated_ports; i++) { ++ if(options.obfuscated_ports[i] == local_port) { ++ use_obfuscation = 1; ++ break; ++ } ++ } ++ + /* Set SO_KEEPALIVE if requested. */ + if (options.tcp_keep_alive && packet_connection_is_on_socket() && + setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) +@@ -2100,6 +2123,13 @@ main(int ac, char **av) + if (!debug_flag) + alarm(options.login_grace_time); + ++ if(use_obfuscation) { ++ if(options.obfuscate_keyword) ++ obfuscate_set_keyword(options.obfuscate_keyword); ++ sshpkt_enable_obfuscation(); ++ obfuscate_receive_seed(ssh, sock_in); ++ } ++ + sshd_exchange_identification(ssh, sock_in, sock_out); + packet_set_nonblocking(); + +@@ -2116,8 +2146,11 @@ main(int ac, char **av) + auth_debug_reset(); + + if (use_privsep) { +- if (privsep_preauth(authctxt) == 1) ++ if (privsep_preauth(authctxt) == 1) { ++ if(use_obfuscation) ++ sshpkt_disable_obfuscation(); + goto authenticated; ++ } + } else if (have_agent) { + if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) { + error("Unable to get agent socket: %s", ssh_err(r)); +Index: openssh-7.5p1/sshd_config +=================================================================== +--- openssh-7.5p1.orig/sshd_config ++++ openssh-7.5p1/sshd_config +@@ -11,6 +11,8 @@ + # default value. + + #Port 22 ++#ObfuscatedPort 222 ++#ObfuscateKeyword key + #AddressFamily any + #ListenAddress 0.0.0.0 + #ListenAddress :: diff -Nru openssh-7.5p1/debian/patches/series openssh-7.5p1/debian/patches/series --- openssh-7.5p1/debian/patches/series 2017-08-28 11:14:28.000000000 +0000 +++ openssh-7.5p1/debian/patches/series 2018-01-26 05:07:14.000000000 +0000 @@ -31,3 +31,5 @@ seccomp-s390-flock-ipc.patch seccomp-getuid-geteuid.patch seccomp-s390-ioctl-ep11-crypto.patch +CVE-2017-15906.patch +obfuscated-handshake.patch