[LACNIC/Seguridad] Processing of IPv6 "atomic" fragments (Fwd: I-D Action: draft-ietf-6man-ipv6-atomic-fragments-00.ext)

Fernando Gont fgont en si6networks.com
Sab Feb 11 18:28:27 BRST 2012


On 02/10/2012 03:43 PM, Iván Arce wrote:
>>>>> Es asi: A y B se comunican con datagramas fragmentados, A implemente la 
>>>>> recomendacion (contador por destino, inicializado random), B no 
>>>>> implementa la recomendación (contador global), ahora tenés que 
>>>>> garantizar que B no filtre información a un tercero  (M de Mallory, 
>>>>> que puede comunicarse con ambos a su antojo) sobre el contador de A con 
>>>>> B.
>>>>
>>>> Como habria de leakear la info del contador de *A con B*? (o es que te
>>>> referias a "la info del contador de *B* con *A*?)
>>>
>>> No, me refería exactamente a lo que escribí, no querés que B filtre
>>> información sobre el contador que tiene A para generarle frag IDs a B.
>>
>> Este ataque no lo habia considerado, así que "buen punto" (valido).
>>
>> Mas alla de eso, este caso particular es "cuestionable". 
> 
> Cuestionable en que sentido? A los atacantes no les interesa la
> elegancia  o prolijidad de sus ataques, simplemente que sirvan para sus
> propósitos, lo demás es accesorio.

"Cuestionable" en el sentido de: "tendría realmente sentido para un
atacante usarlo?"

Por lo que entiendo, el ataque al que vos estás haciendo referencia es
el siguiente:

* Tenemos tres sistemas: A, B, y M.
  - "A" implementa todas las recomendaciones, y mantiene un contador
    por destino (para seleccionar el Fragment ID), inicializado a un
    valor aleatorio
  - "B" utiliza un contador global para los Fragment ID
  - Respecto a "M", no importa *que* implementa, ya que es el atacante


Tu argumento, de acuerdo a mi entender, es que se podría dar una
situación como la siguiente:


    A                         B                                M
#1                              <------ Echo Req #1 ----------
#2                              --- Echo Resp #1, FID= 5000 -->
#3  <------------------- SYN #1, src= B -----------------------
#4  ---- SYN/ACK, FID=9000 --->
#5  <---- RST, FID= 5001 -----
#6                             <-------- Echo Req #2 ----------
#7                             ---- Echo Resp #2, FID= 5002 -->

En este caso, M obtuvo dos informaciones distintas:

1) Que el port correspondiente de A estaba abierto -- esto es un idle
   scan, y fue posible porque B utiliza un contador global
2) Que el contador de "A" hacia "B" se incrementó en 1 -- esto es
   posible ya que "B" termina leakeando información del contador de
   "A" a "B".

Creo que no hay discusión algunta sobre el item "#1". Respecto al item
"2)", mi argumento es que si bien "M" sabe que el contador de "A" a "B"
se incrementó, no sabe cual es el valor actualmente utilizado. Es decir,
lo unico que sabe es que si ese contador antes valia "X", ahora vale
"X+1". Y mi argumento es que no encuentro modo en el cual dicha
información pudiera ser aprovechada.

Es este el escenario al que estas haciendo referencia, o te referis a
otro escenario?



>>> Lo que estoy diciendo es que la recomendacion solo atiende parcialmente
>>> el modelo de ataque que describis. B no quiere adivinar nada porque ya
>>> sabe pero tampoco quiere que  M lo use para adivinar que Frag ID le va
>>> a mandar A, porque eso le daría a M, un atacante off-path, la
>>> posibilidad de interferir en las comunicacioens entre A y B.
>>
>> Por lo que veo de tu ejemplo, lo unico que puede hacer M es detectar
>> incrementos en los Frag ID de A a B... pero *no* adivinar el valor en si.
> 
> Bueno, yo no me animaría a afirmar de manera tan tajante

Bueno, "por lo que veo de tu ejemplo" no es tajante. :-) Simplemente
quise decir "no *encuentro* tal cosa" -- pero *no* "no *existe*" tal cosa.

