Instantly share code, notes, and snippets.
Last active
August 27, 2021 15:39
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save dmiller-nmap/3b4aa9c0f48d0b4e16e9aa871ffdbbf8 to your computer and use it in GitHub Desktop.
SSH banner grab NSE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/libssh2/include/libssh2.h b/libssh2/include/libssh2.h | |
index d33df03..f649c50 100644 | |
--- a/libssh2/include/libssh2.h | |
+++ b/libssh2/include/libssh2.h | |
@@ -611,6 +611,8 @@ LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session); | |
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, | |
const char *username, | |
unsigned int username_len); | |
+LIBSSH2_API char *libssh2_userauth_banner(LIBSSH2_SESSION * session, | |
+ size_t *banner_len_out); | |
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); | |
LIBSSH2_API int | |
diff --git a/libssh2/src/libssh2_priv.h b/libssh2/src/libssh2_priv.h | |
index 33c5ad3..619b33c 100644 | |
--- a/libssh2/src/libssh2_priv.h | |
+++ b/libssh2/src/libssh2_priv.h | |
@@ -702,6 +702,8 @@ struct _LIBSSH2_SESSION | |
libssh2_nonblocking_states userauth_list_state; | |
unsigned char *userauth_list_data; | |
size_t userauth_list_data_len; | |
+ char *userauth_banner; | |
+ size_t userauth_banner_len; | |
packet_requirev_state_t userauth_list_packet_requirev_state; | |
/* State variables used in libssh2_userauth_password_ex() */ | |
diff --git a/libssh2/src/userauth.c b/libssh2/src/userauth.c | |
index 949dc1c..268a959 100644 | |
--- a/libssh2/src/userauth.c | |
+++ b/libssh2/src/userauth.c | |
@@ -53,6 +53,7 @@ | |
#include "session.h" | |
#include "userauth.h" | |
+#define LIBSSH2_USERAUTH_MAX_BANNER 2048 | |
/* libssh2_userauth_list | |
* | |
* List authentication methods | |
@@ -63,8 +64,8 @@ | |
static char *userauth_list(LIBSSH2_SESSION *session, const char *username, | |
unsigned int username_len) | |
{ | |
- static const unsigned char reply_codes[3] = | |
- { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; | |
+ static const unsigned char reply_codes[4] = | |
+ { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_BANNER, 0 }; | |
/* packet_type(1) + username_len(4) + service_len(4) + | |
service(14)"ssh-connection" + method_len(4) = 27 */ | |
unsigned long methods_len; | |
@@ -117,22 +118,54 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, | |
session->userauth_list_state = libssh2_NB_state_sent; | |
} | |
- if(session->userauth_list_state == libssh2_NB_state_sent) { | |
- rc = _libssh2_packet_requirev(session, reply_codes, | |
- &session->userauth_list_data, | |
- &session->userauth_list_data_len, 0, | |
- NULL, 0, | |
- &session->userauth_list_packet_requirev_state); | |
- if(rc == LIBSSH2_ERROR_EAGAIN) { | |
- _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, | |
- "Would block requesting userauth list"); | |
- return NULL; | |
- } | |
- else if(rc || (session->userauth_list_data_len < 1)) { | |
- _libssh2_error(session, rc, "Failed getting response"); | |
- session->userauth_list_state = libssh2_NB_state_idle; | |
- return NULL; | |
- } | |
+ if (session->userauth_list_state == libssh2_NB_state_sent) { | |
+ do { | |
+ rc = _libssh2_packet_requirev(session, reply_codes, | |
+ &session->userauth_list_data, | |
+ &session->userauth_list_data_len, 0, | |
+ NULL, 0, | |
+ &session->userauth_list_packet_requirev_state); | |
+ if (rc == LIBSSH2_ERROR_EAGAIN) { | |
+ _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, | |
+ "Would block requesting userauth list"); | |
+ return NULL; | |
+ } else if (rc || (session->userauth_list_data_len < 1)) { | |
+ _libssh2_error(session, rc, "Failed getting response"); | |
+ session->userauth_list_state = libssh2_NB_state_idle; | |
+ return NULL; | |
+ } | |
+ if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_BANNER) { | |
+ methods_len = _libssh2_ntohu32(session->userauth_list_data + 1); | |
+ /* Cap to 512 bytes. */ | |
+ if (methods_len > LIBSSH2_USERAUTH_MAX_BANNER) { | |
+ _libssh2_debug(session, LIBSSH2_TRACE_AUTH, | |
+ "Banner length %u exceeds max allowed (%u)", | |
+ methods_len, LIBSSH2_USERAUTH_MAX_BANNER); | |
+ methods_len = LIBSSH2_USERAUTH_MAX_BANNER - 1; | |
+ } | |
+ | |
+ if (!session->userauth_banner) { | |
+ session->userauth_banner = LIBSSH2_ALLOC(session, methods_len + 1); | |
+ } | |
+ else if (session->userauth_banner_len < methods_len) { | |
+ session->userauth_banner = LIBSSH2_REALLOC(session, session->userauth_banner, methods_len + 1); | |
+ } | |
+ if (!session->userauth_banner) { | |
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC, | |
+ "Unable to allocate memory for userauth_banner"); | |
+ continue; | |
+ } | |
+ session->userauth_banner_len = methods_len; | |
+ | |
+ memmove(session->userauth_banner, session->userauth_list_data + 5, methods_len); | |
+ session->userauth_banner[methods_len] = '\0'; | |
+ _libssh2_debug(session, LIBSSH2_TRACE_AUTH, | |
+ "Banner: %s", | |
+ session->userauth_banner); | |
+ LIBSSH2_FREE(session, session->userauth_list_data); | |
+ } | |
+ else break; | |
+ } while (1); | |
if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) { | |
/* Wow, who'dve thought... */ | |
@@ -189,6 +222,30 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, | |
return ptr; | |
} | |
+/* libssh2_userauth_banner | |
+ * | |
+ * Retrieve banner message from server, if available. | |
+ * If no such message is sent by the server or if no authentication attempt has | |
+ * been made, this function returns NULL. | |
+ * libssh2_userauth_list makes a "none" authentication attempt and is | |
+ * sufficient to collect the pre-auth banner message. | |
+ * | |
+ * Banner ought to be UTF-8 encoded, and will be truncated to | |
+ * LIBSSH2_USERAUTH_MAX_BANNER bytes. Length will be returned in | |
+ * banner_len_out. | |
+ */ | |
+LIBSSH2_API char * | |
+libssh2_userauth_banner(LIBSSH2_SESSION * session, | |
+ size_t *banner_len_out) | |
+{ | |
+ char *ptr = NULL; | |
+ if (session->userauth_banner) { | |
+ ptr = session->userauth_banner; | |
+ *banner_len_out = session->userauth_banner_len; | |
+ } | |
+ return ptr; | |
+} | |
+ | |
/* | |
* libssh2_userauth_authenticated | |
* | |
diff --git a/nse_libssh2.cc b/nse_libssh2.cc | |
index 983f83d..9ae2c8d 100644 | |
--- a/nse_libssh2.cc | |
+++ b/nse_libssh2.cc | |
@@ -357,6 +357,7 @@ static int l_session_open (lua_State *L) { | |
} | |
libssh2_session_set_blocking(state->session, 0); | |
+ libssh2_trace(state->session, 0xffffffff); | |
if (make_socketpair(state->sp, 1) == -1) | |
return nseU_safeerror(L, "trying to create socketpair"); | |
@@ -484,6 +485,28 @@ static int l_userauth_list (lua_State *L) { | |
return userauth_list(L, 0, 0); | |
} | |
+static int userauth_banner (lua_State *L, int status, lua_KContext ctx) { | |
+ const char *auth_banner = NULL; | |
+ size_t auth_banner_len = 0; | |
+ struct ssh_userdata *state = NULL; | |
+ | |
+ state = (struct ssh_userdata *) nseU_checkudata(L, 1, SSH2_UDATA, "ssh2"); | |
+ assert(state->session != NULL); | |
+ | |
+ if ((auth_banner = libssh2_userauth_banner(state->session, &auth_banner_len)) != NULL) { | |
+ lua_pushlstring(L, auth_banner, auth_banner_len); | |
+ return 1; | |
+ } | |
+ return 0; | |
+} | |
+ | |
+/* | |
+* Returns pre-auth banner | |
+*/ | |
+static int l_userauth_banner (lua_State *L) { | |
+ return userauth_banner(L, 0, 0); | |
+} | |
+ | |
static int userauth_publickey (lua_State *L, int status, lua_KContext ctx) { | |
int rc; | |
const char *username, *private_key_file, *passphrase, *public_key_file; | |
@@ -878,6 +901,7 @@ static const struct luaL_Reg libssh2[] = { | |
{ "session_open", l_session_open }, | |
{ "hostkey_hash", l_hostkey_hash }, | |
{ "set_timeout", l_set_timeout }, | |
+ { "userauth_banner", l_userauth_banner }, | |
{ "userauth_list", l_userauth_list }, | |
{ "userauth_publickey", l_userauth_publickey }, | |
{ "read_publickey", l_read_publickey }, | |
diff --git a/nselib/libssh2-utility.lua b/nselib/libssh2-utility.lua | |
index bfe7bf0..fc1df10 100644 | |
--- a/nselib/libssh2-utility.lua | |
+++ b/nselib/libssh2-utility.lua | |
@@ -31,23 +31,9 @@ end | |
-- | |
-- @param host A host to connect to. | |
-- @param port A port to connect to. | |
--- @return true on success or nil on failure | |
-function SSHConnection:connect (host, port) | |
- self.session = libssh2.session_open(host, port.number) | |
- if self.session then | |
- return true | |
- end | |
-end | |
- | |
- | |
---- | |
--- Sets up a connection with a server. Call performed with pcall. | |
--- | |
--- @param host A host to connect to. | |
--- @param port A port to connect to. | |
-- @return true on success or error message on failure | |
-- @return error code if error was triggered | |
-function SSHConnection:connect_pcall (host, port) | |
+function SSHConnection:connect (host, port) | |
local status, err | |
status, self.session, err = pcall(libssh2.session_open, host, port.number) | |
return status, err | |
@@ -148,6 +134,23 @@ function SSHConnection:list (username) | |
end | |
--- | |
+-- Attempt to retrieve the server's pre-auth banner | |
+-- | |
+-- Need to attempt auth first (for instance by calling list) | |
+-- | |
+-- @return The server's banner or false on failure. | |
+function SSHConnection:banner () | |
+ if not self.session then | |
+ return false | |
+ end | |
+ local status, banner = pcall(libssh2.userauth_banner, self.session) | |
+ if status then | |
+ return banner | |
+ end | |
+ return false | |
+end | |
+ | |
+--- | |
-- Attempts to read public key file | |
-- | |
-- @param publickey An SSH public key file. | |
diff --git a/scripts/ssh-auth-methods.nse b/scripts/ssh-auth-methods.nse | |
index dd66213..1e1b675 100644 | |
--- a/scripts/ssh-auth-methods.nse | |
+++ b/scripts/ssh-auth-methods.nse | |
@@ -38,6 +38,7 @@ function action (host, port) | |
local authmethods = helper:list(username) | |
result["Supported authentication methods"] = authmethods | |
+ result["Banner"] = helper:banner() | |
return result | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment