Skip to content

Instantly share code, notes, and snippets.

@ryancdotorg
Last active December 22, 2023 15:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryancdotorg/1e2f0d9543c8c998d380aa666b37a881 to your computer and use it in GitHub Desktop.
Save ryancdotorg/1e2f0d9543c8c998d380aa666b37a881 to your computer and use it in GitHub Desktop.
diff -ruN dropbear.orig/Makefile.in dropbear/Makefile.in
--- dropbear.orig/Makefile.in 2023-12-21 13:53:06.474210019 +0000
+++ dropbear/Makefile.in 2023-12-21 18:43:15.890803869 +0000
@@ -50,7 +50,7 @@
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
cli-agentfwd.o
-CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
+CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o common-ident.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o dh_groups.o \
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
diff -ruN dropbear.orig/common-ident.c dropbear/common-ident.c
--- dropbear.orig/common-ident.c 1970-01-01 01:00:00.000000000 +0100
+++ dropbear/common-ident.c 2023-12-22 02:43:07.517459121 +0000
@@ -0,0 +1,79 @@
+#include "includes.h"
+#include "dbutil.h"
+#include "ident.h"
+
+#if DROPBEAR_RUNTIME_IDENT
+/* RFC 4253 § 4.2 says the identificatin string MUST be
+ * SSH-protoversion-softwareversion SP comments CR LF
+ * MUST NOT contain a null, and MUST be at most 253 characters
+ */
+static unsigned int ssh_ident_len = 8;
+static char ssh_ident[253] = {'S','S','H','-','2','.','0','-'};
+
+/* not thread safe */
+int set_ssh_ident(char *software_version, char *comments) {
+ ssh_ident_len = 8;
+ unsigned int new_ident_len = ssh_ident_len;
+ size_t avail = sizeof(ssh_ident) - new_ident_len;
+
+ if (software_version == NULL) {
+ software_version = (char *)((uintptr_t)(LOCAL_IDENT) + 8);
+ }
+
+ for (int i = 0;;) {
+ char c = software_version[i++];
+
+ if (c == '\0') {
+ break;
+ } else if (avail == 0 || c <= 0x20 || c >= 0x7F || c == '-') {
+ return -1; /* out of space or invalid character */
+ }
+
+ ssh_ident[new_ident_len++] = c;
+ --avail;
+ }
+
+ if (comments != NULL) {
+ if (new_ident_len == sizeof(ssh_ident)) {
+ return -1; /* out of space */
+ }
+
+ ssh_ident[new_ident_len++] = ' ';
+ --avail;
+
+ for (int i = 0;;) {
+ char c = comments[i++];
+
+ if (c == '\0') {
+ break;
+ } else if (avail == 0 || c == '\n') {
+ return -1; /* out of space or invalid character */
+ }
+
+ ssh_ident[new_ident_len++] = c;
+ --avail;
+ }
+ }
+
+ ssh_ident_len = new_ident_len;
+ return 0;
+}
+
+unsigned int get_ssh_ident(char *buf, size_t n) {
+ if (ssh_ident_len > 253) {
+ __builtin_unreachable();
+ } else if (n < ssh_ident_len) {
+ dropbear_exit("Local ident does not fit in buffer");
+ __builtin_unreachable();
+ } else if (ssh_ident_len <= 8) {
+ size_t len = strlen(LOCAL_IDENT);
+ memcpy(buf, LOCAL_IDENT, len);
+ return (unsigned int)len;
+ } else {
+ memcpy(buf, ssh_ident, ssh_ident_len);
+ return (unsigned int)ssh_ident_len;
+ }
+
+ return 0;
+}
+#endif
diff -ruN dropbear.orig/common-kex.c dropbear/common-kex.c
--- dropbear.orig/common-kex.c 2023-12-21 13:53:06.478209618 +0000
+++ dropbear/common-kex.c 2023-12-21 19:16:03.651993561 +0000
@@ -38,6 +38,7 @@
#include "ecc.h"
#include "curve25519.h"
#include "crypto_desc.h"
+#include "ident.h"
static void kexinitialise(void);
static void gen_new_keys(void);
@@ -475,7 +476,13 @@
unsigned int kexhashbuf_len = 0;
unsigned int remote_ident_len = 0;
- unsigned int local_ident_len = 0;
+#if DROPBEAR_RUNTIME_IDENT
+ char local_ident[253];
+ unsigned int local_ident_len = get_ssh_ident(local_ident, sizeof(local_ident));
+#else
+ char *local_ident = LOCAL_IDENT;
+ unsigned int local_ident_len = strlen(LOCAL_IDENT);
+#endif
TRACE(("<- KEXINIT"))
TRACE(("enter recv_msg_kexinit"))
@@ -493,7 +500,6 @@
}
/* start the kex hash */
- local_ident_len = strlen(LOCAL_IDENT);
remote_ident_len = strlen(ses.remoteident);
kexhashbuf_len = local_ident_len + remote_ident_len
@@ -508,7 +514,7 @@
read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
- buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
+ buf_putstring(ses.kexhashbuf, local_ident, local_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
@@ -529,7 +535,7 @@
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
- buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
+ buf_putstring(ses.kexhashbuf, local_ident, local_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, ses.payload_beginning);
diff -ruN dropbear.orig/common-session.c dropbear/common-session.c
--- dropbear.orig/common-session.c 2023-12-21 13:53:06.478209618 +0000
+++ dropbear/common-session.c 2023-12-21 19:22:43.575532046 +0000
@@ -35,6 +35,7 @@
#include "channel.h"
#include "runopts.h"
#include "netio.h"
+#include "ident.h"
static void checktimeouts(void);
static long select_timeout(void);
@@ -358,8 +359,12 @@
}
void send_session_identification() {
- buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
- buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
+ char local_ident[255];
+ unsigned int local_ident_len = get_ssh_ident(local_ident, sizeof(local_ident) - 2);
+ local_ident[local_ident_len++] = '\r';
+ local_ident[local_ident_len++] = '\n';
+ buffer *writebuf = buf_new(local_ident_len + 1);
+ buf_putbytes(writebuf, (const unsigned char *) local_ident, local_ident_len);
writebuf_enqueue(writebuf);
}
diff -ruN dropbear.orig/ident.h dropbear/ident.h
--- dropbear.orig/ident.h 1970-01-01 01:00:00.000000000 +0100
+++ dropbear/ident.h 2023-12-21 19:10:43.908414764 +0000
@@ -0,0 +1,13 @@
+#ifndef DROPBEAR_IDENT_H_
+#define DROPBEAR_IDENT_H_
+#include "includes.h"
+
+/* not thread safe */
+int set_ssh_ident(char *software_version, char *comments);
+unsigned int get_ssh_ident(char *buf, size_t n);
+
+#ifndef DROPBEAR_RUNTIME_IDENT
+#define DROPBEAR_RUNTIME_IDENT 1
+#endif
+
+#endif
diff -ruN dropbear.orig/svr-runopts.c dropbear/svr-runopts.c
--- dropbear.orig/svr-runopts.c 2023-12-21 16:29:20.213431783 +0000
+++ dropbear/svr-runopts.c 2023-12-22 02:35:54.077140433 +0000
@@ -29,6 +29,7 @@
#include "dbutil.h"
#include "algo.h"
#include "ecdsa.h"
+#include "ident.h"
#include <grp.h>
@@ -106,6 +107,10 @@
"-A <authplugin>[,<options>]\n"
" Enable external public key auth through <authplugin>\n"
#endif
+#if DROPBEAR_RUNTIME_IDENT
+ "-Z <version> Override SSH software version string\n"
+ "-C <comments> Set identification string comments\n"
+#endif
"-V Version\n"
#if DEBUG_TRACE
"-v verbose (repeat for more verbose)\n"
@@ -140,6 +145,10 @@
char* reexec_fd_arg = NULL;
char* keyfile = NULL;
char c;
+#if DROPBEAR_RUNTIME_IDENT
+ char* software_version = NULL;
+ char* comments = NULL;
+#endif
#if DROPBEAR_PLUGIN
char* pubkey_plugin = NULL;
#endif
@@ -310,6 +319,14 @@
next = &pubkey_plugin;
break;
#endif
+#if DROPBEAR_RUNTIME_IDENT
+ case 'Z':
+ next = &software_version;
+ break;
+ case 'C':
+ next = &comments;
+ break;
+#endif
#if DEBUG_TRACE
case 'v':
debug_trace++;
@@ -355,6 +372,12 @@
addhostkey(keyfile);
keyfile = NULL;
}
+
+#if DROPBEAR_RUNTIME_IDENT
+ if (set_ssh_ident(software_version, comments) != 0) {
+ dropbear_exit("Invalid ident argument");
+ }
+#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment