Your SlideShare is downloading. ×
Trouvez la faille! - Confoo 2012
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Trouvez la faille! - Confoo 2012

1,181
views

Published on

Source code security review challenge at Confoo 2012 - Montreal (confoo.ca) …

Source code security review challenge at Confoo 2012 - Montreal (confoo.ca)

The audience was challenged in attempting to spot security vulnerabilities in a series of source code examples.

Published in: Technology

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,181
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
16
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • En cas de distribution? Identifiant prévisible
  • En cas de distribution? Identifiant prévisible
  • Password a été rapatrié en local
  • Password a été rapatrié en local
  • En cas de distribution? Identifiant prévisible
  • En cas de distribution? Identifiant prévisible
  • Transcript

    • 1. Trouvez la faille! Antonio Fontes / Confoo 2012 - MontréalNotice 1: cette présentation contient des références à Common Weakness Enumeration:http://cwe.mitre.org/data/index.htmlNotice 2: aucun chat na été maltraité durant la préparation de cette séance.Notice 3: cette présentation contient des références audocument "Test your Security IQ", par M. Howard et B. SullivanNotice 4: Un grand merci à Sébastien pour ses idées & propositions!
    • 2. • Règles de jeu: – Lire l’exemple de code affiché à lécran – Trouver la ou les éléments pouvant constituer un risque pour la sécurité du S.I. – Tenir une comptabilité analytique des points obtenus! 02.03.2012 Confoo Conference 2012 - Antonio Fontes 2
    • 3. Antonio Fontes Genève (Suisse) Consultant indépendant Infosécurité logicielle: Sécurité des applications web Visibilité et gestion du risque sur Internet Formation / accompagnement durant les projets de développement Bulletin dinformation"cybermenaces et sécurité Internet": http://cddb.ch OWASP: Membre du Comité - OWASP Suisse Leader - OWASP GenèveA propos du conférencier… 02.03.2012 Confoo Conference 2012 - Antonio Fontes 3
    • 4. • Le site d’actualité permet la création de comptes personnels, la publication de réactions à l’actualité, l’échange de messages entre membres.• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 4
    • 5. Envoi des éléments dauthentification en clair.• Le site d’actualité permet la création de comptes personnels, la publication de réactions à l’actualité, l’échange de messages entre membres.• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 5
    • 6. • Idem. 02.03.2012 Confoo Conference 2012 - Antonio Fontes 6
    • 7. function printFile($username,$filename){ //read file into string $file = file_get_contents($filename); if ($file && isOwnerOf($username,$filename)){ echo $file; return true; } else { echo You are not authorized to view this file; } return false; }• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 7
    • 8. function printFile($username,$filename){ //read file into string $file = file_get_contents($filename); Le chargement du if ($file && isOwnerOf($username,$filename)){ fichier a lieu avant echo $file; le contrôle daccès. return true; } else { echo You are not authorized to view this file; } return false; }• 1 point – Identification du risque pour la disponibilité du S.I. 02.03.2012 Confoo Conference 2012 - Antonio Fontes 8
    • 9. protected void Page_Load(object sender, EventArgs e) { string lastLogin = Request["LastLogin"]; if (String.IsNullOrEmpty(lastLogin)) { HttpCookie lastLoginCookie = new HttpCookie("LastLogin", DateTime.Now.ToShortDateString()); lastLoginCookie.Expires = DateTime.Now.AddYears(1); Response.Cookies.Add(lastLoginCookie); } else { Response.Write("Welcome back! You last logged in on " + lastLogin); Response.Cookies["LastLogin"].Value = DateTime.Now.ToShortDateString(); } }• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 9
    • 10. protected void Page_Load(object sender, EventArgs e) { string lastLogin = Request["LastLogin"]; if (String.IsNullOrEmpty(lastLogin)) { Appel vers la HttpCookie lastLoginCookie = new HttpCookie("LastLogin", collection parente DateTime.Now.ToShortDateString()); "Request" lastLoginCookie.Expires = DateTime.Now.AddYears(1); Response.Cookies.Add(lastLoginCookie); } else { Response.Write("Welcome back! You last logged in on " + lastLogin); Response.Cookies["LastLogin"].Value Transfert du contenu = DateTime.Now.ToShortDateString(); vers le client, sans } encodage approprié. }• 1 point – Cas de type "XSS" (Cross-site scripting) 02.03.2012 Confoo Conference 2012 - Antonio Fontes 10
    • 11. $role = $_COOKIES[role]; if (!$role) { $role = getRole(user); if ($role) { // save the cookie to send out in future responses setcookie("role", $role, time()+60*60*2); } else { ShowLoginScreen(); die("n"); } } if ($role == Reader) { DisplayMedicalHistory($_POST[patient_ID]); } else { die("You are not Authorized to view this recordn"); }• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 11
    • 12. $role = $_COOKIES[role]; if (!$role) { Absence de contrôle $role = getRole(user); dintégrité du if ($role) { cookie. // save the cookie to send out in future responses setcookie("role", $role, time()+60*60*2); } else { Contournement du ShowLoginScreen(); mécanisme die("n"); dauthentification } } if ($role == Reader) { Contournement du DisplayMedicalHistory($_POST[patient_ID]); contrôle daccès } else { die("You are not Authorized to view this recordn"); }• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 12
    • 13. • 1 + 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 13
    • 14. Transfert de confiance à un tiers• 1 + 1 + 1 points – 1 point: identification du risque dinjection de contenu par un tiers – 1 point: identification du risque sur la confidentialité (fuite des referrers) – 1 point: identification du risque de déni de service sur le tiers 02.03.2012 Confoo Conference 2012 - Antonio Fontes 14
    • 15. • 1 + 1 + 1 points – Faire attention aux recommandations sur le web: elles vont souvent à lencontre de la sécurité et visent à faciliter la collecte de données par des tiers. – Vérifier qui est lauteur dune recommandation de codage. 02.03.2012 Confoo Conference 2012 - Antonio Fontes 15
    • 16. // API flag, output JSON if set $json = $_GET[json]; $username = $_GET[user]; if($json) { $record = getUserRecord($username); echo(json_encode($record)); } else { $record = getUserRecord($username); foreach($record as $fieldName => $fieldValue) { // never disclose user email addresses to the public (privacy req.) if(!($fieldName == "email_address")) renderToHtmlTable ($fieldName,$fieldValue); }}}• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 16
    • 17. // API flag, output JSON if set $json = $_GET[json]; Dans le cas json, $username = $_GET[user]; ladresse email nest if($json) { plus protégée contre les $record = getUserRecord($username); fuites. echo(json_encode($record)); } else { $record = getUserRecord($username); foreach($record as $fieldName => $fieldValue) { // never disclose user email addresses to the public (privacy req.) if(!($fieldName == "email_address")) renderToHtmlTable ($fieldName,$fieldValue); }}}• 1 point – Identification de la fuite dadresses email 02.03.2012 Confoo Conference 2012 - Antonio Fontes 17
    • 18. byte[] GetKey(UInt32 keySize) { byte[] key = null; try { key = new byte[keySize]; RNGCryptoServiceProvider.Create().GetBytes(key); } catch (Exception e) { Math.Random r = new Math.Random(); r.NextBytes(key); } return key; }1 + 1 + 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 18
    • 19. byte[] GetKey(UInt32 keySize) { byte[] key = null; try { key = new byte[keySize]; RNGCryptoServiceProvider.Create().GetBytes(key); } catch (Exception e) { Exception générique? Math.Random r = new Math.Random(); r.NextBytes(key); } Math.Random? Fail-safe? return key; }1 + 1 + 1 point – Exception générique: privilégier lexception typée – Principe de conception "Fail-safe": le code néchoue pas en haute sécurité – La classe Math.Random ne fournit pas dentropie de niveau cryptographique 02.03.2012 Confoo Conference 2012 - Antonio Fontes 19
    • 20. private decimal? lookupPrice(XmlDocument doc) { string query = @"//products/product[id/text()=" + Request["itemId"] + "]/price" XmlNode node = doc.SelectSingleNode(query); if (node == null) return null; else return(Convert.ToDecimal(node.InnerText)); }• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 20
    • 21. private decimal? lookupPrice(XmlDocument doc) { string query = @"//products/product[id/text()=" + Request["itemId"] + "]/price" XmlNode node = doc.SelectSingleNode(query); Validation? if (node == null) return null; else return(Convert.ToDecimal(node.InnerText)); }• 1 point – Injection de type Xpath (il ny a pas que des injections SQL!!) – Marche aussi sur: commandes système, LDAP, APIs ORM, etc. 02.03.2012 Confoo Conference 2012 - Antonio Fontes 21
    • 22. public class MySessionIDManager : System.Web.Session State.SessionIDManager { private static object lockObject = new object(); public override string CreateSessionID(HttpContext context) { lock (lockObject) { Int32? lastSessionId = (int?)context.Application ["LastSessionId"]; if (lastSessionId == null) lastSessionId = 1; else lastSessionId++; context.Application["LastSessionId"] = lastSessionId; return lastSessionId.ToString(); }}}• 1 + 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 22
    • 23. public class MySessionIDManager : System.Web.Session State.SessionIDManager { private static object lockObject = new object(); public override string CreateSessionID(HttpContext context) { lock (lockObject) Multi-serveur? { Int32? lastSessionId = (int?)context.Application ["LastSessionId"]; if (lastSessionId == null) lastSessionId = 1; ID de session prédictibles else lastSessionId++; context.Application["LastSessionId"] = lastSessionId; return lastSessionId.ToString(); }}}• 1 + 1 point – Identification de lidentifiant de session prédictible – Collision des identifiants de session si le serveur est répliqué! 02.03.2012 Confoo Conference 2012 - Antonio Fontes 23
    • 24. bool login(SqlConnection connection, out string errorMessage) { string uname = Request.Form["username"]; string pword = Request.Form["password"]; SqlCommand selectUserAndPassword = new SqlCommand( "SELECT pwd FROM Users WHERE uname = @username", connection); selectUserAndPassword.Parameters.Add( new SqlParameter("@username", uname)); string validPassword = (string)selectUserAndPassword.ExecuteScalar(); if (validPassword == null) { // the user doesnt exist in the database errorMessage = "The username is invalid."; return false; } else if (validPassword != pword) { // the given password doesnt match errorMessage = "The password is incorrect."; return false; } else { // successBug #9 errorMessage = String.Empty; return true; } } 1 + 1 + 1 points – 1 point + bonus point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 24
    • 25. bool login(SqlConnection connection, out string errorMessage) { Requête paramétrée, ça, cest juste! string uname = Request.Form["username"]; string pword = Request.Form["password"]; SqlCommand selectUserAndPassword = new SqlCommand( "SELECT pwd FROM Users WHERE uname = @username", connection); selectUserAndPassword.Parameters.Add( new SqlParameter("@username", uname)); string validPassword = (string)selectUserAndPassword.ExecuteScalar(); if (validPassword == null) { // the user doesnt exist in the database Rapatriement inutile du errorMessage = "The username is invalid."; return false; mot de passe! } else if (validPassword != pword) { Stockage du mot de passe en // the given password doesnt match clair. errorMessage = "The password is incorrect."; return false; } else Message derreur variable lorsque le { // success login ou le mdp est faux (fuite)Bug #9 errorMessage = String.Empty; return true; } } 1 + 1 + 1 points – 1 point + bonus point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 25
    • 26. // SilverLight code module reviewbool verifyCode(string discountCode){ // We store the hash of the secret code instead of the plaintext of the secret code for security. // We hash the incoming value and compare it against the stored hash. byte[] codeHash = SecurityUtils.ComputeHash(discountCode, "MD5"); byte[] secretCode = new byte[] { 116, 46, 130, 122, 36, 234, 158, 125, 163, 122, 157, 186, 64, 142, 51, 153, 113, 79, 1, 42 }; // This should never happen, but we check it anyway if (codeHash.Length != secretCode.Length) return false; // perform an element-by-element comparison of the arrays for (int i = 0; i < codeHash.Length; i++) { if (codeHash[i] != secretCode[i]) return false; // the hashes dont match } // all the elements match, so the strings match // the discount code is valid, inform the server WebServiceSoapClient client = new WebServiceSoapClient(); client.ApplyDiscountCode(); return true; 1 + 1 + 2 points} 02.03.2012 Confoo Conference 2012 - Antonio Fontes 26
    • 27. // SilverLight code module reviewbool verifyCode(string discountCode) Algorithme déconseillé (+1){ // We store the hash of the secret code instead of the plaintext of the secret code for security. // We hash the incoming value and compare it against the stored hash. byte[] codeHash = SecurityUtils.ComputeHash(discountCode, "MD5"); byte[] secretCode = new byte[] { 116, 46, 130, 122, 36, 234, 158, 125, 163, 122, 157, 186, 64, 142, 51, 153, 113, 79, 1, 42 }; // This should never happen, but we check it anyway A-t-on besoin dun if (codeHash.Length != secretCode.Length) sel? (seed) +1 return false; // perform an element-by-element comparison of the arrays for (int i = 0; i < codeHash.Length; i++) { if (codeHash[i] != secretCode[i]) Défense côté client  return false; // the hashes dont match } // all the elements match, so the strings match totalement inutile! (+2 points) // the discount code is accepted, inform the server WebServiceSoapClient client = new WebServiceSoapClient(); client.ApplyDiscountCode(); return true; 1 + 1 + 2 points} 02.03.2012 Confoo Conference 2012 - Antonio Fontes 27
    • 28. • 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 28
    • 29. Injection SQL (absence de validation)• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 29
    • 30. $MessageFile = "messages/messages.out"; if ($_GET["action"] == "NewMessage") { $name = $_GET["name"]; $message = $_GET["message"]; $handle = fopen($MessageFile, "a+"); fwrite($handle, "<b>$name</b> says $message<hr>n"); fclose($handle); echo "Message Saved!<p>n"; } else if ($_GET["action"] == "ViewMessages") { include($MessageFile); }• 1 + 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 30
    • 31. $MessageFile = "messages/messages.out"; if ($_GET["action"] == "NewMessage") { $name = $_GET["name"]; $message = $_GET["message"]; $handle = fopen($MessageFile, "a+"); fwrite($handle, "<b>$name</b> says $message<hr>n"); Et sil y a du script fclose($handle); client? echo "Message Saved!<p>n"; } else if ($_GET["action"] == "ViewMessages") { include($MessageFile); include == eval() } ?• 1 + 1 point – Identification de linjection de code côté-serveur (via la fonction "include") – Identification de linjection de code côté-client (via laffichage du fichier) 02.03.2012 Confoo Conference 2012 - Antonio Fontes 31
    • 32. // anti SQL-injection filter for user input string SQliProtect(string formValue) { string tmp = formValue.ToUpperCase(); return(tmp.Replace("SELECT", "").Replace("INSERT ", "").Replace("UPDATE", "").Replace("UNION","") .Replace("BENCHMARK, "").Replace("-- ", "").Replace("OR 1=1", "").Replace("DROP", "").Replace("@@version ", "").Replace("WAITFOR", "").Replace("OUTFILE", "") ... return(tmp) }• 1 point 02.03.2012 Confoo Conference 2012 - Antonio Fontes 32
    • 33. // anti SQL-injection filter for user input string SQliProtect(string formValue) { string tmp = formValue.ToUpperCase(); return(tmp.Replace("SELECT", table" ? "DRDROPOP "").Replace("INSERT ", "").Replace("UPDATE", "").Replace("UNION","") .Replace("BENCHMARK, "").Replace("-- ", "").Replace("OR 1=1", "").Replace("DROP", "").Replace("@@version ", "").Replace("WAITFOR", "").Replace("OUTFILE", "") ... return(tmp) }• 1 point – Identification de la technique de contournement du filtre 02.03.2012 Confoo Conference 2012 - Antonio Fontes 33
    • 34. <? $reqId = 0; if(isset($_GET[“account_id"])) $reqId = (int)(htmlentities($_GET[“account_id"])); if($reqId == 0) { // no account selected, show the list of authorized accounts $sql = " SELECT * FROM accounts a " ." INNER JOIN account_managers am " ." ON a.id = am.account_id " ." WHERE am.manager_id = ".$currentUserID; echo(RenderHTMLTable($sql)); } else { // docucment is clicked -> show statement $sql = " SELECT * FROM accounts a WHERE a.id = ".$reqId; RenderHTMLAccount($sql); }• 2 points 02.03.2012 Confoo Conference 2012 - Antonio Fontes 34
    • 35. <? $reqId = 0; if(isset($_GET[“account_id"])) $reqId = (int)(htmlentities($_GET[“account_id"])); if($reqId == 0) Références internes? { // no account selected, show the list of authorized accounts $sql = " SELECT * FROM accounts a " Contrôle d’accès. Bien! ." INNER JOIN account_managers am " ." ON a.id = am.account_id " ." WHERE am.manager_id = ".$currentUserID; echo(RenderHTMLTable($sql)); } else { // docucment is clicked -> show statement $sql = " SELECT * FROM accounts a WHERE a.id = ".$reqId; RenderHTMLAccount($sql); } Mais ici?• 2 points – Identification de lexposition de références internes – Identification de labsence de contrôle daccès lors de laffichage du document 02.03.2012 Confoo Conference 2012 - Antonio Fontes 35
    • 36. bool verifyPassword(string formPwd, int userId) { byte[] formHash = Tools.ComputeSHA1Hash(formPwd); byte[] dbHash = B64.Decode(User.GetPasswordHash(userId)); if (formHash.Length != dbHash.Length) return false; for (int i = 0; i < formHash.Length; i++) { if (formHash[i] != dbHash[i]) return false; // the hashes dont match } // we are still here, so the passwords matched return true; }• 1+1+1+1+1 points 02.03.2012 Confoo Conference 2012 - Antonio Fontes 36
    • 37. bool verifyPassword(string formPwd, int userId) { Sel? byte[] formHash = Tools.ComputeSHA1Hash(formPwd); byte[] dbHash = B64.Decode(User.GetPasswordHash(userId));Rappatriement du modede passe? if (formHash.Length != dbHash.Length) Algorithme fort? return false; for (int i = 0; i < formHash.Length; i++) { if (formHash[i] != dbHash[i]) Longueurs variables return false; // the hashes dont match possibles? } // we are still here, so the passwords matched return true; } Stratégie Fail safe?– Absence probable de sel +1– Sinterroger sur la nature de lalgorithme choisi +1– Rapatriement inutile du mot de passe +1– Identification de labsence de mécanisme fail-safe +1– Présence de signes indiquant une méconnaissance des fonctions de hachage +102.03.2012 Confoo Conference 2012 - Antonio Fontes 37
    • 38. Quel a été votre score? 20 points et plus: changez de carrière, ça embauche! De 13 à 19 points: Très bien! Vous vous y intéressez et ça se voit. Vous devriez songer à appliquer vos connaissances aussi au code de vos collègues si ce nest déjà fait, pensez aussi à joindre une association ou communauté traitant du sujet. Sensibilisez les gens autour de vous! De 8 à 12 points: Vous avez clairement identifié la notion de risque dans le code mais vous ne savez probablement pas encore où regarder. Il faut à présent consolider les bases simplement en…pratiquant! De 4 à 7 points: Demandez à vos chefs de vous faire suivre un cours!  Moins de 4 points: Si vous êtes développeur(ou développeuse), votre code est probablement dangereux pour la survie de lorganisation. Assurez-vous quil soit relu par une personne expérimentée dans lattente davoir un peu plus dexpérience!02.03.2012 Confoo Conference 2012 - Antonio Fontes 38
    • 39. Common Weakness Enumeration database: http://cwe.mitre.org/data/index.html OWASP Secure Coding Checklist: https://www.owasp.org/index.php/OWASP_Secure_Coding_Practices_- _Quick_Reference_Guide OWASP ASVS: https://www.owasp.org/index.php/Category:OWASP_Application_Security_Ve rification_Standard_ProjectMerci de votre attention!Si vous souhaitez me contacter: – antonio.fontes@L7securite.ch ou @starbuck3000 – Newsletter: http://cddb.ch 02.03.2012 Confoo Conference 2012 - Antonio Fontes 39