Simovits

Säkerhetsaspekter av Type Juggling

Dagens blogg handlar om type-juggling som är en ”feature” i PHP som kan användas i antagonistiska syfte. Angreppen baseras på att “==“ är en svagare form av jämförelse mellan två objekt än ”===”, enligt vad som syns nedan.

Det som händer när man använder “==“ är att PHP ser om det går ändra typen av en av sidorna för att kunna göra jämförelsen “bättre”. I exemplet försöker man jämföra en int och en sträng. Strängen ändras då till en int (0) vartefter jämförelsen görs. Anledningen till att detta är värt att nämna i en blogg om säkerhet är att det kan användas i antagonistiska syften för att komma runt kontroller där “==“ används i tron att det fungerar som “===”. 

För att exemplifiera risken skapade jag ett enkelt inloggningsformulär där en svag jämförelse används som består av ett html-formulär samt kod som hanterar input från formuläret på serversidan.

Inloggningsformulär

Källkod till inloggningsformulär

 <html>
 <head>
   <meta charset="utf-8">
   <title>Sårbart login formulär</title>
 </head>
 <body>
 Logga in här
 <form action="action_form_vuln.php" method="post">
 <div>
 <label for="uname"><b>Användarnamn</b></label>
   <input type="text" placeholder="användarnamn" name="uname" required><br>
   <label for="psw"><b>Lösenord</b></label>
   <input type="password" placeholder="lösenord" name="psw" required></br>
   <button type="submit">Login</button>
   <label>
     <input type="checkbox" checked="checked" name="remember"> Kom ihåg mig
   </label>
 </div>
 </body>
 </html>

När användaren klickar på “Login” körs följande kod på servern (action_form_vuln.php): 

<html>
 <body>
 <?php
 $password="secretpassword";
 $uname = $psw = "";
 if ($_SERVER["REQUEST_METHOD"]==="POST"){
   $uname= ($_POST["uname"]);
   $psw= ($_POST["psw"]);
    if (strcmp($psw,$password)==0){
     echo "correct password! :)";
   }
   else {
     echo "Wrong password! :(";}
 }
 ?>
 </body>
 </html>

I exemplet ovan är det möjligt att kringgå autentiseringen via type-juggling då uttrycket strcmp($psw,$password)==0 används för att kontrollera om rätt lösenord angivits. 

Generellt används funktionen strcmp för att jämföra skillnader mellan två strängar och (int-)värdet 0 innebär att strängarna är lika. Variabeln $psw är det värde som användaren fyller i lösenordsfältet medan $password är det (för pedagogiska syften hårdkodade) korrekta lösenordet. Funktionen strcmp fungerar dock så att den returnerar värdet null om en av strängarna som jämförs är en array. En angripare kan använda detta för att kringgå autentiseringen enligt skärmbilden nedan.

Det som händer i skärmbilden är att eftersom angriparen kontrollerar parametern $psw testar hen att använda type-juggling för att kringgå autentisering genom att skicka en array istället för sträng som parametern $psw. Resultatet är att strcmp blir null istället för en int och tillföljd av type juggling är vidare uttrycket null==0 sant.