sshdump: add capability to use doas on remote host

This commit is contained in:
Jaap Keuter 2023-02-19 13:41:24 +00:00 committed by Gilbert Ramirez
parent f6e6853dc4
commit 455b9a470f
3 changed files with 142 additions and 33 deletions

View File

@ -26,11 +26,17 @@ sshdump - Provide interfaces to capture from a remote host through SSH using a r
[ *--remote-port*=<TCP port> ] [ *--remote-port*=<TCP port> ]
[ *--remote-username*=<username> ] [ *--remote-username*=<username> ]
[ *--remote-password*=<password> ] [ *--remote-password*=<password> ]
[ *--sshkey*=<public key path> ] [ *--sshkey*=<private key path> ]
[ *--sshkey-passphrase*=<private key passphrase> ]
[ *--proxycommand*=<SSH proxy command> ]
[ *--remote-interface*=<interface> ] [ *--remote-interface*=<interface> ]
[ *--remote-capture-command-select*=<capture command selection> ] [ *--remote-capture-command-select*=<capture command selection> ]
[ *--remote-capture-command*=<capture command> ] [ *--remote-capture-command*=<capture command> ]
[ *--remote-sudo* ] [ *--remote-priv*=<privilege elevation command selection> ]
[ *--remote-priv-user*=<privileged user name> ]
[ *--remote-noprom* ]
[ *--remote-filter*=<remote capture filter> ]
[ *--remote-count*=<number> ]
[manarg] [manarg]
*sshdump* *sshdump*
@ -128,6 +134,14 @@ List DLTs of specified interface.
List configuration options of specified interface. List configuration options of specified interface.
-- --
--extcap-capture-filter=<capture filter>::
+
--
The capture filter. It corresponds to the value provided via the *tshark -f*
option, and the Capture Filter field next to the interfaces list in the
Wireshark interface.
--
--capture:: --capture::
+ +
-- --
@ -172,6 +186,18 @@ recommended to use keyfiles with a SSH agent.
The path to a private key for authentication. NOTE: Only OPENSSH key/value pair format is supported. The path to a private key for authentication. NOTE: Only OPENSSH key/value pair format is supported.
-- --
--sshkey-passphrase=<SSH private key passphrase>::
+
--
The passphrase for the private key for authentication.
--
--proxycommand=<proxy command>::
+
--
The command to use as proxy for the SSH connection.
--
--remote-interface=<remote interface>:: --remote-interface=<remote interface>::
+ +
-- --
@ -204,14 +230,33 @@ When specified, this command will be used as is, options such as the capture
filter (*--extcap-capture-filter*) will not be appended. filter (*--extcap-capture-filter*) will not be appended.
-- --
--extcap-capture-filter=<capture filter>:: --remote-priv=<privilege elevation command selection>::
+ +
-- --
The capture filter. It corresponds to the value provided via the *tshark -f* The command to use to achieve privilege elevation to capture on the remote host. Either none, sudo or doas.
--
--remote-priv-user=<privileged user name>::
+
--
If a command is used to achieve privilege elevation to capture on the remote host this may require a user name.
If needed use this option to give that user name.
--
--remote-filter=<capture filter>::
+
--
The remote capture filter. It corresponds to the value provided via the *tshark -f*
option, and the Capture Filter field next to the interfaces list in the option, and the Capture Filter field next to the interfaces list in the
Wireshark interface. Wireshark interface.
-- --
--remote-count=<number>::
+
--
The number of packets to capture.
--
== EXAMPLES == EXAMPLES
To see program arguments: To see program arguments:
@ -245,7 +290,7 @@ To see interface configuration options:
.Example output .Example output
arg {number=0}{call=--remote-host}{display=Remote SSH server address}{type=string} arg {number=0}{call=--remote-host}{display=Remote SSH server address}{type=string}
{tooltip=The remote SSH host. It can be both an IP address or a hostname}{required=true}{group=Server} {tooltip=The remote SSH host. It can be both an IP address or a hostname}{required=true}{group=Server}
arg {number=1}{call=--remote-port}{display=Remote SSH server port}{type=unsigned} arg {number=1}{call=--remote-port}{display=Remote SSH server port}{type=unsigned}{default=22}
{tooltip=The remote SSH host port (1-65535)}{range=1,65535}{group=Server} {tooltip=The remote SSH host port (1-65535)}{range=1,65535}{group=Server}
arg {number=2}{call=--remote-username}{display=Remote SSH server username}{type=string} arg {number=2}{call=--remote-username}{display=Remote SSH server username}{type=string}
{tooltip=The remote SSH username. If not provided, the current user will be used}{group=Authentication} {tooltip=The remote SSH username. If not provided, the current user will be used}{group=Authentication}
@ -266,21 +311,26 @@ To see interface configuration options:
value {arg=8}{value=other}{display=Other:} value {arg=8}{value=other}{display=Other:}
arg {number=9}{call=--remote-capture-command}{display=Remote capture command}{type=string} arg {number=9}{call=--remote-capture-command}{display=Remote capture command}{type=string}
{tooltip=The remote command used to capture}{group=Capture} {tooltip=The remote command used to capture}{group=Capture}
arg {number=10}{call=--remote-sudo}{display=Use sudo on the remote machine}{type=boolflag} arg {number=10}{call=--remote-priv}{display=Gain capture privilege on the remote machine}{type=radio}
{tooltip=Prepend the capture command with sudo on the remote machine}{group=Capture} {tooltip=Optionally prepend the capture command with sudo or doas on the remote machine}{group=Capture}
arg {number=11}{call=--remote-noprom}{display=No promiscuous mode}{type=boolflag} value {arg=10}{value=none}{display=none}{default=true}
value {arg=10}{value=sudo}{display=sudo}
value {arg=10}{value=doas -n}{display=doas}
arg {number=11}{call=--remote-priv-user}{display=Privileged user name for sudo or doas}{type=string}
{tooltip=User name of privileged user to execute the capture command on the remote machine}{group=Capture}
arg {number=12}{call=--remote-noprom}{display=No promiscuous mode}{type=boolflag}
{tooltip=Don't use promiscuous mode on the remote machine}{group=Capture} {tooltip=Don't use promiscuous mode on the remote machine}{group=Capture}
arg {number=12}{call=--remote-filter}{display=Remote capture filter}{type=string} arg {number=13}{call=--remote-filter}{display=Remote capture filter}{type=string}
{tooltip=The remote capture filter}{default=not ((host myhost) and port 22)}{group=Capture} {tooltip=The remote capture filter}{default=not ((host myhost) and port 22)}{group=Capture}
arg {number=13}{call=--remote-count}{display=Packets to capture}{type=unsigned}{default=0} arg {number=14}{call=--remote-count}{display=Packets to capture}{type=unsigned}{default=0}
{tooltip=The number of remote packets to capture. (Default: inf)}{group=Capture} {tooltip=The number of remote packets to capture. (Default: inf)}{group=Capture}
arg {number=14}{call=--log-level}{display=Set the log level}{type=selector} arg {number=15}{call=--log-level}{display=Set the log level}{type=selector}
{tooltip=Set the log level}{required=false}{group=Debug} {tooltip=Set the log level}{required=false}{group=Debug}
value {arg=14}{value=message}{display=Message}{default=true} value {arg=14}{value=message}{display=Message}{default=true}
value {arg=14}{value=info}{display=Info} value {arg=14}{value=info}{display=Info}
value {arg=14}{value=debug}{display=Debug} value {arg=14}{value=debug}{display=Debug}
value {arg=14}{value=noisy}{display=Noisy} value {arg=14}{value=noisy}{display=Noisy}
arg {number=15}{call=--log-file}{display=Use a file for logging}{type=fileselect} arg {number=16}{call=--log-file}{display=Use a file for logging}{type=fileselect}
{tooltip=Set a file where log messages are written}{required=false}{group=Debug} {tooltip=Set a file where log messages are written}{required=false}{group=Debug}
@ -291,6 +341,10 @@ To capture:
To use different capture binaries: To use different capture binaries:
sshdump --extcap-interface=sshdump --fifo=/tmp/ssh.pcap --capture --remote-host 192.168.1.10
--remote-username user --remote-priv sudo --remote-capture-command-select tcpdump
--remote-interface eth0 --remote-noprom
sshdump --extcap-interface=sshdump --fifo=/tmp/ssh.pcap --capture --remote-host 192.168.1.10 sshdump --extcap-interface=sshdump --fifo=/tmp/ssh.pcap --capture --remote-host 192.168.1.10
--remote-capture-command='dumpcap -i eth0 -P -w -' --remote-capture-command='dumpcap -i eth0 -P -w -'

