ssh-agent security

Michael A Stevens mstevens at cmu.edu
Tue Aug 21 10:23:35 EST 2007


ssh-agent is a great tool that is often misconfigured with respect to 
agent forwarding. How many people running ssh-agent and doing a ssh 
-A have the very same public keys in ~/.ssh/authorized_keys of the machine 
they are coming from? ssh(1) is very clear in its warning about enabling 
agent forwarding. The simple act of prompting the user before using the 
key would enable them to determine when they key was potentially being 
used without their knowledge. It won't stop an attacker from riding on 
ssh sessions that a user legitimately forms, but it will help deter 
them from using the agent socket to make new ones either to other 
machines or back to the source machine. This patch is by no means 
ready to roll out to users, but any comments on it would be appreciated.

Usage:

patch -p0 < openssh-4.6p1-agentmod2.diff
cd openssh-4.6p1
./configure && make
./ssh-agent -di "xmessage -buttons Yes:0,No:1 Authorize key use by process with PID ="

(In other shell...)
SSH_AUTH_SOCK=/tmp/ssh-XXXXXXX/agent.XXXX; export SSH_AUTH_SOCK;
echo Agent pid XXXX;
ssh-add ~/.ssh/id_dsa
ssh -A user at host
ssh user at source


Mike Stevens
-------------- next part --------------
--- openssh-4.6p1/ssh-agent.c	2007-02-28 05:19:58.000000000 -0500
+++ openssh-4.6p1-agentmod2/ssh-agent.c	2007-08-20 19:56:38.000000000 -0400
@@ -134,6 +134,9 @@
 /* Default lifetime (0 == forever) */
 static int lifetime = 0;
 
+static int run_inform = 0;
+char inform_cmd[MAXPATHLEN];
+
 static void
 close_socket(SocketEntry *e)
 {
@@ -247,6 +250,28 @@
 	MD5_CTX md;
 	Key *key;
 
+#if defined(SO_PEERCRED)
+	if (AUTH_CONNECTION == e->type) {
+		struct ucred cred;
+		socklen_t len = sizeof(cred);
+		char inform_cmdline[MAXPATHLEN];
+
+		if (run_inform && getsockopt(e->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) >= 0) {
+			int ret;
+
+			snprintf(inform_cmdline, sizeof inform_cmdline, "%s %d",
+					inform_cmd, cred.pid);
+			ret = system(inform_cmdline);
+			if (ret != 0) {
+				close_socket(e);
+				return;
+			}
+		}
+	}
+#endif
+	
+
+
 	buffer_init(&msg);
 	key = key_new(KEY_RSA1);
 	if ((challenge = BN_new()) == NULL)
@@ -314,6 +339,26 @@
 	Buffer msg;
 	Key *key;
 
+#if defined(SO_PEERCRED)
+	if (AUTH_CONNECTION == e->type) {
+		struct ucred cred;
+		socklen_t len = sizeof(cred);
+		char inform_cmdline[MAXPATHLEN];
+
+		if (run_inform && getsockopt(e->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) >= 0) {
+			int ret;
+
+			snprintf(inform_cmdline, sizeof inform_cmdline, "%s %d",
+					inform_cmd, cred.pid);
+			ret = system(inform_cmdline);
+			if (ret != 0) {
+				close_socket(e);
+				return;
+			}
+		}
+	}
+#endif
+	
 	datafellows = 0;
 
 	blob = buffer_get_string(&e->request, &blen);
@@ -1007,6 +1052,7 @@
 	fprintf(stderr, "  -d          Debug mode.\n");
 	fprintf(stderr, "  -a socket   Bind agent socket to given name.\n");
 	fprintf(stderr, "  -t life     Default identity lifetime (seconds).\n");
+	fprintf(stderr, "  -i cmd      Command to run on new connection.\n");
 	exit(1);
 }
 
@@ -1047,7 +1093,7 @@
 	init_rng();
 	seed_rng();
 
-	while ((ch = getopt(ac, av, "cdksa:t:")) != -1) {
+	while ((ch = getopt(ac, av, "cdksa:i:t:")) != -1) {
 		switch (ch) {
 		case 'c':
 			if (s_flag)
@@ -1070,6 +1116,10 @@
 		case 'a':
 			agentsocket = optarg;
 			break;
+		case 'i':
+			run_inform = 1;
+			snprintf(inform_cmd, sizeof inform_cmd, "%s", optarg);
+			break;
 		case 't':
 			if ((lifetime = convtime(optarg)) == -1) {
 				fprintf(stderr, "Invalid lifetime\n");


More information about the openssh-unix-dev mailing list