From 4c0e2c2078943c116a04b55de6bd48effad30e61 Mon Sep 17 00:00:00 2001 From: Manoj Ampalam Date: Sat, 7 May 2016 21:04:54 -0700 Subject: [PATCH] 5-7 C2 --- .../win32/win32compat/ssh-agent/agent-main.c | 7 +- contrib/win32/win32compat/ssh-agent/agent.c | 300 +++++++++++------- contrib/win32/win32compat/ssh-agent/agent.h | 14 +- .../win32/win32compat/ssh-agent/connection.c | 2 +- 4 files changed, 206 insertions(+), 117 deletions(-) diff --git a/contrib/win32/win32compat/ssh-agent/agent-main.c b/contrib/win32/win32compat/ssh-agent/agent-main.c index bd62a93..4ed3428 100644 --- a/contrib/win32/win32compat/ssh-agent/agent-main.c +++ b/contrib/win32/win32compat/ssh-agent/agent-main.c @@ -84,6 +84,7 @@ BOOL WINAPI ctrl_c_handler( _In_ DWORD dwCtrlType ) { /* for any Ctrl type, shutdown agent*/ + debug("Ctrl+C received"); agent_shutdown(); return TRUE; } @@ -98,11 +99,11 @@ int main(int argc, char **argv) { /* console app - start in debug mode*/ SetConsoleCtrlHandler(ctrl_c_handler, TRUE); log_init("ssh-agent", 7, 1, 1); - return agent_start(TRUE, FALSE, 0); + return agent_start(TRUE, FALSE, 0, 0); } else { log_init("ssh-agent", config_log_level(), 1, 0); - return agent_start(FALSE, TRUE, (HANDLE)atoi(*argv)); + return agent_start(FALSE, TRUE, (HANDLE)atoi(*(argv+1)), atoi(*(argv+2))); } } else @@ -118,6 +119,6 @@ int scm_start_servie(DWORD num, LPWSTR* args) { ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300); ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); log_init("ssh-agent", config_log_level(), 1, 0); - return agent_start(FALSE, FALSE, 0); + return agent_start(FALSE, FALSE, 0, 0); } diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c index 8a1a068..4c00555 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.c +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -32,108 +32,58 @@ #define AGENT_PIPE_ID L"\\\\.\\pipe\\ssh-agent" #define BUFSIZE 5 * 1024 -static HANDLE ioc_port; -static volatile long action_queue; -static struct agent_connection* list; +static HANDLE ioc_port = NULL; +static BOOL debug_mode = FALSE; -#define ACTION_LISTEN 0x80000000 -#define ACTION_SHUTDOWN 0x40000000 +#define NUM_LISTENERS 1 +#define KEY_AGENT_PIPE_ID L"\\\\.\\pipe\\ssh-agent" -void agent_sm_process_action_queue() { +static wchar_t *pipe_ids[NUM_LISTENERS] = { KEY_AGENT_PIPE_ID }; +static enum agent_type types[NUM_LISTENERS] = { KEY_AGENT }; +HANDLE event_stop_agent; - do { - if (action_queue & ACTION_SHUTDOWN) { - /* go through the list and disconect each connection */ - struct agent_connection* tmp = list; - while (tmp) { - agent_connection_disconnect(tmp); - tmp = tmp->next; - } +struct listener { + OVERLAPPED ol; + HANDLE pipe; + wchar_t *pipe_id; + enum agent_type type; + SECURITY_ATTRIBUTES sa; +} listeners[NUM_LISTENERS]; - /* remove unwanted queued actions */ - InterlockedAnd(&action_queue, ~ACTION_LISTEN); - if (InterlockedAnd(&action_queue, ~ACTION_SHUTDOWN) == ACTION_SHUTDOWN) - break; +static int +init_listeners() { + int i; + memset(listeners, 0, sizeof(listeners)); + for (i = 0; i < NUM_LISTENERS; i++) { + if ((listeners[i].ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { + debug("cannot create event ERROR:%d", GetLastError()); + return GetLastError(); } - else if (action_queue & ACTION_LISTEN) { - HANDLE h; - long prev_queue; - SECURITY_ATTRIBUTES sa; - struct agent_connection* con = - (struct agent_connection*)malloc(sizeof(struct agent_connection)); - memset(con, 0, sizeof(struct agent_connection)); - memset(&sa, 0, sizeof(sa)); - sa.bInheritHandle = FALSE; - sa.lpSecurityDescriptor = NULL; - h = CreateNamedPipeW( - AGENT_PIPE_ID, // pipe name - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access - PIPE_TYPE_BYTE | // message type pipe - PIPE_READMODE_BYTE | // message-read mode - PIPE_WAIT, // blocking mode - PIPE_UNLIMITED_INSTANCES, // max. instances - BUFSIZE, // output buffer size - BUFSIZE, // input buffer size - 0, // client time-out - &sa); + listeners[i].pipe_id = pipe_ids[i]; + listeners[i].type = types[i]; + listeners[i].pipe = INVALID_HANDLE_VALUE; + listeners[i].sa.bInheritHandle = TRUE; + } - /* remove action from queue before assigning iocp port*/ - con->connection = h; - con->next = list; - list = con; - prev_queue = InterlockedAnd(&action_queue, ~ACTION_LISTEN); - CreateIoCompletionPort(h, ioc_port, (ULONG_PTR)con, 0); - ConnectNamedPipe(h, &con->ol); - if (prev_queue == ACTION_LISTEN) - break; - } - else { - /* cleanup up a done connection*/ - struct agent_connection *prev = NULL, *tmp = list; - while (tmp) { - if (tmp->state == DONE) { - if (prev == NULL) - list = tmp->next; - else - prev->next = tmp->next; - CloseHandle(tmp->connection); - printf("deleting %p\n", tmp); - free(tmp); - break; - } - prev = tmp; - tmp = tmp->next; - } - if (InterlockedDecrement(&action_queue) == 0) - break; - } - } while (1); + return 0; } -void -agent_cleanup_connection(struct agent_connection* con) { - if (InterlockedIncrement(&action_queue) == 1) - agent_sm_process_action_queue(); +static void +agent_cleanup() { + int i; + for (i = 0; i < NUM_LISTENERS; i++) { + if (listeners[i].ol.hEvent != NULL) + CloseHandle(listeners[i].ol.hEvent); + if (listeners[i].pipe != INVALID_HANDLE_VALUE) + CloseHandle(listeners[i].pipe); + } + if (ioc_port) + CloseHandle(ioc_port); + return; } -void -agent_listen() { - if (InterlockedOr(&action_queue, ACTION_LISTEN) == 0) - agent_sm_process_action_queue(); -} - - -void agent_shutdown() { - if (InterlockedOr(&action_queue, ACTION_SHUTDOWN) == 0) - agent_sm_process_action_queue(); - while (list != NULL) - Sleep(100); - CloseHandle(ioc_port); -} - -HANDLE iocp_workers[4]; - -DWORD WINAPI iocp_work(LPVOID lpParam) { +static DWORD WINAPI +iocp_work(LPVOID lpParam) { DWORD bytes; struct agent_connection* con = NULL; OVERLAPPED *p_ol; @@ -141,35 +91,167 @@ DWORD WINAPI iocp_work(LPVOID lpParam) { con = NULL; p_ol = NULL; if (GetQueuedCompletionStatus(ioc_port, &bytes, &(ULONG_PTR)con, &p_ol, INFINITE) == FALSE) { - printf("error: %d on %p \n", GetLastError(), con); - if (con) + debug("iocp error: %d on %p \n", GetLastError(), con); + if (con) agent_connection_on_error(con, GetLastError()); else return 0; } - //printf("io on %p state %d bytes %d\n", con, con->state, bytes); - agent_connection_on_io(con, bytes, p_ol); + else + agent_connection_on_io(con, bytes, p_ol); } } -int agent_start(BOOL dbg, BOOL child, HANDLE pipe) { - int i; + +static int +process_connection(HANDLE pipe, int type) { + struct agent_connection* con; + + if ((con = malloc(sizeof(struct agent_connection))) == NULL) { + debug("out of memory"); + return ERROR_OUTOFMEMORY; + } + memset(con, 0, sizeof(struct agent_connection)); + con->connection = pipe; + con->type = type; + CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0); + agent_connection_on_io(con, 0, &con->ol); + iocp_work(NULL); +} + +static void +agent_listen_loop() { + DWORD i, r; + HANDLE wait_events[NUM_LISTENERS + 1]; + + wait_events[0] = event_stop_agent; + for (i = 0; i < NUM_LISTENERS; i++) + wait_events[i + 1] = listeners[i].ol.hEvent; + + while (1) { + for (i = 0; i < NUM_LISTENERS; i++) { + if (listeners[i].pipe == INVALID_HANDLE_VALUE) { + listeners[i].pipe = CreateNamedPipeW( + listeners[i].pipe_id, // pipe name + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access + PIPE_TYPE_BYTE | // message type pipe + PIPE_READMODE_BYTE | // message-read mode + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // max. instances + BUFSIZE, // output buffer size + BUFSIZE, // input buffer size + 0, // client time-out + &listeners[i].sa); + + if (listeners[i].pipe == INVALID_HANDLE_VALUE) { + debug("cannot create listener pipe ERROR:%d", GetLastError()); + SetEvent(event_stop_agent); + } + else if (ConnectNamedPipe(listeners[i].pipe, &listeners[i].ol) != FALSE) { + debug("ConnectNamedPipe returned unexpectedly"); + SetEvent(event_stop_agent); + } + + if (GetLastError() == ERROR_PIPE_CONNECTED) + SetEvent(listeners[i].ol.hEvent); + + if (GetLastError() != ERROR_IO_PENDING) { + debug("ConnectNamedPipe failed ERROR: %d", GetLastError()); + SetEvent(event_stop_agent); + } + + } + } + + r = WaitForMultipleObjects(NUM_LISTENERS + 1, wait_events, FALSE, INFINITE); + if (r == WAIT_OBJECT_0) { + //received signal to shutdown + debug("shutting down"); + agent_cleanup(); + return; + } + else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + NUM_LISTENERS))) { + /* process incoming connection */ + HANDLE con = listeners[r - 1].pipe; + listeners[r - 1].pipe = INVALID_HANDLE_VALUE; + + if (debug_mode) { + process_connection(con, listeners[r - 1].type); + agent_cleanup(); + return; + } + else { + /* todo - spawn a child to take care of this*/ + wchar_t path[MAX_PATH], module_path[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFO si; + + si.cb = sizeof(STARTUPINFO); + memset(&si, 0, sizeof(STARTUPINFO)); + GetModuleFileNameW(NULL, module_path, MAX_PATH); + swprintf_s(path, MAX_PATH, L"%s %d %d", module_path, con, listeners[r - 1].type); + if (CreateProcessW(NULL, path, NULL, NULL, TRUE, + DETACHED_PROCESS, NULL, NULL, + &si, &pi) == FALSE) { + debug("CreateProcess failure: %d", GetLastError()); + CloseHandle(con); + agent_cleanup(); + return; + } + + CloseHandle(con); + + } + + } + else { + debug("wait on events ended with %d ERROR:%d", r, GetLastError()); + agent_cleanup(); + return; + } + + } +} + +void agent_cleanup_connection(struct agent_connection* con) { + debug("connection %p clean up", con); + CloseHandle(con->connection); + free(con); + CloseHandle(ioc_port); + ioc_port = NULL; +} + +void agent_shutdown() { + SetEvent(event_stop_agent); +} + +int agent_start(BOOL dbg_mode, BOOL child, HANDLE pipe, enum agent_type type) { + int i, r; HKEY agent_root; DWORD process_id = GetCurrentProcessId(); - debug("agent_start pid:%d, dbg:%d, child:%d, pipe:%d", process_id, dbg, child, pipe); - action_queue = 0; - list = NULL; - ioc_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); + debug("agent_start pid:%d, dbg:%d, child:%d, pipe:%d", process_id, dbg_mode, child, pipe); + debug_mode = dbg_mode; - for (i = 0; i < 3; i++) - QueueUserWorkItem(iocp_work, NULL, 0); + if ((ioc_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0)) == NULL) { + debug("cannot create ioc port ERROR:%d", GetLastError()); + return GetLastError(); + } + + if (child == FALSE) { + RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_ROOT, 0, 0, 0, KEY_WRITE, 0, &agent_root, 0); + RegSetValueExW(agent_root, L"ProcessID", 0, REG_DWORD, (BYTE*)&process_id, 4); + if ((event_stop_agent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) + return GetLastError(); + if ((r = init_listeners()) != 0) + return r; + agent_listen_loop(); + } + else { + return process_connection(pipe, type); + } - agent_listen(); - RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_ROOT, 0, 0, 0, KEY_WRITE, 0, &agent_root, 0); - RegSetValueExW(agent_root, L"ProcessID", 0, REG_DWORD, (BYTE*)&process_id, 4); - iocp_work(NULL); - return 1; + return 0; } diff --git a/contrib/win32/win32compat/ssh-agent/agent.h b/contrib/win32/win32compat/ssh-agent/agent.h index f18c3e5..927893a 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.h +++ b/contrib/win32/win32compat/ssh-agent/agent.h @@ -7,6 +7,13 @@ #define SSHD_KEYS_ROOT SSH_ROOT L"\\Keys" #define HEADER_SIZE 4 + +enum agent_type { + KEY_AGENT, + PUBKEY_AGENT, + PUBKEY_AUTH_AGENT +}; + struct agent_connection { OVERLAPPED ol; HANDLE connection; @@ -23,14 +30,13 @@ struct agent_connection { WRITING, DONE } state; - struct agent_connection* next; + enum agent_type type; }; void agent_connection_on_io(struct agent_connection*, DWORD, OVERLAPPED*); void agent_connection_on_error(struct agent_connection* , DWORD ); void agent_connection_disconnect(struct agent_connection*); -int agent_start(BOOL debug, BOOL child, HANDLE pipe); +int agent_start(BOOL, BOOL, HANDLE, enum agent_type); void agent_shutdown(); -void agent_listen(); -void agent_cleanup_connection(struct agent_connection*); +void agent_cleanup_connection(struct agent_connection*); \ No newline at end of file diff --git a/contrib/win32/win32compat/ssh-agent/connection.c b/contrib/win32/win32compat/ssh-agent/connection.c index 2e51249..2c07564 100644 --- a/contrib/win32/win32compat/ssh-agent/connection.c +++ b/contrib/win32/win32compat/ssh-agent/connection.c @@ -46,6 +46,7 @@ void agent_connection_on_error(struct agent_connection* con, DWORD error) { void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPED* ol) { /* process error */ + debug("connection io %p #bytes:%d state:%d", con, bytes, con->state); if ((bytes == 0) && (GetOverlappedResult(con->connection, ol, &bytes, FALSE) == FALSE)) ABORT_CONNECTION_RETURN(con); @@ -56,7 +57,6 @@ void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPE { switch (con->state) { case LISTENING: - agent_listen(); case WRITING: /* Writing is done, read next request */ /* assert on assumption that write always completes on sending all bytes*/