Zoals ik in het topic [topic=291785] kun je nogal snel fouten in je programma/script maken waardoor security niet meer gewaarborgd is. Op verzoek van D2k ga ik hier even wat over vertellen
Hier onder volgt een lijst van veel gemaakte fouten in PHP en hoe je ze voorkomt/oplost. Niet alle problemen zijn specifiek voor PHP, maar de tijd ontbreekt me om een lijst te maken voor PHP/ASP en C/C++.
SQL Query injection
Probleem: Variable niet escapen van quotes bij strings die in queries gebruikt worden
Uitleg:
Stel je hebt een login.php waar een gebruikers naam en wachtwoord vanaf een form heen gepost worden. Hiermee voor je een query uit op je database om te kijken of de user bestaat en welke rechten de user heeft:
Stel dat ik nu het volgende doe:
[url="http://localhost/index.php?username=test""]http://localhost/index.php?username=test"[/url] or username like "%&password=" or password like "%
( browser vertaald dat naar [url="http://localhost/index.php?username=test"%20or%20username%20like%20"%&password="%20or%20password%20like%20"%"]http://localhost/index.php?username=test"%20or%20username%20like%20"%&password="%20or%20password%20like%20"%[/url] )
Dan komt de Query er zo uit te zien:
Oftewel, het eerste record van de database word nu terug gegeven, en je kunt inloggen zonder geldige username/password combinatie. Als je wat creatiever bent kun je zelfs inloggen onder elke gebruiker als je wilt. Je moet wel dus even gokken hoe de velden in de database heten, maar in de praktijk blijkt dit niet zo moeilijk.
Oplossing: gebruik AddSlashes() of zet magic_quotes_gpc op "On" in je php config file, hierdoor worden quotes in gpc (get, post, cookie) variables automatisch escaped.
Directory traversel
Uitleg:
Stel je hebt een php gemaakt die vanuit een directory alle files list een in mooie tabel. De standaard aanroep is bv. list.php?dir=/ je hebt de / dir ingesteld op /www/images/fotoboek dus in je php doe je:
$listdir = "/www/images/fotoboek" . $dir;
En in $listdir ga je nu de lijst met files ophalen en in de tabel gooien. Wat nu als iemand de $dir variable om gooit als: $dir=/../../../ wat er nu gebeurd is:
$listdir = "/www/images/fotoboek" . $dir;
dus in $listdir staat: "/www/images/fotoboek/../../../" dit evalueert naar de ECHTE root directory van je machine, en zo kan een hacker dus je filesysteem kan verkennen. Niet goed.
Oplossing: kijken of er ".." in je string voorkomt, zoja het request afwijzen. Eigenlijk is de implementatie zoals boven beschreven geen goede en kun je beter wat anders bedenken (zoals vast gelegde directories in 'n array die bekenen mogen worden), maar omdat ik dit vaak tegen ben gekomen vermeld ik hem ook maar.
Botweg variables in include() of require() gooien
Uitleg:
Stel je hebt een index.php die de layout van je pagina bevat, en ergens daarin wil je een file includen die je content bevat. Je roept de pagina aan met:
index.php?article=content.html
in de index.php doe je ergens include($article); Wat nu als iemand besluit de url index.php?article=/etc/passwd op te roepen? De inhoud van deze file word nu weer gegeven, en de hacker weet nu welke users er bestaan op je systeem.
Oplossing: Strip de slashes ("/") uit de variable, of gebruik een andere aanpak. bv. index.php?section=articles&file=content hiermee kun je dan later weer de plaats van de file bepalen zonder dat iemand een directory op kan geven.
Session variables verkeerd gebruiken
Uitleg:
Je hebt een mooi inlog systeempje gemaakt, en gebruikt sessies om bij te houden wie wie is etc.
Dit lijkt opzich goed te werken, maar hiermee kan een gebruiker zelf opgeven welke username en userlevel hij wilt (door ?userlevel=1 aan de url te plakken). De volgende code is wel juist:
System calls niet escapen
Uitleg:
Stel je wilt van een bepaalde user de finger informatie laten zien op een web pagina, en je gebruikt daarvoor de volgende code:
Maar wat nu als de gebruiker als username opgeeft:
pietje;ls -al
de gebruiker kan dus elk willekeurig commando opgeven en dat word ook uitgevoerd.
is wel juist.
Oplossing: Gebruik bij PassThru(), System(), Exec() altijd EscapeShellCmds() als je user input erin gebruikt.
[b]Conclusie[/b]
Never trust user input. Controleer altijd alles wat van de user afkomt en ga dat niet klakkeloos gebruiken. Kap strings af op de lengte die ze max. mogen zijn, en wees liever te voorzichtig dan te nonchalant.
[b]Andere nuttige informatie[/b]
Exploiting Common Vulnerabilities in PHP Applications
RFP2K01: "How I hacked PacketStorm" (mooie uitleg over SQL hacking)
SQL Query injection
Probleem: Variable niet escapen van quotes bij strings die in queries gebruikt worden
Uitleg:
Stel je hebt een login.php waar een gebruikers naam en wachtwoord vanaf een form heen gepost worden. Hiermee voor je een query uit op je database om te kijken of de user bestaat en welke rechten de user heeft:
PHP:
1
2
3
4
| <? $Query = "SELECT * FROM users WHERE username = \"$username\" AND password = \"$password\""; $result = mysql_query($Query, $db); ?> |
Stel dat ik nu het volgende doe:
[url="http://localhost/index.php?username=test""]http://localhost/index.php?username=test"[/url] or username like "%&password=" or password like "%
( browser vertaald dat naar [url="http://localhost/index.php?username=test"%20or%20username%20like%20"%&password="%20or%20password%20like%20"%"]http://localhost/index.php?username=test"%20or%20username%20like%20"%&password="%20or%20password%20like%20"%[/url] )
Dan komt de Query er zo uit te zien:
code:
1
| SELECT * FROM users WHERE username = "test" or username like "%" AND password = "" or password like "%" |
Oftewel, het eerste record van de database word nu terug gegeven, en je kunt inloggen zonder geldige username/password combinatie. Als je wat creatiever bent kun je zelfs inloggen onder elke gebruiker als je wilt. Je moet wel dus even gokken hoe de velden in de database heten, maar in de praktijk blijkt dit niet zo moeilijk.
Oplossing: gebruik AddSlashes() of zet magic_quotes_gpc op "On" in je php config file, hierdoor worden quotes in gpc (get, post, cookie) variables automatisch escaped.
Directory traversel
Uitleg:
Stel je hebt een php gemaakt die vanuit een directory alle files list een in mooie tabel. De standaard aanroep is bv. list.php?dir=/ je hebt de / dir ingesteld op /www/images/fotoboek dus in je php doe je:
$listdir = "/www/images/fotoboek" . $dir;
En in $listdir ga je nu de lijst met files ophalen en in de tabel gooien. Wat nu als iemand de $dir variable om gooit als: $dir=/../../../ wat er nu gebeurd is:
$listdir = "/www/images/fotoboek" . $dir;
dus in $listdir staat: "/www/images/fotoboek/../../../" dit evalueert naar de ECHTE root directory van je machine, en zo kan een hacker dus je filesysteem kan verkennen. Niet goed.
Oplossing: kijken of er ".." in je string voorkomt, zoja het request afwijzen. Eigenlijk is de implementatie zoals boven beschreven geen goede en kun je beter wat anders bedenken (zoals vast gelegde directories in 'n array die bekenen mogen worden), maar omdat ik dit vaak tegen ben gekomen vermeld ik hem ook maar.
Botweg variables in include() of require() gooien
Uitleg:
Stel je hebt een index.php die de layout van je pagina bevat, en ergens daarin wil je een file includen die je content bevat. Je roept de pagina aan met:
index.php?article=content.html
in de index.php doe je ergens include($article); Wat nu als iemand besluit de url index.php?article=/etc/passwd op te roepen? De inhoud van deze file word nu weer gegeven, en de hacker weet nu welke users er bestaan op je systeem.
Oplossing: Strip de slashes ("/") uit de variable, of gebruik een andere aanpak. bv. index.php?section=articles&file=content hiermee kun je dan later weer de plaats van de file bepalen zonder dat iemand een directory op kan geven.
Session variables verkeerd gebruiken
Uitleg:
Je hebt een mooi inlog systeempje gemaakt, en gebruikt sessies om bij te houden wie wie is etc.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <? session_start(); session_register("username"); // login naam session_register("userlevel"); // toegangs nivo van gebruiker switch ($userlevel) { case 0: echo "Gebruiker: $username"; break; case 1: echo "Beheerder: $username"; break; } ?> |
Dit lijkt opzich goed te werken, maar hiermee kan een gebruiker zelf opgeven welke username en userlevel hij wilt (door ?userlevel=1 aan de url te plakken). De volgende code is wel juist:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <? session_start(); session_register("username"); // login naam session_register("userlevel"); // toegangs nivo van gebruiker $username = $HTTP_SESSION_VARS["username"]; $userlevel = $HTTP_SESSION_VARS["userlevel"]; switch ($userlevel) { case 0: echo "Gebruiker: $username"; break; case 1: echo "Beheerder: $username"; break; } ?> |
System calls niet escapen
Uitleg:
Stel je wilt van een bepaalde user de finger informatie laten zien op een web pagina, en je gebruikt daarvoor de volgende code:
PHP:
1
2
3
| <? system("finger $username"); ?> |
Maar wat nu als de gebruiker als username opgeeft:
pietje;ls -al
de gebruiker kan dus elk willekeurig commando opgeven en dat word ook uitgevoerd.
PHP:
1
2
3
| <? system("finger " . EscapeShellCmds($username)); ?> |
is wel juist.
Oplossing: Gebruik bij PassThru(), System(), Exec() altijd EscapeShellCmds() als je user input erin gebruikt.
[b]Conclusie[/b]
Never trust user input. Controleer altijd alles wat van de user afkomt en ga dat niet klakkeloos gebruiken. Kap strings af op de lengte die ze max. mogen zijn, en wees liever te voorzichtig dan te nonchalant.
[b]Andere nuttige informatie[/b]
Exploiting Common Vulnerabilities in PHP Applications
RFP2K01: "How I hacked PacketStorm" (mooie uitleg over SQL hacking)