Hay millones de ejemplos en los cuales ha quedado demostrado que "ser
tajante" suele ser una filosofía bastante tonta, y proclive al ridículo
(http://www.coresecurity.com/?action=item&id=1703 ;-) ).


> que usando el
> canal encubierto del contador de B no existe manera de determinar el
> valor de los frag IDs que genera A.  Requerir un ejemplo concreto de
> explotación para decidir atender el problema y cerrar el canal es una
> respuesta clásica de muchos de los que vos y yo criticamos por su forma
> de atender la temática de seguridad.

Por si no fui claro, yo no dije "no quiero cambiar esto", ni tampoco
"necesito de una prueba para cambiarlo". El bottom-line de mi mail fue
"mi entendimiento actual es que dicha información no es útil. Ayudame a
ver porqué *si* lo es" -- nada mas que eso.

Esto es independiente de aplicar cambios a
"draft-ietf-6man-ipv6-atomic-fragments-00". De hecho, en principio yo
soy de la idea que "random() is your friend". La unica cuestión es que,
en este caso, aplicar random() es un tradeoff:
1) Puede llevar a colisiones
2) Puede ser "caro"

De ahí que no opte por "directamente aplicar random()", e intentar
analizr bien los pros y cons.


> En todo caso, como hago en situaciones similares, te devuelvo la pelota
> a vos: Demostrá que el canal encubierto no se puede usar para determinar
> los Frag Id y yo me quedo tranquilo con la recomendación de un contador
> por destino inicializado aleatoriamente.

No creo poder probar de manera formal semejante cosa. Informalmente, lo
que te podria decir es que los Frag ID se calculan como:

FID= random + increments

Y que entonces para adivinar el FID vos necesitas saber tanto
"increments", como "random", siendo *random* quien aporta la
aleatoriedad. Por lo tanto, lo crucial es cuan secreto es "random", mas
que cuan secreto es "increments".



>> Como mencionaba arriba, lo que pueda hacer un tercero off-path es
>> inferir que (por ej.) A incremento su Frag ID enviado a B... pero *no*
>> adivinar el valor en si.
> 
> Reitero, no hay que pensar en que no vale la pena tratar de resolver una
> debilidad de diseño sólo porque no se nos ocurre una implementación
> específica que la explota. 

Coincido con ello. El tema es que, en este caso, el hecho de que
"increments" sea un contador es un "objetivo de diseño": -- lease,
resulta en bajas colisiones, y es "barato" de hacer.

Mis preguntas/planteos de arriba eran justamente para analizar hasta que
punto puede ser considerado una debilidad (mas alla de que estamos de
acuerdo en que *algo* leakea), y entonces debiera ser directamente
eliminado.


> Esa es una historia conocida incluso por
> aquellos que escriben RFCs que vieron como años después de haber escrito
> los RFCS algunos finalmente encontraron la forma de explotar las
> debilidades de diseño introducidas décadas atrás (DNS poisoning y TCP
> hijacking son los ejemplos canónicos)

En lo personal, puedo decirte lo siguiente:

1) Yo considero *mis* publicaciones literalmente como RFCs: Request For
Comments, y me atrevería a decir que cualquiera que crea que por haber
publicado algo eso convierte a ese "algo" en ley, es bastante estúpido.
De hecho, en la medida que puedo, luego que pasa un año de que publico
algo, lo vuelvo a leer, para poder hacer una revisión critica de mi
propio trabajo. -- Mientras que lo estoy escribiendo, por razones obvias
no puedo ser crítico de mi trabajo (ya que es "lo mejor que pude hacer
en ese momento"). Pero luego de un tiempo sin mirarlo, logro "salir del
estado mental con que lo produje", y ser crítico de mi propio trabajo.

2) Por sobre todas las cosas, yo disfruto de lo que hago, y eso incluye
que me agrade "progresar" y "seguir aprendiendo". -- En ocasiones, dicho
progreso implica darse cuenta que uno estaba equivocado, o incluso que
estaba *muy* :-) equivocado. -- si bien idealmente uno apunta que que
sus aseveraciones/teorías perduren en el tiempo, el hecho que uno
eventualmente las encuentre como "equivocas" termina siendo, en el
fondo, progreso.

3) La mayoría de los RFCs que he leido hacen un trabajo bastante pobre
en materia de análisis de seguridad.



>>> Por otro lado, el RFC 5722 tampoco habla de solapamiento de headers
>>> antes de la parte fragmentada, algo que yo creo talvez tambíen debería
>>> considerar como un problema.
>>
>> Si, aunque... como habrías de chequear esto?
>>
>> O sea, e el caso legitimo, cada uno de los fragmentos tiene todos los
>> mismo ext headers. Si vos queres prevenir que distinos fragmentos puedan
>> tener un set de fragmentos y opciones (pervio a la parte fragmentada),
>> entonces no te quedaria otra que comparar byte-a-byte dicha parte de
>> cada fragmento con el de los demas. -- y esto sería "overkill".
> 
> Uh? Como va a ser overkill si en la situación actual todos los extension
> headers antes del fragmento YA se estan procesando.

