Waarschijnlijk lag de firewall er ook uit (want hoe anders kun je ongemerkt een database aftasten?), en was er een standaard installatie van een database applicatie en was het wachtwoord admin1.
Dit hoeft niet eens. Laat de website zelf de database connectie opzetten en wat "aangepaste" queries uitvoeren. Op wat rare requests na in het access log van de server zie je er niks van. Het is helemaal niet nodig om een remote connectie met de db server te maken (en daarbij de gebruikersnaam en het wachtwoord te weten).
Dat is net het hele punt van SQL injection. Doordat de site lek is kun je de queries zo vanuit de browser manipuleren. Een simpel voorbeeld, ik heb dit in PHP staan:
$select = "SELECT id, title, content FROM pages WHERE id = '" . $_GET['page'] . "'";
$result = mysql_query($select);
while($row = mysql_fetch_assoc($result))
{
echo '<h1>' . $row['title'] . '</h1>';
echo $row['content'];
}
De pagina wordt dan dus opgevraagd middels pagina.php?page=1. Doordat er geen validatie en escaping plaatsvind op $_GET['page'] kun je dus zo de query manipuleren. Maak je pagina.php?page=1' ervan (met quoteje), krijg je (standaard) van PHP een warning dat de param van mysql_fetch_assoc() geen resource (query resultaat) is. Dit geeft dus al een enorme hint weg voor de hacker. In sommige gevallen is het zelfs zo erg dat er controle plaatsvind of de query gelukt is, en als dat het niet geval is wordt mysql_error() (error van de database) weergegeven en soms wordt daarnaast zelfs nog de volledige query geprint (hallo... hoeveel informatie wil je kwijt geven? en een normale gebruiker heeft er niet eens iets aan).
Door bovenstaande aanvraag aan te passen naar pagina.php?page=1' OR 1=1 krijg je alle pagina's te zien (1=1 is altijd waar, dus alle rijen worden opgehaald). Maar de leuke dingen beginnen pas als je met UNION gaat spelen. Met UNION kun je de resultaten van twee SELECT queries samenvoegen. Door vervolgens een tweede SELECT te doen van de INFORMATION_SCHEMA.COLUMNS tabel is het
heel eenvoudig om de volledige database structuur op te halen (SELECT TABLE_NAME, GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() GROUP BY TABLE_NAME). Het enige "probleem" waar je nog tegenaan loopt is hoeveel kolommen je moet ophalen (bij UNION moeten beide SELECTs wel hetzelfde aantal kolommen hebben). Dit kun je echter gewoon proberen (UNION SELECT 1, 2, ... en op het moment dat je geen error krijgt heb je het juiste aantal kolommen te pakken, en weet je welke kolomnummers worden weergegeven en je dus moet gebruiken).
Door de aanvraag dus aan te passen naar pagina.php?page=-1' UNION SELECT 1, table_name, GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema = DATABASE() GROUP BY table_name krijg je dus een pagina waarop de namen van
alle tabellen staan, met per tabel
alle kolommen. Met deze informatie kun je vervolgens weer de UNION SELECT aanpassen naar een SELECT 1, username, password FROM users (bv.) en hoplakkee, alle gebruikersnamen met daarbij het wachtwoord.
Dit alles kan simpel worden opgelost door de $_GET['page'] te vervangen door mysql_real_escape_string($_GET['page']), daardoor voegt PHP een \ toe voor de ', leest de database de ' dus niet als "einde tekst" waardoor die hele UNION met toeters en bellen zo letterlijk in de id kolom moet staan.
[Reactie gewijzigd door RobertMe op 4 augustus 2011 19:01]