Files
HIP7CTF_Writeups/de/selective_security.md
m0rph3us1987 a79656b647 Added writeups
2026-03-08 12:22:39 +01:00

112 lines
5.2 KiB
Markdown

# Selective Security
Willkommen zum Write-up für **Selective Security**. Dies ist eine einführende "Web" (Web Exploitation) Challenge, die eine der kritischsten und am weitesten verbreiteten Schwachstellen in der Geschichte von Webanwendungen demonstriert: **SQL Injection (SQLi)**.
In dieser Challenge wird uns ein scheinbar sicheres Login-Portal präsentiert, das "Standard"-Benutzer von "Administratoren" trennt. Unsere Mission ist es, den Authentifizierungsmechanismus zu umgehen und Zugriff auf das eingeschränkte Admin-Dashboard zu erhalten, um die Flagge abzurufen.
---
## 1. Erste Erkundung
Die Challenge stellt uns einen Link zu einem "Internen Blog-Portal" und ein herunterladbares Archiv zur Verfügung: `selective_security.tar.xz`.
Wenn wir das Portal besuchen, werden wir von einem Login-Formular begrüßt. Wir können versuchen, uns mit zufälligen Anmeldeinformationen (z.B. `guest`/`guest`) anzumelden, was uns Zugriff als "Standardbenutzer" gewährt. Wir sehen einen einfachen Blog-Feed, aber keine Flagge. Die Challenge-Beschreibung sagt uns, dass die "tatsächlichen administrativen Funktionen durch eine strenge Datenbanküberprüfung geschützt sind". Um die Flagge zu erhalten, müssen wir uns als **admin**-Benutzer anmelden.
## 2. Quellcode-Analyse
Da wir den Quellcode in `selective_security.tar.xz` erhalten haben, können wir genau sehen, wie der Server unseren Anmeldeversuch behandelt. Nach dem Entpacken des Archivs finden wir eine einzelne Datei: `main.go`.
Wenn wir uns die `loginHandler`-Funktion ansehen, sehen wir, wie die Anwendung zwischen Benutzern unterscheidet:
```go
func loginHandler(w http.ResponseWriter, r *http.Request) {
// ...
username := r.FormValue("username")
password := r.FormValue("password")
if username == "admin" {
handleAdminLogin(w, password)
} else {
// Standardbenutzer erhalten das fakeUserTmpl (keine Flagge)
data := map[string]string{"Username": username}
renderTemplate(w, fakeUserTmpl, data)
}
}
```
Wenn wir den Benutzernamen `admin` angeben, ruft die Anwendung `handleAdminLogin` auf. Hier findet die "strenge Datenbanküberprüfung" statt:
```go
func handleAdminLogin(w http.ResponseWriter, password string) {
// Query erstellen
query := fmt.Sprintf("SELECT id FROM users WHERE username = 'admin' AND password = '%s'", password)
log.Println("Executing Query:", query)
var id int
err := db.QueryRow(query).Scan(&id)
if err == nil {
// ERFOLG: Die Datenbank hat einen passenden Datensatz gefunden!
data := map[string]string{"Flag": globalFlag}
renderTemplate(w, successTmpl, data)
} else {
// ... Fehlerbehandlung ...
}
}
```
## 3. Die Schwachstelle: SQL Injection
Die Schwachstelle liegt darin, wie die SQL-Abfrage konstruiert wird. Die Anwendung verwendet `fmt.Sprintf`, um unser `password` direkt in den Abfrage-String einzufügen:
`"SELECT id FROM users WHERE username = 'admin' AND password = '%s'"`
Dies ist eine klassische **SQL Injection** Schwachstelle. Da die Anwendung keine **parametrisierten Abfragen** (Platzhalter wie `?`) verwendet, behandelt sie unsere Eingabe als Teil des SQL-Befehls selbst und nicht nur als Daten.
## 4. Entwicklung des Exploits
Wir kennen das Passwort des Admins nicht, aber wir können SQL-Syntax verwenden, um die Logik der `WHERE`-Klausel zu ändern. Unser Ziel ist es, die gesamte Bedingung zu **WAHR** auszuwerten, damit die Datenbank ein Ergebnis zurückgibt.
Wenn wir den folgenden Payload als Passwort eingeben:
`' OR '1'='1`
Die endgültige von der Datenbank ausgeführte Abfrage wird zu:
```sql
SELECT id FROM users WHERE username = 'admin' AND password = '' OR '1'='1'
```
### Aufschlüsselung der Logik:
1. `username = 'admin' AND password = ''`: Dieser Teil wird zuerst ausgewertet (aufgrund der Operator-Rangfolge) und ist wahrscheinlich **Falsch**.
2. `OR '1'='1'`: Dieser Teil ist immer **Wahr**.
3. `Falsch ODER Wahr` ergibt **Wahr**.
Die Datenbank ignoriert die falsche Passwortprüfung und gibt die ID des Admins zurück. Der Go-Code sieht, dass eine Zeile zurückgegeben wurde (`err == nil`) und gewährt uns Zugriff auf das Dashboard.
## 5. Ausnutzung
1. Navigieren Sie zur Login-Seite.
2. Benutzername eingeben: `admin`
3. Passwort eingeben: `' OR '1'='1`
4. Klicken Sie auf **Login**.
Die Seite "Administrator Access Granted" erscheint und zeigt die Flagge an.
**Flag:** `{flag:Sql_Inj3ct10n_Is_Ez_Pz_Read_From_File}`
---
## Gelernte Lektionen
Diese Challenge hebt hervor, warum Sie **niemals** Benutzereingaben vertrauen sollten, wenn Sie Datenbankabfragen erstellen. Selbst eine einzige Schwachstelle wie diese kann einem Angreifer vollen Zugriff auf sensible Daten oder administrative Konten gewähren.
Um dies zu verhindern, verwenden Sie immer **parametrisierte Abfragen** (auch bekannt als Prepared Statements). In Go wäre der sichere Weg, diese Abfrage zu schreiben:
```go
// SICHERE VERSION
db.QueryRow("SELECT id FROM users WHERE username = 'admin' AND password = ?", password)
```
Durch die Verwendung des `?`-Platzhalters stellt der Datenbanktreiber sicher, dass die Eingabe strikt als String behandelt wird, was es für den Benutzer unmöglich macht, "auszubrechen" und SQL-Befehle zu injizieren.
Frohes Hacken!