View File

@ -6016,16 +6016,27 @@ set_pref(gchar *pref_name, const gchar *value, void *private_data _U_,
} else if (strcmp(pref_name, "name_resolve_suppress_smi_errors") == 0) { } else if (strcmp(pref_name, "name_resolve_suppress_smi_errors") == 0) {
pref = prefs_find_preference(nameres_module, "suppress_smi_errors"); pref = prefs_find_preference(nameres_module, "suppress_smi_errors");
} }
} else if (strcmp(module->name, "extcap") == 0) {
/* Handle the old "sshdump.remotesudo" preference; map it to the new
"sshdump.remotepriv" preference, and map the boolean values to the
appropriate strings of the new preference. */
if (strcmp(dotp, "sshdump.remotesudo") == 0) {
pref = prefs_find_preference(module, "sshdump.remotepriv");
if (g_ascii_strcasecmp(value, "true") == 0)
value = "sudo";
else
value = "none";
}
} }
} }
if (pref == NULL ) { if (pref == NULL ) {
if (strcmp(module->name, "extcap") == 0 && g_list_length(module->prefs) <= 1) { if (strcmp(module->name, "extcap") == 0 && g_list_length(module->prefs) <= 1) {
/* /*
* Assume that we've skipped extcap preference registration * Assume that we've skipped extcap preference registration
* and that only extcap.gui_save_on_start is loaded. * and that only extcap.gui_save_on_start is loaded.
*/ */
return PREFS_SET_OK; return PREFS_SET_OK;
} }
return PREFS_SET_NO_SUCH_PREF; /* no such preference */ return PREFS_SET_NO_SUCH_PREF; /* no such preference */
} }

