Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

FeedsKontaktDatenschutz© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2020-28018 — Exploit für Exim Use-After-Free (CVE-2020-28018), der über Memory-Corruption-Primitive Remote-Codeausführung erreicht, einschließlich beliebigem Lesen/Schreiben und Heap-Leak, mit optionaler Kette zur lokalen Privilegienausweitung. | Kitploit
Tools/GitHubGitHub/dorkerdevil/cve-2020-28018
Privilege EscalationSpeicherforensikSchwachstellenanalyseExploitationRemote-Access-ToolPayload-EntwicklungBinary-Exploitation
GitHubdorkerdevil/cve-2020-28018

CVE-2020-28018

Exploit für Exim Use-After-Free (CVE-2020-28018), der über Memory-Corruption-Primitive Remote-Codeausführung erreicht, einschließlich beliebigem Lesen/Schreiben und Heap-Leak, mit optionaler Kette zur lokalen Privilegienausweitung.

Repository anzeigen
7112vor 5 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2020-28018: Exim Use-After-Free (UAF) mit RCE-Folge

Einleitung

Es existiert eine Use-After-Free (UAF)-Schwachstelle in tls-openssl.c, die es entfernten, nicht authentifizierten Angreifern ermöglicht, interne Speicherdaten zu korrumpieren und schließlich eine entfernte Codeausführung (Remote Code Execution, RCE) zu erreichen.

Primitive:

  • Speicherleck (Memory Leak)
  • Beliebiges Lesen (Arbitrary Read Primitive)
  • Schreiben-an-beliebiger-Stelle (Write-What-Where Primitive)

Durch die Verkettung all dieser Primitive ist es möglich, alle verfügbaren Exploit-Mitigations vollständig zu umgehen und schließlich eine entfernte Codeausführung als der Exim-Benutzer zu erreichen.

Diese Schwachstelle wurde zusammen mit einer großen Liste weiterer Schwachstellen veröffentlicht. Der offizielle Qualys-Bericht verkettet den Use-After-Free mit CVE-2020-28008, um eine lokale Privilegienerweiterung (Local Privilege Escalation, LPE) durchzuführen, nachdem RCE erreicht wurde.

Voraussetzungen

Exim muss wie folgt konfiguriert/kompiliert sein:

  • TLS ist aktiviert
  • OpenSSL wird verwendet (anstelle von GnuTLS)
  • Exim ist eine der verwundbaren Versionen
  • X_PIPE_CONNECT ist deaktiviert

Sie können das Skript checker.py verwenden, um zu prüfen, ob ein entfernter Server eine verwundbare Version hat und einige notwendige Voraussetzungen für die Ausnutzbarkeit erfüllt.

[!] checker.py löst die Schwachstelle NICHT aus, sondern prüft lediglich auf eine verwundbare Version und ob PIPELINING und TLS aktiviert sind. Das bedeutet, dass dieses Prüfprogramm nicht auf den Patch prüft, was zu Fehlalarmen führen kann.

Verwundbarer Code

Wie bereits bekannt, befindet sich die Schwachstelle in tls-openssl.c.

/*************************************************
*         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)
{
int outbytes, error, left;
SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
static gstring * corked = NULL;

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. */
/*XXX + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
a store reset there. */

if (!ct_ctx && (more || corked))
  {
#ifdef EXPERIMENTAL_PIPE_CONNECT
  int save_pool = store_pool;
  store_pool = POOL_PERM;
#endif

  corked = string_catn(corked, buff, len);

#ifdef EXPERIMENTAL_PIPE_CONNECT
  store_pool = save_pool;
#endif

  if (more)
    return len;
  buff = CUS corked->s;
  len = corked->ptr;
  corked = NULL;
  }

for (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 len;
}

smtp_setup_msg() ist die Hauptfunktion, die das Lesen von Nachrichten vom Client durchführt.

In bestimmten Situationen wird smtp_reset() aufgerufen, das eine Bereinigung aller Puffer und Werte durchführt.

