This commit is contained in:
manojampalam 2016-05-12 16:41:59 -07:00
parent fcc3bdcd0a
commit fedeacacf5
4 changed files with 99 additions and 19 deletions

View File

@ -65,7 +65,7 @@ init_listeners() {
listeners[i].pipe_id = pipe_ids[i]; listeners[i].pipe_id = pipe_ids[i];
listeners[i].type = pipe_types[i]; listeners[i].type = pipe_types[i];
listeners[i].pipe = INVALID_HANDLE_VALUE; listeners[i].pipe = INVALID_HANDLE_VALUE;
listeners[i].sa.bInheritHandle = TRUE; listeners[i].sa.bInheritHandle = FALSE;
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(pipe_sddls[i], SDDL_REVISION_1, if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(pipe_sddls[i], SDDL_REVISION_1,
&listeners[i].sa.lpSecurityDescriptor, &listeners[i].sa.nLength)) { &listeners[i].sa.lpSecurityDescriptor, &listeners[i].sa.nLength)) {
debug("cannot convert sddl ERROR:%d", GetLastError()); debug("cannot convert sddl ERROR:%d", GetLastError());
@ -111,7 +111,6 @@ iocp_work(LPVOID lpParam) {
} }
} }
static void static void
process_connection(HANDLE pipe, int type) { process_connection(HANDLE pipe, int type) {
struct agent_connection* con; struct agent_connection* con;
@ -124,7 +123,7 @@ process_connection(HANDLE pipe, int type) {
con->type = type; con->type = type;
if (CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0) != ioc_port) if (CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0) != ioc_port)
fatal("failed to assign pipe to ioc_port"); fatal("failed to assign pipe to ioc_port");
agent_connection_on_io(con, 0, &con->ol); agent_connection_on_io(con, 0, &con->ol);
return iocp_work(NULL); return iocp_work(NULL);
} }
@ -185,8 +184,10 @@ agent_listen_loop() {
else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + NUM_LISTENERS))) { else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + NUM_LISTENERS))) {
/* process incoming connection */ /* process incoming connection */
HANDLE con = listeners[r - 1].pipe; HANDLE con = listeners[r - 1].pipe;
DWORD client_pid = 0;
listeners[r - 1].pipe = INVALID_HANDLE_VALUE; listeners[r - 1].pipe = INVALID_HANDLE_VALUE;
verbose("client connected on %ls", pipe_ids[r-1]); GetNamedPipeClientProcessId(con, &client_pid);
verbose("client pid %d connected on %ls", client_pid, pipe_ids[r-1]);
if (debug_mode) { if (debug_mode) {
process_connection(con, listeners[r - 1].type); process_connection(con, listeners[r - 1].type);
agent_cleanup(); agent_cleanup();
@ -201,6 +202,7 @@ agent_listen_loop() {
si.cb = sizeof(STARTUPINFOW); si.cb = sizeof(STARTUPINFOW);
memset(&si, 0, sizeof(STARTUPINFOW)); memset(&si, 0, sizeof(STARTUPINFOW));
GetModuleFileNameW(NULL, module_path, MAX_PATH); GetModuleFileNameW(NULL, module_path, MAX_PATH);
SetHandleInformation(con, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
if ((swprintf_s(path, MAX_PATH, L"%s %d %d", module_path, con, listeners[r - 1].type) == -1 ) || if ((swprintf_s(path, MAX_PATH, L"%s %d %d", module_path, con, listeners[r - 1].type) == -1 ) ||
(CreateProcessW(NULL, path, NULL, NULL, TRUE, (CreateProcessW(NULL, path, NULL, NULL, TRUE,
DETACHED_PROCESS, NULL, NULL, DETACHED_PROCESS, NULL, NULL,
@ -212,6 +214,7 @@ agent_listen_loop() {
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
} }
SetHandleInformation(con, HANDLE_FLAG_INHERIT, 0);
CloseHandle(con); CloseHandle(con);
} }

View File

@ -31,6 +31,13 @@ struct agent_connection {
WRITING, WRITING,
DONE DONE
} state; } state;
enum {
UNKNOWN = 0,
OTHER,
LOCAL_SYSTEM,
SSHD,
NETWORK_SERVICE
} client_type;
enum agent_type type; enum agent_type type;
}; };

View File

@ -114,17 +114,74 @@ void agent_connection_disconnect(struct agent_connection* con) {
DisconnectNamedPipe(con->connection); DisconnectNamedPipe(con->connection);
} }
static int
get_con_client_type(HANDLE pipe) {
int r = -1;
wchar_t *sshd_act = L"NT SERVICE\\SSHD", *ref_dom = NULL;
PSID sshd_sid = NULL;
char system_sid[SECURITY_MAX_SID_SIZE];
char ns_sid[SECURITY_MAX_SID_SIZE];
DWORD sshd_sid_len = 0, reg_dom_len = 0, info_len = 0, sid_size;
SID_NAME_USE nuse;
HANDLE token;
TOKEN_USER* info = NULL;
if (ImpersonateNamedPipeClient(pipe) == FALSE)
return -1;
if (LookupAccountNameW(NULL, sshd_act, NULL, &sshd_sid_len, NULL, &reg_dom_len, &nuse) == TRUE ||
(sshd_sid = malloc(sshd_sid_len)) == NULL ||
(ref_dom = (wchar_t*)malloc(reg_dom_len * 2)) == NULL ||
LookupAccountNameW(NULL, sshd_act, sshd_sid, &sshd_sid_len, ref_dom, &reg_dom_len, &nuse) == FALSE ||
OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token) == FALSE ||
GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE ||
(info = (TOKEN_USER*)malloc(info_len)) == NULL ||
GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE)
goto done;
sid_size = SECURITY_MAX_SID_SIZE;
if (CreateWellKnownSid(WinLocalSystemSid, NULL, system_sid, &sid_size) == FALSE)
goto done;
sid_size = SECURITY_MAX_SID_SIZE;
if (CreateWellKnownSid(WinNetworkServiceSid, NULL, ns_sid, &sid_size) == FALSE)
goto done;
if (EqualSid(info->User.Sid, system_sid))
r = LOCAL_SYSTEM;
else if (EqualSid(info->User.Sid, sshd_sid))
r = SSHD;
else if (EqualSid(info->User.Sid, ns_sid))
r = NETWORK_SERVICE;
else
r = OTHER;
debug("client type: %d", r);
done:
if (sshd_sid)
free(sshd_sid);
if (ref_dom)
free(ref_dom);
if (info)
free(info);
RevertToSelf();
return r;
}
static int static int
process_request(struct agent_connection* con) { process_request(struct agent_connection* con) {
int r; int r = -1;
struct sshbuf *request = NULL, *response = NULL; struct sshbuf *request = NULL, *response = NULL;
if (con->client_type == UNKNOWN)
if ((con->client_type = get_con_client_type(con->connection)) == -1)
goto done;
request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes); request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes);
response = sshbuf_new(); response = sshbuf_new();
if ((request == NULL) || (response == NULL)) { if ((request == NULL) || (response == NULL))
r = ENOMEM;
goto done; goto done;
}
if (con->type == KEY_AGENT) if (con->type == KEY_AGENT)
r = process_keyagent_request(request, response, con); r = process_keyagent_request(request, response, con);
@ -132,8 +189,6 @@ process_request(struct agent_connection* con) {
r = process_pubkeyagent_request(request, response, con); r = process_pubkeyagent_request(request, response, con);
else if (con->type == PUBKEY_AUTH_AGENT) else if (con->type == PUBKEY_AUTH_AGENT)
r = process_authagent_request(request, response, con); r = process_authagent_request(request, response, con);
else
r = EINVAL;
done: done:
if (request) if (request)

View File

@ -40,9 +40,12 @@ static int
get_user_root(struct agent_connection* con, HKEY *root){ get_user_root(struct agent_connection* con, HKEY *root){
int r = 0; int r = 0;
if (ImpersonateNamedPipeClient(con->connection) == FALSE) if (ImpersonateNamedPipeClient(con->connection) == FALSE)
return ERROR_INTERNAL_ERROR; return -1;
r = RegOpenCurrentUser(KEY_ALL_ACCESS, root); if (con->client_type > OTHER)
*root = HKEY_LOCAL_MACHINE;
else if (RegOpenCurrentUser(KEY_ALL_ACCESS, root) != ERROR_SUCCESS)
r = -1;
RevertToSelf(); RevertToSelf();
return r; return r;
@ -52,8 +55,10 @@ static int
convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **eblob, DWORD *eblen, int encrypt) { convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **eblob, DWORD *eblen, int encrypt) {
int success = 0; int success = 0;
DATA_BLOB in, out; DATA_BLOB in, out;
if (ImpersonateNamedPipeClient(con->connection) == FALSE)
return -1; if (con->client_type == OTHER)
if (ImpersonateNamedPipeClient(con->connection) == FALSE)
return -1;
in.cbData = blen; in.cbData = blen;
in.pbData = (char*)blob; in.pbData = (char*)blob;
@ -61,12 +66,16 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **
out.pbData = NULL; out.pbData = NULL;
if (encrypt) { if (encrypt) {
if (!CryptProtectData(&in, NULL, NULL, 0, NULL, 0, &out)) if (!CryptProtectData(&in, NULL, NULL, 0, NULL, 0, &out)) {
debug("cannot encrypt data");
goto done; goto done;
}
} }
else { else {
if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) {
debug("cannot decrypt data");
goto done; goto done;
}
} }
*eblob = malloc(out.cbData); *eblob = malloc(out.cbData);
@ -79,7 +88,8 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **
done: done:
if (out.pbData) if (out.pbData)
LocalFree(out.pbData); LocalFree(out.pbData);
RevertToSelf(); if (con->client_type == OTHER)
RevertToSelf();
return success? 0: -1; return success? 0: -1;
} }
@ -182,9 +192,11 @@ static int sign_blob(const struct sshkey *pubkey, u_char ** sig, size_t *siglen,
(tmpbuf = sshbuf_from(keyblob, keyblob_len)) == NULL) (tmpbuf = sshbuf_from(keyblob, keyblob_len)) == NULL)
goto done; goto done;
if ( sshkey_private_deserialize(tmpbuf, &prikey) != 0 || if (sshkey_private_deserialize(tmpbuf, &prikey) != 0 ||
sshkey_sign(prikey, sig, siglen, blob, blen, 0) != 0) sshkey_sign(prikey, sig, siglen, blob, blen, 0) != 0) {
debug("cannot sign using retrieved key");
goto done; goto done;
}
success = 1; success = 1;
@ -221,6 +233,7 @@ process_sign_request(struct sshbuf* request, struct sshbuf* response, struct age
sshbuf_get_string_direct(request, &data, &dlen) != 0 || sshbuf_get_string_direct(request, &data, &dlen) != 0 ||
sshbuf_get_u32(request, &flags) != 0 || sshbuf_get_u32(request, &flags) != 0 ||
sshkey_from_blob(blob, blen, &key) != 0) { sshkey_from_blob(blob, blen, &key) != 0) {
debug("sign request is invalid");
request_invalid = 1; request_invalid = 1;
goto done; goto done;
} }
@ -403,6 +416,8 @@ int process_keyagent_request(struct sshbuf* request, struct sshbuf* response, st
if ((r = sshbuf_get_u8(request, &type)) != 0) if ((r = sshbuf_get_u8(request, &type)) != 0)
return r; return r;
debug2("process key agent request type %d", type);
switch (type) { switch (type) {
case SSH2_AGENTC_ADD_IDENTITY: case SSH2_AGENTC_ADD_IDENTITY:
return process_add_identity(request, response, con); return process_add_identity(request, response, con);