View File

@ -37,7 +37,7 @@ static gchar* sshdump_extcap_interface;
#endif #endif
#define SSHDUMP_VERSION_MAJOR "1" #define SSHDUMP_VERSION_MAJOR "1"
#define SSHDUMP_VERSION_MINOR "1" #define SSHDUMP_VERSION_MINOR "2"
#define SSHDUMP_VERSION_RELEASE "0" #define SSHDUMP_VERSION_RELEASE "0"
#define SSH_READ_BLOCK_SIZE 256 #define SSH_READ_BLOCK_SIZE 256
@ -58,7 +58,9 @@ enum {
OPT_SSHKEY_PASSPHRASE, OPT_SSHKEY_PASSPHRASE,
OPT_PROXYCOMMAND, OPT_PROXYCOMMAND,
OPT_REMOTE_COUNT, OPT_REMOTE_COUNT,
OPT_REMOTE_SUDO, OPT_REMOTE_SUDO, // Deprecated
OPT_REMOTE_PRIV,
OPT_REMOTE_PRIV_USER,
OPT_REMOTE_NOPROM OPT_REMOTE_NOPROM
}; };
@ -69,7 +71,9 @@ static struct ws_option longopts[] = {
SSH_BASE_OPTIONS, SSH_BASE_OPTIONS,
{ "remote-capture-command-select", ws_required_argument, NULL, OPT_REMOTE_CAPTURE_COMMAND_SELECT}, { "remote-capture-command-select", ws_required_argument, NULL, OPT_REMOTE_CAPTURE_COMMAND_SELECT},
{ "remote-capture-command", ws_required_argument, NULL, OPT_REMOTE_CAPTURE_COMMAND}, { "remote-capture-command", ws_required_argument, NULL, OPT_REMOTE_CAPTURE_COMMAND},
{ "remote-sudo", ws_no_argument, NULL, OPT_REMOTE_SUDO }, { "remote-sudo", ws_no_argument, NULL, OPT_REMOTE_SUDO }, // Deprecated
{ "remote-priv", ws_required_argument, NULL, OPT_REMOTE_PRIV },
{ "remote-priv-user", ws_required_argument, NULL, OPT_REMOTE_PRIV_USER },
{ "remote-noprom", ws_no_argument, NULL, OPT_REMOTE_NOPROM }, { "remote-noprom", ws_no_argument, NULL, OPT_REMOTE_NOPROM },
{ 0, 0, 0, 0} { 0, 0, 0, 0}
}; };
@ -130,7 +134,7 @@ static char* local_interfaces_to_filter(const guint16 remote_port)
} }
static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command_select, static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command_select,
const char* capture_command, const gboolean use_sudo, gboolean noprom, const char* capture_command, const char* privilege, gboolean noprom,
const char* iface, const char* cfilter, const guint32 count) const char* iface, const char* cfilter, const guint32 count)
{ {
gchar* cmdline = NULL; gchar* cmdline = NULL;
@ -175,7 +179,7 @@ static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command
count_str = ws_strdup_printf("-c %u", count); count_str = ws_strdup_printf("-c %u", count);
cmdline = ws_strdup_printf("%s tcpdump -U %s%s %s -w - %s %s", cmdline = ws_strdup_printf("%s tcpdump -U %s%s %s -w - %s %s",
use_sudo ? "sudo" : "", privilege,
quoted_iface ? "-i " : "", quoted_iface ? "-i " : "",
quoted_iface ? quoted_iface : "", quoted_iface ? quoted_iface : "",
noprom ? "-p" : "", noprom ? "-p" : "",
@ -196,7 +200,7 @@ static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command
count_str = ws_strdup_printf("-c %u", count); count_str = ws_strdup_printf("-c %u", count);
cmdline = ws_strdup_printf("%s dumpcap %s %s -w - %s -f %s", cmdline = ws_strdup_printf("%s dumpcap %s %s -w - %s -f %s",
use_sudo ? "sudo" : "", privilege,
noprom ? "-p" : "", noprom ? "-p" : "",
*ifaces ? ifaces : "", *ifaces ? ifaces : "",
count_str ? count_str : "", count_str ? count_str : "",
@ -223,7 +227,7 @@ static ssh_channel run_ssh_command(ssh_session sshs, const char* capture_command
} }
static int ssh_open_remote_connection(const ssh_params_t* params, const char* iface, const char* cfilter, static int ssh_open_remote_connection(const ssh_params_t* params, const char* iface, const char* cfilter,
const char* capture_command_select, const char* capture_command, const gboolean use_sudo, const char* capture_command_select, const char* capture_command, const char* privilege,
gboolean noprom, const guint32 count, const char* fifo) gboolean noprom, const guint32 count, const char* fifo)
{ {
ssh_session sshs = NULL; ssh_session sshs = NULL;
@ -248,7 +252,7 @@ static int ssh_open_remote_connection(const ssh_params_t* params, const char* if
goto cleanup; goto cleanup;
} }
channel = run_ssh_command(sshs, capture_command_select, capture_command, use_sudo, noprom, iface, cfilter, count); channel = run_ssh_command(sshs, capture_command_select, capture_command, privilege, noprom, iface, cfilter, count);
if (!channel) { if (!channel) {
ws_warning("Can't run ssh command."); ws_warning("Can't run ssh command.");
@ -323,7 +327,7 @@ static int list_config(char *interface, unsigned int remote_port)
"{type=string}{tooltip=The remote SSH host. It can be both " "{type=string}{tooltip=The remote SSH host. It can be both "
"an IP address or a hostname}{required=true}{group=Server}\n", inc++); "an IP address or a hostname}{required=true}{group=Server}\n", inc++);
printf("arg {number=%u}{call=--remote-port}{display=Remote SSH server port}" printf("arg {number=%u}{call=--remote-port}{display=Remote SSH server port}"
"{type=unsigned}{tooltip=The remote SSH host port (1-65535)}" "{type=unsigned}{default=22}{tooltip=The remote SSH host port (1-65535)}"
"{range=1,65535}{group=Server}\n", inc++); "{range=1,65535}{group=Server}\n", inc++);
printf("arg {number=%u}{call=--remote-username}{display=Remote SSH server username}" printf("arg {number=%u}{call=--remote-username}{display=Remote SSH server username}"
"{type=string}{tooltip=The remote SSH username. If not provided, " "{type=string}{tooltip=The remote SSH username. If not provided, "
@ -350,8 +354,18 @@ static int list_config(char *interface, unsigned int remote_port)
printf("value {arg=%u}{value=other}{display=Other:}\n", inc++); printf("value {arg=%u}{value=other}{display=Other:}\n", inc++);
printf("arg {number=%u}{call=--remote-capture-command}{display=Remote capture command}" printf("arg {number=%u}{call=--remote-capture-command}{display=Remote capture command}"
"{type=string}{tooltip=The remote command used to capture}{group=Capture}\n", inc++); "{type=string}{tooltip=The remote command used to capture}{group=Capture}\n", inc++);
printf("arg {number=%u}{call=--remote-sudo}{display=Use sudo on the remote machine}" // Deprecated
"{type=boolflag}{tooltip=Prepend the capture command with sudo on the remote machine}" //printf("arg {number=%u}{call=--remote-sudo}{display=Use sudo on the remote machine}"
// "{type=boolflag}{tooltip=Prepend the capture command with sudo on the remote machine}"
// "{group=Capture}\n", inc++);
printf("arg {number=%u}{call=--remote-priv}{display=Gain capture privilege on the remote machine}"
"{type=radio}{tooltip=Optionally prepend the capture command with sudo or doas on the remote machine}"
"{group=Capture}\n", inc);
printf("value {arg=%u}{value=none}{display=none}{default=true}\n", inc);
printf("value {arg=%u}{value=sudo}{display=sudo}\n", inc);
printf("value {arg=%u}{value=doas -n}{display=doas}\n", inc++);
printf("arg {number=%u}{call=--remote-priv-user}{display=Privileged user name for sudo or doas}"
"{type=string}{tooltip=User name of privileged user to execute the capture command on the remote machine}"
"{group=Capture}\n", inc++); "{group=Capture}\n", inc++);
printf("arg {number=%u}{call=--remote-noprom}{display=No promiscuous mode}" printf("arg {number=%u}{call=--remote-noprom}{display=No promiscuous mode}"
"{type=boolflag}{tooltip=Don't use promiscuous mode on the remote machine}{group=Capture}" "{type=boolflag}{tooltip=Don't use promiscuous mode on the remote machine}{group=Capture}"
@ -401,7 +415,8 @@ int main(int argc, char *argv[])
extcap_parameters* extcap_conf = g_new0(extcap_parameters, 1); extcap_parameters* extcap_conf = g_new0(extcap_parameters, 1);
char* help_url; char* help_url;
char* help_header = NULL; char* help_header = NULL;
gboolean use_sudo = FALSE; char* priv = NULL;
char* priv_user = NULL;
gboolean noprom = FALSE; gboolean noprom = FALSE;
gchar* interface_description = g_strdup("SSH remote capture"); gchar* interface_description = g_strdup("SSH remote capture");
@ -461,7 +476,9 @@ int main(int argc, char *argv[])
extcap_help_add_option(extcap_conf, "--remote-interface <iface>", "the remote capture interface"); extcap_help_add_option(extcap_conf, "--remote-interface <iface>", "the remote capture interface");
extcap_help_add_option(extcap_conf, "--remote-capture-command-select <selection>", "dumpcap, tcpdump or other remote capture command"); extcap_help_add_option(extcap_conf, "--remote-capture-command-select <selection>", "dumpcap, tcpdump or other remote capture command");
extcap_help_add_option(extcap_conf, "--remote-capture-command <capture command>", "the remote capture command"); extcap_help_add_option(extcap_conf, "--remote-capture-command <capture command>", "the remote capture command");
extcap_help_add_option(extcap_conf, "--remote-sudo", "use sudo on the remote machine to capture"); //extcap_help_add_option(extcap_conf, "--remote-sudo", "use sudo on the remote machine to capture"); // Deprecated
extcap_help_add_option(extcap_conf, "--remote-priv <selection>", "none, sudo or doas");
extcap_help_add_option(extcap_conf, "--remote-priv-user <username>", "privileged user name");
extcap_help_add_option(extcap_conf, "--remote-noprom", "don't use promiscuous mode on the remote machine"); extcap_help_add_option(extcap_conf, "--remote-noprom", "don't use promiscuous mode on the remote machine");
extcap_help_add_option(extcap_conf, "--remote-filter <filter>", "a filter for remote capture (default: don't listen on local interfaces IPs)"); extcap_help_add_option(extcap_conf, "--remote-filter <filter>", "a filter for remote capture (default: don't listen on local interfaces IPs)");
extcap_help_add_option(extcap_conf, "--remote-count <count>", "the number of packets to capture"); extcap_help_add_option(extcap_conf, "--remote-count <count>", "the number of packets to capture");
@ -543,7 +560,19 @@ int main(int argc, char *argv[])
break; break;
case OPT_REMOTE_SUDO: case OPT_REMOTE_SUDO:
use_sudo = TRUE; // Deprecated
g_free(priv);
priv = g_strdup("sudo");
break;
case OPT_REMOTE_PRIV:
g_free(priv);
priv = g_strdup(ws_optarg);
break;
case OPT_REMOTE_PRIV_USER:
g_free(priv_user);
priv_user = g_strdup(ws_optarg);
break; break;
case OPT_REMOTE_FILTER: case OPT_REMOTE_FILTER:
@ -597,17 +626,30 @@ int main(int argc, char *argv[])
if (extcap_conf->capture) { if (extcap_conf->capture) {
char* filter; char* filter;
char* privilege;
if (!ssh_params->host) { if (!ssh_params->host) {
ws_warning("Missing parameter: --remote-host"); ws_warning("Missing parameter: --remote-host");
goto end; goto end;
} }
if ((priv) && g_strcmp0(priv, "none") && strlen(g_strstrip(priv))) {
if ((priv_user) && strlen(g_strstrip(priv_user)))
/* Both sudo and doas use the same command line option */
privilege = g_strconcat(priv, " -u ", priv_user, NULL);
else
privilege = g_strdup(priv);
} else {
privilege = g_strdup("");
}
filter = concat_filters(extcap_conf->capture_filter, remote_filter); filter = concat_filters(extcap_conf->capture_filter, remote_filter);
ssh_params->debug = extcap_conf->debug; ssh_params->debug = extcap_conf->debug;
ret = ssh_open_remote_connection(ssh_params, remote_interface, ret = ssh_open_remote_connection(ssh_params, remote_interface,
filter, remote_capture_command_select, remote_capture_command, filter, remote_capture_command_select, remote_capture_command,
use_sudo, noprom, count, extcap_conf->fifo); privilege, noprom, count, extcap_conf->fifo);
g_free(filter); g_free(filter);
g_free(privilege);
} else { } else {
ws_debug("You should not come here... maybe some parameter missing?"); ws_debug("You should not come here... maybe some parameter missing?");
ret = EXIT_FAILURE; ret = EXIT_FAILURE;
@ -620,6 +662,8 @@ end:
g_free(remote_capture_command); g_free(remote_capture_command);
g_free(remote_interface); g_free(remote_interface);
g_free(remote_filter); g_free(remote_filter);
g_free(priv);
g_free(priv_user);
extcap_base_cleanup(&extcap_conf); extcap_base_cleanup(&extcap_conf);
return ret; return ret;
} }