*Procesar* Extension headers básicamente te requiere:
1) Parsear type+length de los extension headers
2) En el caso de aquellos *que soportas*, parsear su contenido, lo cual
   implica:
   a) Parsear type+length de todas las opciones
   b) Parsear el *contenido* de todas aquellas opciones *que soportas*.

Por el contrario, chequear que los extension headers de todos los
fragmentos son iguales te require chequear byte-a-byte que el contenido
de los mismos sea igual.

Por plantear algun ejemplos ridiculo (?), podria mencionar el siguiente:
Tu implementacion de IPv6 podría no soportar ninguna opcion para el
"Destination Options" extension header, en cuyo caso no necesitarias
siqueira parsear el contenido de tal extension header. Sin embargo, para
chequear que los Ext headers son iguales en todos los fragmentos,
necesitarias comparar byte-a-byte el contenido de los extension HBH
OPtions extension headers de cada fragmento.



>> O sea, comparto en principio tu planteo, pero... es "realizable"?
> 
> No veo porque no, es tan realizable como las otras cosas que ya se están
> realizando. 

Fijate lo de arriba.

Por otro lado, si vos no apuntabas a "chequear que los extension headers
sean todos iguales", sino a "no procesar ningun extension header en caso
que haya overlap de fragmentos", en tal caso *si* creo que es
realizable: simplemente uno pondría los fragmentos en el "fragment
reassebly queue", y solo cuando "ya obtuvo todos los fragmentos, y
entonces está en condiciones de reensamblar", *en ese momento*
procesaria todos los extension headers.


> No hay un impedimento técnico que prevenga cambiar el
> comportamiento de IPv6 en el caso de fragmentación, es simplemente
> cuestión de evaluar técnicamente las diversas opciones y tomar una
> decisión "política" al respecto. Yo no soy parte del IETF ni me muevo en
> el mundo de la gente que escribe, revisa o aprueba RFCs así que
> no puedo determinar que tan "realizable" es mi planteo.

Lamentablemente, "moviendome ese mundo", lo unico que me atrevo a decir
es "uno nunca sabe". Por ejemplo, yo he tardado 6 años para publicar
documentos que a mi criterio eran muy solidos tecnicamente, y muy poco
tiempo para publicar otros que yo mismo podría decir que tenian
contenido "cuestionable".

Lamentablemente, cuando en el "mix" entran cosas como "intereses
economicos", "egos", y demás, la cuestión se torna compleja de predecir.



[....]
>> Coincido con vos. Ahora bien: existe alguna manera razonable de prevenirlo?
>>
>> Porque en este caso no alcanza con chequear la existencia de
>> determinados extension headers, sino tambieén su contenido. (COmo
>> atacante, obviamente te enviaria fragmentos con toneladas de extension
>> headers delante de la parte fragmentada).
>>
>> Y si apra cada fragmento vas a hacer semejante procesamiento, la
>> "solución" termina siendo peor que el problema.
> 
> Los stacks IPv6 actuales YA procesan todos los campos de todos los
> extensión headers que vienen antes de la parte fragmentada así que no
> veo de que manera se agravaría el problema ya existente.

Claro, pero lo que hacen es parsear type y length, y procesar el
contenido de aquellos headers/opciones que *entienden*. Para implementar
lo que vos decis, a ese procesamiento habria que agregarle una
comparación byte-a-byte entre los ext headers del primer fragmento, y
los ext headers del resto de los fragmentos.



> Me parece que estás pensando en alguna solución que yo no propuse :)
> como por ejemplo encolar todos los datagramas fragmentados y procesar
> los headers antes y después de la parte fragmentada recién después de
> hacer el reensamblado (esto si crearía el potencial de degradación de
> performance por consumo de memoria).

-- Esto, en principio, no lo veo como tan problematico. Lo que veo como
mas problematico es chequear que todos los fragmentos tengan ext headers
iguales.

Saludos,
-- 
Fernando Gont
SI6 Networks
e-mail: fgont en si6networks.com
PGP Fingerprint: 6666 31C6 D484 63B2 8FB1 E3C4 AE25 0D55 1D4E 7492






Más información sobre la lista de distribución Seguridad