Sploitus

Exploit for CVE-2020-28018

kitploit · 2026-08-27

Exploit Code

MARKDOWN132 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-ZR0TT-CVE-2020-28018
# PoC CVE-2020-28018

## Введение

Команда Qualys обнаружила и опубликовала 21 критическую уязвимость в почтовом сервере Exim4.

https://blog.qualys.com/vulnerabilities-research/2021/05/04/21nails-multiple-vulnerabilities-in-exim-mail-server

По следующей ссылке предоставлена подробная техническая информация об уязвимостях и их эксплуатации.

https://www.qualys.com/2021/05/04/21nails/21nails.txt

В этом репозитории мы сосредоточимся на CVE-2020-28018, которая позволяет удаленно выполнять код, эксплуатируя уязвимость Use-after-free.

## Требования

  * STARTTLS включен (по умолчанию)
  * PIPELINING включен (по умолчанию)
  * X_PIPE_CONNECT отключен (по умолчанию до Exim 4.94)
  * Exim4 скомпилирован с библиотекой OpenSSL. (Требуется перекомпиляция, объяснено ниже)
  * Все тесты проводились с Exim 4-4.93 из репозитория исходных кодов Ubuntu 20.04.



## Уязвимость

Уязвимость находится в функции tls_write() в файле tls-openssl.c

root@kitploit:~
    
    
    /*************************************************
    *         Write bytes down TLS channel           *
    *************************************************/
    
    /*
    Arguments:
      ct_ctx    client context pointer, or NULL for the one global server context
      buff      buffer of data
      len       number of bytes
      more	    further data expected soon
    
    Returns:    the number of bytes after a successful write,
                -1 after a failed write
    
    Used by both server-side and client-side TLS.
    */
    
    int
    tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more)
    {
    size_t olen = len;
    int outbytes, error;
    SSL * ssl = ct_ctx
      ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
    static gstring * server_corked = NULL;
    gstring ** corkedp = ct_ctx
      ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked;
    gstring * corked = *corkedp;
    
    DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
      buff, (unsigned long)len, more ? ", more" : "");
    
    /* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when
    "more" is notified.  This hack is only ok if small amounts are involved AND only
    one stream does it, in one context (i.e. no store reset).  Currently it is used
    for the responses to the received SMTP MAIL , RCPT, DATA sequence, only.
    We support callouts done by the server process by using a separate client
    context for the stashed information. */
    /* + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
    a store reset there, so use POOL_PERM. */
    /* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
    
    if ((more || corked))
      {
    #ifdef SUPPORT_PIPE_CONNECT
      int save_pool = store_pool;
      store_pool = POOL_PERM;
    #endif
    
      corked = string_catn(corked, buff, len);
    
    #ifdef SUPPORT_PIPE_CONNECT
      store_pool = save_pool;
    #endif
    
      if (more)
        {
        *corkedp = corked;
        return len;
        }
      buff = CUS corked->s;
      len = corked->ptr;
      *corkedp = NULL;
      }
    
    for (int left = len; left > 0;)
      {
      DEBUG(D_tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, buff, left);
      outbytes = SSL_write(ssl, CS buff, left);
      error = SSL_get_error(ssl, outbytes);
      DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error);
      switch (error)
        {
        case SSL_ERROR_SSL:
          ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
          log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring);
          return -1;
    
        case SSL_ERROR_NONE:
          left -= outbytes;
          buff += outbytes;
          break;
    
        case SSL_ERROR_ZERO_RETURN:
          log_write(0, LOG_MAIN, "SSL channel closed on write");
          return -1;
    
        case SSL_ERROR_SYSCALL:
          log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
    	sender_fullhost ? sender_fullhost : US"<unknown>",
    	strerror(errno));
          return -1;
    
        default:
          log_write(0, LOG_MAIN, "SSL_write error %d", error);
          return -1;
        }
      }
    return olen;
    }