Dies kann in Situationen wie den folgenden passieren:

  • HELO/EHLO wird empfangen
  • STARTTLS wird empfangen
  • RSET wird empfangen
  • Beim Start von smtp_setup_msg()

Am Ende von smtp_reset() wird ein Aufruf von store_reset() durchgeführt.

store_reset ist ein Makro, das die Funktion store_reset_3() umschließt.

Die Store-Funktionen sind lediglich Funktionen, die den dynamischen Speicher verwalten.

Exim verwendet einen Pool-Allokator für Blöcke, die von malloc empfangen werden.

Es gibt auch eine interessante Funktionalität: eine implementierung von wachsenden Strings (growable string).

gstring-Struktur:

typedef struct gstring {
  int   size;           /* Current capacity of string memory */
  int   ptr;            /* Offset at which to append further chars */
  uschar * s;           /* The string memory */
} gstring;

Wenn mehr Platz zum Verketten eines neuen Strings benötigt wird, wird gstring_grow() aufgerufen.

Diese Funktion versucht zunächst, store_extend_3() aufzurufen, das versucht, den Speicher innerhalb des gleichen Pool-Blocks zu erweitern.

Dies kann nützlich sein, wenn die Länge der Eingabe unbekannt ist, aber wenn nach dem zu erweiternden Speicher mehr Speicher allokiert wurde, kann eine Erweiterung nicht durchgeführt werden.

Dann ruft gstring_grow() store_newblock_3() auf, das einfach neuen Speicher zurückgibt und die bereits vorhandenen Bytes vom alten in den neuen Speicher kopiert.

Dann wird der Zeiger g->s von gstring_catn() wiederhergestellt.

In der Funktion tls_write() sehen wir einen BOOL namens more.

Er gibt an, ob noch mehr Daten in den String-Puffer kopiert werden müssen, bevor die Daten an den Benutzer zurückgegeben werden.

Wenn ja, wird der Zeiger nicht auf NULL gesetzt.

Wenn nicht, werden die im String-Puffer enthaltenen Daten an den Benutzer zurückgegeben.

Diese Funktionalität eröffnet einige interessante Wege, einen Use-After-Free auszulösen.

Zunächst wird der Zeiger auf die gstring-Struktur in einer statischen Variable gespeichert. Das bedeutet, dass wir ihn bei zukünftigen Aufrufen von tls_write() verwenden können.

Wie können wir den Puffer freigeben und ihn dann trotzdem nutzen?

Wir müssen erreichen, dass smtp_setup_msg() smtp_reset() aufruft, nachdem sich einer unserer Puffer noch in server_corked befindet (nicht auf NULL gesetzt).

Nach dem Zurücksetzen wird der Zeiger, wenn wir tls_write() irgendwie aufrufen, immer noch vorhanden sein, sodass wir ihn nutzen können, nachdem der Speicher freigegeben wurde.

smtp_reset() gibt den gesamten Speicher von POOL_MAIN frei, in dem sich unser Puffer befindet.

Auslösen des Use-After-Free

Um den Use-After-Free zu kontrollieren, müssen wir zunächst eine neue Verbindung initialisieren.

Da wir tls_write() ausnutzen wollen, müssen wir zuerst eine neue TLS-Sitzung starten.

Also senden wir zuerst einen EHLO-Befehl, gefolgt von einem STARTTLS, um die TLS-Verbindung zu starten.

Um dann more auf 1 zu setzen, pipelinieren wir einen Befehl, und der letzte wird die Hälfte eines NOOP sein.

Wir schließen die TLS-Verbindung und senden den Rest des NOOP-Befehls.

Wir senden erneut EHLO, was dazu führt, dass smtp_reset aufgerufen wird und unseren Puffer freigibt.

Jetzt müssen wir eine weitere TLS-Verbindung starten, um tls_write() wieder nutzen zu können.

Wir senden STARTTLS.

Tool herunterladen