Authentifizierungs-Bypass: OpenSSL CTX-Objekt nach Erstellung von SSL-Objekten modifiziert
Beschreibung
Authentifizierungs-Bypass: OpenSSL CTX-Objekt nach Erstellung von SSL-Objekten modifiziert tritt auf, wenn eine Anwendung SSL_CTX-Sicherheitseinstellungen (wie den Zertifikatsverifizierungsmodus) ändert, nachdem SSL-Objekte bereits aus diesem Kontext erstellt wurden. In OpenSSL erben SSL-Objekte Einstellungen von ihrem CTX zum Erstellungszeitpunkt. Spätere Modifikationen am CTX beeinflussen existierende SSL-Objekte nicht, was bedeutet, dass Sicherheitseinstellungen möglicherweise nicht wie beabsichtigt angewendet werden.
Risiko
Anwendungen können glauben, sie hätten Zertifikatsverifizierung oder andere Sicherheitsfeatures aktiviert, wenn tatsächlich die SSL-Verbindungen die ursprünglichen, potenziell unsicheren Einstellungen verwenden. Dies kann zu Man-in-the-Middle-Angriffen, Verbindung zu bösartigen Servern ohne Zertifikatsvalidierung oder Akzeptanz ungültiger Zertifikate führen. Der Code erscheint bei der Überprüfung sicher, arbeitet aber tatsächlich unsicher.
Lösung
Konfigurieren Sie SSL_CTX immer vollständig, bevor Sie SSL-Objekte daraus erstellen. Setzen Sie Verifizierungsmodi, Zertifikatsketten, Cipher-Suites und alle anderen Sicherheitsparameter zuerst am CTX. Wenn Einstellungen dynamisch geändert werden müssen, erstellen Sie einen neuen SSL_CTX mit den aktualisierten Einstellungen oder wenden Sie Änderungen direkt auf einzelne SSL-Objekte mit SSL_set_verify() und ähnlichen Funktionen an.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Authentifizierung | Bereich: Bypass Zertifikatsverifizierung wird möglicherweise nicht durchgesetzt, obwohl Code sie setzt. |
| Vertraulichkeit | Bereich: MITM-Exposure Verbindungen können anfällig für Abfangen sein. |
| Integrität | Bereich: Datenmanipulation Unverifizierte Verbindungen erlauben Datenmodifikation. |
Beispielcode + Lösungscode
Verwundbarer Code
// VERWUNDBAR: CTX nach SSL-Objekt-Erstellung modifiziert
SSL_CTX* ctx;
SSL* ssl;
void init_ssl_vulnerable() {
ctx = SSL_CTX_new(TLS_client_method());
// SSL-Objekt mit aktuellen CTX-Einstellungen erstellen
ssl = SSL_new(ctx); // Erbt Einstellungen JETZT
// Später: Versuchen Verifizierung zu aktivieren
// FEHLER: Dies beeinflusst bereits erstelltes ssl-Objekt nicht!
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations(ctx, "ca-bundle.crt", NULL);
// ssl hat immer noch keine Verifizierung aktiviert!
}
void connect_vulnerable(int fd) {
SSL_set_fd(ssl, fd);
// Verbindet ohne Zertifikatsverifizierung!
if (SSL_connect(ssl) <= 0) {
handle_error();
}
// Verbindung ist unsicher trotz CTX-Einstellungen
}
// VERWUNDBAR: Verzögerte Sicherheitskonfiguration
SSL_CTX* create_context_vulnerable() {
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
return ctx; // Gibt ohne Sicherheitseinstellungen zurück
}
void use_context_vulnerable(SSL_CTX* ctx) {
// Verbindungen erstellen
SSL* ssl1 = SSL_new(ctx); // Keine Verifizierung
SSL* ssl2 = SSL_new(ctx); // Keine Verifizierung
// Jetzt versuchen den Kontext zu sichern
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
// ssl1 und ssl2 sind immer noch unsicher!
// Nur neue SSL-Objekte bekommen die Einstellungen
SSL* ssl3 = SSL_new(ctx); // Dieses hat Verifizierung
}
// VERWUNDBAR: Verbindungspool mit später Konfiguration
typedef struct {
SSL_CTX* ctx;
SSL* connections[10];
int count;
} ConnectionPool;
void init_pool_vulnerable(ConnectionPool* pool) {
pool->ctx = SSL_CTX_new(TLS_client_method());
pool->count = 0;
// SSL-Objekte für Pooling vorab erstellen
for (int i = 0; i < 10; i++) {
pool->connections[i] = SSL_new(pool->ctx);
}
}
void secure_pool_vulnerable(ConnectionPool* pool) {
// Versuchen Sicherheit nach Pool-Erstellung hinzuzufügen
// FEHLER: Beeinflusst vorab erstellte Verbindungen nicht!
SSL_CTX_set_verify(pool->ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations(pool->ctx, "certs/ca.pem", NULL);
}
// VERWUNDBAR: Bedingte Sicherheit die zu spät kommt
void conditional_security_vulnerable(int require_certs) {
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
SSL* ssl = SSL_new(ctx); // Erstellt vor Bedingungsprüfung
if (require_certs) {
// Zu spät! ssl existiert bereits
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
}
// Selbst mit require_certs=1 hat ssl keine Verifizierung
}
// VERWUNDBAR: C++ Klasse mit Initialisierungsreihenfolge-Problem
class VulnerableSSLClient {
SSL_CTX* ctx;
SSL* ssl;
public:
VulnerableSSLClient() {
ctx = SSL_CTX_new(TLS_client_method());
ssl = SSL_new(ctx); // Sofort erstellt
}
void enableVerification() {
// Nach Konstruktor aufgerufen - zu spät!
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr);
}
void connect(const char* host, int port) {
// ssl hat keine Verifizierung unabhängig von enableVerification()-Aufrufen
int fd = create_socket(host, port);
SSL_set_fd(ssl, fd);
SSL_connect(ssl);
}
};
// Verwendung - erscheint sicher, ist es aber nicht
void use_vulnerable() {
VulnerableSSLClient client;
client.enableVerification(); // Zu spät!
client.connect("server.com", 443); // Unsichere Verbindung
}
Lösungscode
// SICHER: CTX vor SSL-Objekt-Erstellung konfigurieren
SSL_CTX* ctx;
SSL* ssl;
void init_ssl_safe() {
ctx = SSL_CTX_new(TLS_client_method());
// ALLE Sicherheitseinstellungen ZUERST konfigurieren
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations(ctx, "ca-bundle.crt", NULL);
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
// JETZT SSL-Objekt erstellen - erbt alle Einstellungen
ssl = SSL_new(ctx);
}
void connect_safe(int fd) {
SSL_set_fd(ssl, fd);
if (SSL_connect(ssl) <= 0) {
handle_error();
return;
}
// Verifizieren dass Zertifikat tatsächlich geprüft wurde
if (SSL_get_verify_result(ssl) != X509_V_OK) {
handle_verification_failure();
SSL_shutdown(ssl);
return;
}
// Verbindung ist sicher
}
// SICHER: Vollständige Kontextkonfiguration vor Verwendung
SSL_CTX* create_secure_context() {
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
if (ctx == NULL) return NULL;
// Alles vor Rückgabe konfigurieren
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
if (!SSL_CTX_load_verify_locations(ctx, "ca-bundle.crt", NULL)) {
SSL_CTX_free(ctx);
return NULL;
}
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
return ctx;
}
// SICHER: Einstellungen auf einzelne SSL-Objekte anwenden wenn nötig
void apply_settings_to_ssl(SSL* ssl) {
// Kann einzelne SSL-Objekte direkt modifizieren
SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
}
// SICHER: Verbindungspool mit ordnungsgemäßer Initialisierung
typedef struct {
SSL_CTX* ctx;
SSL* connections[10];
int count;
} SecureConnectionPool;
void init_pool_safe(SecureConnectionPool* pool) {
pool->ctx = SSL_CTX_new(TLS_client_method());
// Sicherheit VOR Verbindungserstellung konfigurieren
SSL_CTX_set_verify(pool->ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations(pool->ctx, "certs/ca.pem", NULL);
SSL_CTX_set_min_proto_version(pool->ctx, TLS1_2_VERSION);
// JETZT Pool-Verbindungen erstellen - sie erben Einstellungen
pool->count = 0;
for (int i = 0; i < 10; i++) {
pool->connections[i] = SSL_new(pool->ctx);
}
}
// SICHER: Neuen CTX erstellen wenn Einstellungen sich ändern
SSL_CTX* update_security_settings(SSL_CTX* old_ctx, int new_settings) {
// Neuen Kontext mit neuen Einstellungen erstellen
SSL_CTX* new_ctx = SSL_CTX_new(TLS_client_method());
// Neue Einstellungen anwenden
if (new_settings & REQUIRE_CLIENT_CERT) {
SSL_CTX_set_verify(new_ctx,
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
}
// Alte SSL-Objekte verwenden noch old_ctx
// Neue SSL-Objekte verwenden new_ctx mit neuen Einstellungen
return new_ctx;
}
// SICHER: Factory-Pattern für ordnungsgemäße Initialisierung
typedef struct {
SSL_CTX* ctx;
int initialized;
} SSLFactory;
int init_factory(SSLFactory* factory) {
factory->ctx = SSL_CTX_new(TLS_client_method());
if (!factory->ctx) return -1;
// Alle Sicherheitseinstellungen hier konfiguriert
SSL_CTX_set_verify(factory->ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations(factory->ctx, "ca-bundle.crt", NULL);
SSL_CTX_set_min_proto_version(factory->ctx, TLS1_2_VERSION);
factory->initialized = 1;
return 0;
}
SSL* create_ssl_from_factory(SSLFactory* factory) {
if (!factory->initialized) {
return NULL; // Factory nicht bereit
}
// SSL-Objekte immer aus vollständig konfiguriertem CTX erstellt
return SSL_new(factory->ctx);
}
// SICHER: C++ Klasse mit ordnungsgemäßer Initialisierungsreihenfolge
class SafeSSLClient {
SSL_CTX* ctx;
SSL* ssl;
void configureContext() {
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr);
SSL_CTX_load_verify_locations(ctx, "ca-bundle.crt", nullptr);
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
}
public:
SafeSSLClient() {
ctx = SSL_CTX_new(TLS_client_method());
// VOR SSL-Objekt-Erstellung konfigurieren
configureContext();
// JETZT SSL erstellen - erbt alle Einstellungen
ssl = SSL_new(ctx);
}
bool connect(const char* host, int port) {
int fd = create_socket(host, port);
SSL_set_fd(ssl, fd);
if (SSL_connect(ssl) <= 0) {
return false;
}
// Zertifikat verifizieren
return SSL_get_verify_result(ssl) == X509_V_OK;
}
~SafeSSLClient() {
if (ssl) SSL_free(ssl);
if (ctx) SSL_CTX_free(ctx);
}
};
// SICHER: Builder-Pattern für SSL-Konfiguration
class SSLContextBuilder {
SSL_CTX* ctx;
public:
SSLContextBuilder() {
ctx = SSL_CTX_new(TLS_client_method());
}
SSLContextBuilder& withPeerVerification() {
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr);
return *this;
}
SSLContextBuilder& withCAFile(const char* path) {
SSL_CTX_load_verify_locations(ctx, path, nullptr);
return *this;
}
SSLContextBuilder& withMinVersion(int version) {
SSL_CTX_set_min_proto_version(ctx, version);
return *this;
}
SSL* createSSL() {
// SSL erst nach aller Konfiguration erstellt
return SSL_new(ctx);
}
SSL_CTX* getContext() { return ctx; }
};
// Verwendung
void use_safe() {
SSLContextBuilder builder;
builder.withPeerVerification()
.withCAFile("ca-bundle.crt")
.withMinVersion(TLS1_2_VERSION);
SSL* ssl = builder.createSSL(); // Ordnungsgemäß konfiguriert
}
Ausgenutzt in der Praxis
Zertifikatsverifizierungs-Bypass
Anwendungen, die Zertifikatsverifizierung zu aktivieren schienen, aber tatsächlich ohne Validierung verbanden, wurden für MITM-Angriffe ausgenutzt.
Mobile App SSL-Schwachstellen
Mehrere mobile Anwendungen hatten dieses Schwachstellenmuster, das Traffic-Abfangen ermöglichte.
IoT-Gerätesicherheit
Eingebettete Geräte mit verzögerter SSL-Konfiguration wurden durch Netzwerkangriffe kompromittiert.
Tools zum Testen/Ausnutzen
- SSLyze — SSL/TLS-Konfigurationsanalyse
- testssl.sh — SSL/TLS-Testtool
- mitmproxy — HTTPS-Traffic abfangen und inspizieren
- Burp Suite — Web-Sicherheitstests
CVE-Beispiele
- CVEs in Anwendungen mit unsachgemäßem SSL_CTX-Konfigurations-Timing
- Zertifikatsvalidierungs-Bypass-Schwachstellen
- MITM-Schwachstellen durch Initialisierungsreihenfolge-Probleme
Referenzen
- MITRE. "CWE-593: Authentication Bypass: OpenSSL CTX Object Modified after SSL Objects are Created." https://cwe.mitre.org/data/definitions/593.html
- OpenSSL Documentation. SSL_CTX_set_verify man page.