Added writeups
This commit is contained in:
111
de/selective_security.md
Normal file
111
de/selective_security.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# 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!
|
||||
Reference in New Issue
Block a user