All your buckets are belong to us: DOSeando PHP a través dos arrays asociativos
Fai unhas horas andaba eu pasando o rato por /r/programming cando topei cun post sobre a posibilidade e as consecuencias de forzar externamente colisións dentro dos arrays asociativos de PHP, é algo tan... ¿abrumador? que hay que probalo para ver o perigo que representa, vexámolo.
Nota: O día 28 de este mes houbo no 28C3 unha charla que ten moito, todo! que ver con isto, é moi recomendable botarlle unha ollada, enormemente interesante.
O perigo agravase por unha combinación de varios factores que PHP agrupa:
-
Pódese adiviñar de forma trivial o hash dun enteiro, el mesmo.
-
Hay algúns arrays onde o usuario ten total poder para crear o seu antoxo:
$_GET
,$_POST
y$_COOKIE
.
Imaxinade se lanzamos contra un servidor unhas cantas petición cun pouco de mala leito, como pode ser un pouco engorroso facelo a man, aqui tedes un script para facilitar a tarefa prueba_hashmap_php.py... non é bonito, non é elegante, pero tampouco o pretende.
O script manexa varias posibilidades, se esperará ou non pola resposta do servidor e canto esperará entre petición e petición, isto pódese modificar nas liñas 10 e 11, ademáis pódese pasar por parámetros ó número de valores que se enviará, ó número de envios, e ó número de fios que farán a operación á vez (nese orde).
Ben, agora pasemos ás probas, o "atacante" é un simple netbook incapaz de tirar cun emulador de N64 (para dar unha idea), a "víctima" é un Cuad Core, non o último do mercado pero debería portarse ben, non?.
Pois non.
Lanzando un ataque dunha soa petición, con 50000 elementos, e esperando polo servidor, obtienese a seguinte saída:
1 2 3 4 5 6 7 8 9 10 |
|
Creo que queda claro o problema, tardouse apenas dúas décimas de segundo en mandalos datos (sen contar o tiempo para preparala petición, que so se fai unha vez) e nembargantes o servidor non so tardou 60 segundos, deténdose cun error 500 (Internal server error), senón que durante ese tempo un núcleo estivo ao 100%.
E se repetimos a experiencia, pero agora con catro fios?
1 2 3 4 5 6 7 8 9 10 11 12 |
|
E durante ese tempo catro (de catro) núcleos ao 100%.
Por se alguén esperaba un script complexo que explicara estes tempos aquí está ó que se lle fan as peticions:
1 2 3 |
|
Pero a cousa non queda nunha denegación de servicio con necesidade de moi pouco tráfico, pódese por peor, que pasaría se inmediatamente despois de envia-la petición ó servidor desconectamos e mandamos outra?
1 2 |
|
Se o lanzamos con bloques de 50000 valores, cun infinito número de intentos (-1 serverá), e digamos... 10 fios, veremos algo moi interesante, deixando de lado que loxicamente tódolos núcleos poñense a 100 e que o principio require un ancho de banda considerable ~3mb (despois de menos dun minuto apenas fai falta 1kb para mantelo), o gasto de memoria aumenta, o principio moi rápido, despois menos, pero o cabo de ~10 minutos consumirá casi 1 Gigabyte e todo isto mentres un simple netbook non lle adica nen un 1% do procesador o ataque.
Solución
Como di no primer post o que se fai referencia na entrada, xa hay un commit no SVN de PHP que añade unha directiva max input vars para limitalos parámetros que se poden enviar á vez, que polo que di o post, chegará con 5.3.9 (nos repos de trisquel a que está e a 5.3.5), teóricamente outra opción sería botar man do parche Suhosin, que ven por defecto con Debian e derivadas, pero despois de probalo non podo dicir que vaia mellor :/
Iso é todo, ata a próxima.