Bypass de Captcha

¿Nunca os habéis preguntado para que sirven las imágenes con números y letras que nos aparecen cuando Posteamos un comentario o bien nos damos de alta en algún servicio? ¿ Alguien se ha planteado si esos métodos realmente son 100% eficaces ? En este artículo cambiarás de parecer :)

Bienvenidos amigos, supongo que todos conoceréis las protecciones que tienen algunos websites a la hora de rellenar formularios. Lo que hacen es usar imágenes con números dentro y pedir al usuario que los introduzca correctamente en una casilla. Esta medida de protección es bastante eficaz, en general, por el simple hecho que para un ordenador, una imagen no es más que una secuencia finita de bytes que interpretados con un visualizador de imágenes dan como resultado la imagen que vemos.

También seréis conscientes que hay varios formatos de imagen, de lo que se puede deducir que la secuencia de bytes de la imagen no será la misma en un archivo ".bmp" que en un archivo ".jpg" o ".jpeg". Por lo tanto su lectura a nivel interno será completamente diferente y si quisiéramos hacer un programa, sus implementaciones deberían hacerse por separado. Con todo esto quiero decir que aunque desde fuera dos imágenes parezcan igual, incluso de calidad, internamente son completamente diferentes.

La protección

La protección como ya se ha dicho anteriormente consiste en hacer escribir al usuario los números que puede ver en una imagen, de esta manera evitan que un programa automatizado llene todos los comentarios de un site o bien que se registren infinidad de usuarios en un servicio.

Si alguno de vosotros tiene scanner sabrá que hay programas que sirven para reconocer texto, son los llamados OCR ( ing. Optical Character Recognition ). Estos programas son capaces de reconocer un texto que se encuentre en una imagen, siempre y cuando estén bien definidas sus fronteras, por ejemplo, fondo blanco y letras negras. De lo contrario se pueden producir incoherencias y el programa sera incapaz de dar con el texto en plano.

Hay varias maneras de dificultar dicha lectura, la más usual es modificar la fuente, haciéndola cursiva o deformándola, o poner fondos desiguales o líneas cruzando la fuente... en fin, infinidad de posibilidades. En la imagen1 podemos ver algunos ejemplos de distintos sites.

IMAGEN 1


El caso "a" corresponde a la imagen que nos aparece cuando fallamos reiteradamente a la hora de loguearnos en gmail, es decir, sirve para evitar hacer programas que ataquen mediante fuerza bruta una cuenta. Para evitar la identificación de los carácteres, éstos son deformados sutilmente para engañar al programa.

Por otra parte en el caso "b" nos aparece en yahoo cuando queremos darnos de alta, este sirve para evitar hacer un programa para crearnos infinitas cuentas de correo. Su eficacia es evidente, ya que cuesta bastante identificar las letras que vemos aun sin usar ningún programa jeje.

Y finalmente tenemos la imagen "c" que corresponde a la imagen que nos aparece cada vez que queremos poner un comentario en un site, que se convertirá en nuestro objetivo. Ésta, a diferencia de las anteriores, no tiene modificación alguna en la fuente, pero en cambio nos pone una recta del mismo color que los números para confundir al programa, análogamente pone un fondo con varios tonos que hacen difícil la detección del color de los números.

Ahora vamos a intentar usar un programa OCR para ver que nos saca en claro de cada imagen, el programa es el "gocr" que esta disponible en casi todas las distribuciones Linux, para poder usarlo primero debemos pasar la imagen a un formato que pueda comprender, nosotros pasaremos las imágenes a "pnm". En Linux tenemos varias aplicaciones que nos permiten cambiar el formato de las imágenes, así que no entraremos en detalle (man convert, por ejemplo):
gmail: gocr -i gmail.pnm -d0 -s1
salida: b _gmpt!
yahoo: gocr -i yahoo.pnm -d0 -s1
salida: _      4
  _  i  '  , '
Objetivo: gocr -i victim.pnm -d0 -s1  -n1
salida:   no spaces found
    _
Nota Para entender los argumentos (man gocr)
Como vemos, excepto en el caso de gmail, que ha sido capaz de reconocer 4 caracteres correctamente ("b mpt "), el resultado en general ha sido nefasto, GORC no ha sido capaz de acertar un sólo símbolo de las otras imágenes Parece ser pues que los métodos son efectivos, a primera vista claro...

A lo largo de este texto vamos a ver como convertir la imagen del site objetivo en un texto en claro, números en este caso.

Estudiando el Objetivo

Vamos a ver algunas características de la imagen, en primera instancia vemos que su generación sigue un claro patrón: todas las imágenes tienen borde de cierto color, unos números con la fuente sin modificar, una línea que los atraviesa y finalmente un fondo con los números en grande para enturbiar el análisis de un programa OCR al no ser todo el fondo uniforme.

Para poder analizar tranquilamente las imágenes, lo mejor sera bajarnos unas cuantas para hacer nuestras pruebas, por ejemplo 5 o 10, así nos aseguramos encontrarnos con todos los problemas inesperados. Ahora una posible pregunta es: ¿Donde se encuentran las imágenes? La respuesta la tenemos en el propio código fuente de la web, si miramos en él veremos las siguientes líneas:
[..]
<input type="hidden" name="code_ok" value="UDUDYQBtUzENOQo5">
[..]
<img src="/img_validator/img.php4?code=UDUDYQBtUzENOQo5" alt="Codigo
seguridad" />
[..]

Como se puede deducir, la imagen tiene un código de identificación único, es decir, cada número tiene un hash como esos. Por otra parte esta imagen es generada por el script "img.php4" a partir de la variable "code", si vamos a dicha pagina y probamos con varios valores, veremos como nos va creando imágenes con números, letras y otros símbolos.

Pues bien, ya tenemos nuestra dirección de la imagen, ahora hacer un script para bajar varias es algo trivial. En la imagen2 vemos algunas muestras de imágenes con su código correspondiente. Notar que las imágenes son en formato PNG y todas tienen las mismas dimensiones: 180x50 píxeles. Ahora vamos a jugar al juego de las diferencias y similitudes.

IMAGEN 2


Si nos fijamos vemos como en todos los casos la línea que cruza los números es del mismo color que éstos. Por otra parte a veces esta línea tiene un pendiente ascendiente y otras veces descendiente, como si eso fuera poco, puede darse el caso que esta línea sea o no del mismo color que el borde, y el borde a su vez, tiene tamaños variados, aunque siempre es regular (del mismo tamaño por todos los lados). Vamos a ver que más...la fuente en todos los casos permanece sin distorsiones pero varía, eso sí, el tipo de fuente en la que esta escrita.

Muy bien, ya tenemos una descripción medianamente detallada de las características de nuestro objetivo, ahora pensemos como saltarnos todas estas complicaciones para dejar la imagen nítida y que un programa OCR pueda hacer su trabajo con comodidad. A partir de ahora supondremos que somos capaces de abrir una imagen "png", que tenemos su contenido en un buffer de las dimensiones de la imagen ( width*heigth ) y que tenemos en cada una de sus posiciones 3 bytes para guardar la combinación de colores RGB.

Qué vamos a hacer?

Como vemos, el principal problema que tenemos es la línea que cruza los números, si pudiéramos sacar esa línea, sabiendo su color, podríamos simplemente copiar todos los píxeles de dicho color en una nueva imagen y obtendríamos el número y en algunos casos también el borde (ya que a veces es del mismo color que los números). Pero por desgracia la línea esta ahí, y no desaparecerá a menos que hagamos algo :). Como podemos sacar esta línea tan molesta? Pues da la casualidad que no hace mucho aprendí un algoritmo precisamente para calcular rectas, el algoritmo de Bressenham para Rectas, su funcionamiento y algunas características más sobre el algoritmo se pueden observar en el listado1.

LISTADO 1

ALGORITMO DE BRESSENHAM

El algoritmo de Bressenham para rectas está muy extendido debido a su sencillez y a su fácil implementación a nivel de hardware, ya que todas sus operaciones son incrementos, multiplicaciones por dos y comparaciones con 0. Si hablamos a nivel de bits, estas operaciones son realmente simples, por ejemplo, para multiplicar por 2, basta con mover todos los bits a la izquierda.

Este algoritmo se basa en ir comparando la diferencia en el eje Y y en el eje X con el fin de decidir si el siguiente pixel se pinta a continuación o con la Y incrementada (o decrementada según el caso). A continuación vemos el algoritmo utilizado para el primer cuadrante que por lo general corresponde a cuando la línea tiene una pendiente ascendiente, pero como en el caso de las imágenes los ejes funcionan al revés, es decir:

  X (0,0) --------->
  Y |   ..
    |     ..
    |       ..
    \/         ..
        (Xmax, Ymax)

Entonces en este caso, el primer cuadrante corresponde a la línea con pendiente negativa, (porque al incrementar la Y en realidad estamos "bajando" en la imagen, en vez de "subir").

Algoritmo:

  Bressenham( X1, Y1, X2, Y2 ) /* Caso Y2 > Y1 */
  {
    dx = X2-X1;
    dy = Y2-Y1;

    x=X1;
    y=Y1;

    p=2*dy-dx;

    while( x < X2 ){
      /* Vamos avanzando en el ejeX */
      x++;
      if( p <= 0 )
        p = p + (2 * dy);

      else{
        p= p + (2 * dy) - (2 * dx);
        /* Incrementaremos Y solo en este caso */
        y++;
      }
    }
  }
Como vemos el algoritmo no tiene ningún secreto, claro que como hemos dicho antes, las líneas pueden subir o bajar, el algoritmo del listado solo nos sirve para las líneas con pendiente ascendiente (desde el punto de vista de la imagen) o descendiente (desde nuestro punto de vista cuando la vemos), algunas imágenes con las que podría funcionar este algoritmo son las muestras 1, 4 y 5. Para el resto necesitaremos hacer una pequeña modificación al algoritmo.

Lo que haremos es tratar el ultimo cuadrante como si fuera el primero, para ello sólo tendremos que modificar dos o tres líneas:
if( Y2 > Y1 ){
  /* Algoritmo del listado1 */
}else{
  /* Algoritmo del listado1 modificado */
  [..]
  dy = Y1-Y2;
  y = Y2;
  [..]
  while....
    x--;
    [..]
  [..]
}

De esta manera conseguimos que el algoritmo se adapte a nuestras necesidades. Cambiando la Y1 por la Y2 y decrementando la X en lugar de incrementarla, conseguiremos que el algoritmo se mantenga al máximo, sólo que en vez de ir de izquierda a derecha, ira de derecha a izquierda, lo cual a nosotros, nos da igual.

Ahora que tenemos un algoritmo para dibujar las rectas, lo único que necesitamos es conocer los extremos de esta recta, para poder reproducirla con exactitud y poder así, borrarla.

Una vez seamos capaces de reconstruir la línea original, podremos seguirla y dejar o quitar sus píxeles según sea necesario, por ejemplo, si el pixel esta en medio del palo del número 1, ese pixel debemos dejarlo tal cual, en cambio si lo que encontramos es un pixel que no está rodeado por ningún otro del mismo color significara que debemos borrar dicho pixel.

Después de esto ya tendremos perfectamente separados los números del resto, además conoceremos su color. Solo hará falta copiar todos los píxeles de los números a otra imagen de fondo blanco con dichos píxeles negros, y luego, si el borde es del mismo color, lo borramos cómodamente, porque estará bien separado de los números. El método a seguir, a grosso modo, sería este, pero todo parte de la base que conocemos los extremos de la recta, pero eso no es así por el momento. Sigamos avanzando...¿Como encontramos los extremos de una manera generalizada? es decir, que funcione siempre indiferentemente de la imagen.

Encontrando los extremos de la recta

Hemos de tener en cuenta que el color del borde y de la línea puede ser igual, con lo que no nos sirve el método de mirar los píxeles de la primera y la ultima columna en busca de un color que destaque, porque a veces fallará, aun así en el programa se han tenido en cuenta ambos casos por separado, solo para mayor facilidad de cálculo. Por otra parte ya hemos visto que los bordes son simétricos, así que si calculamos su grosor ya podremos hacer el recuadro más pequeño y encontrar así los extremos que andamos buscando, o al menos una buena aproximación Así podremos pasar en claro tanto los bordes iguales como los desiguales :),

Para calcular el grosor del borde, sabiendo que es simétrico, es tan simple como poner la siguiente sentencia:
while( memcmp(&BorderColor, buf_img+(BorderWidth*(width+1)), sizeof(img_buf)) ==0 )
    BorderWidth++;

Donde "buf_img" es el buffer de tipo "img_buf" que guarda toda la imagen, "width" es el ancho de la imagen (180) y "BorderColor" es el color del borde, que lo hemos cogido mirando el primer pixel de la imagen (color de la posición x=0, y=0).

Con esta sentencia vamos bajando en diagonal desde la posición (0,0), guardando en "BorderWidth" el número de píxeles que hemos avanzado, así obtendremos el grosor del borde.

Ahora que ya tenemos el grosor, podemos mirar en la primera columna de la imagen (sin tener en cuenta el borde) y ver así el color de la línea y su primer extremo, luego buscamos ese color en la ultima columna de la imagen (sin tener en cuenta el borde) y ya tendremos los dos extremos. En el listado2 vemos una posible forma de implementación donde se observa una clara diferenciación entre, imágenes con el borde del mismo color que la línea, y diferentes.

LISTADO 2

/* Is the BorderColor equal to LineColor? */
for(i=0; i<height; i++){
   /* If aren't equal, here we have one End of the Line */
   if( memcmp(&BorderColor,buf_img+(i*width),sizeof(img_buf)) !=0 ){
      memcpy(&LineColor,buf_img+(i*width),sizeof(img_buf));
      br_line.x1=0;
      br_line.y1=i;
      break;
   }
}

/* NO */
if( i != height ){
   /* And here we have the other End */
   for(i=0; i<eight; i++){
      if( memcmp(&LineColor,(buf_img+(i*width)+width-1),sizeof(img_buf)) ==0 ){
         br_line.x2=width-1;
         br_line.y2=i;
      }
   }
   printf("LineColor: %x - %x - %x \n",
   LineColor.red, LineColor.green, LineColor.blue);

   /* Become black/white */
   pngclean();
}
/* YES */
else{
   printf("LineColor is equal to BorderColor\n");
   memcpy(&LineColor,&BorderColor,3);

   /* Become black/white */
   pngclean();

   /* Taking the Ends of the Line out of the Border (Background section) */
   for( i = BorderWidth; i< (height-BorderWidth-1) ; i++){
      if( memcmp(&colorBack,(buf_img+(i*width)+BorderWidth),sizeof(img_buf)) !=0 ){
         br_line.x1=0;
         br_line.y1=i;
      }
   }

   for( i = BorderWidth; i< (height-BorderWidth-1) ; i++){
      if(memcmp(&colorNum,(buf_img+(i*width)+(width-orderWidth-1)),sizeof(img_buf)) == 0 ){
         br_line.x2=width-1;
         br_line.y2=i;
      }
   }
}

Si nos fijamos, lo que hace el listado2 es lo que hemos dicho antes. Durante el primer "for" recorre toda la primera columna de la imagen en busca de algún color diferente al borde y saber así el inicio de la línea, pero que pasa con los casos que son iguales? Pues simplemente termina el "for", y en el "if( i != height)" se mira si se ha encontrado algún extremo o no. En caso de haber extremo vamos a la ultima columna y sacamos el segundo extremo. En cambio en el caso que "i == height", lo cual significa que el borde y la línea son del mismo color, hacemos todo lo dicho anteriormente, exploramos la primera columna dentro del borde y la ultima haciendo lo mismo, buscar algún color que destaque en la primera columna y una vez encontrado sacar el segundo extremo en la ultima. Fijaros que aunque estemos mirando la columna 3 (por ejemplo) a la X le asignamos el 0, para tener los extremos reales de la recta.

Si os fijáis siempre se busca el color en la primera columna, eso no es simplemente "porque si", si miramos con atención las imágenes, veremos que en la primera columna, tanto dentro como fuera del borde, todos los píxeles son del mismo color o tienen un pixel diferente que corresponde a la línea, en cambio en la ultima columna, tenemos a parte del pixel de la línea, otros tantos de diferentes colores debido al "shading" que hay con los números del fondo y el color del borde. En la imagen3 vemos este problema, en el primer borde esta todo bien identificado, mientras que en el ultimo vemos una zona ambigua bastante considerable, en la que hay varios píxeles de varios colores.

IMAGEN 3

Probando el método

Ahora que ya esta todo más claro, vamos a probar una primera versión del programa, a ver si realmente es capaz de quitar la línea en todos los casos y dejar los números lo mejor posible. Para ello compilamos el código de la siguiente manera:
$ gcc Dec.c -o Dec -l png
El argumento "-l png" sirve para linkar en el ejecutable dichas librerías Ahora que ya lo tenemos compilado lo pasaremos por todas las imágenes que disponemos:
$ for i in `ls test/`; do ./Dec test/$i modified/$i; done
Reading test/B2UEbwJtB2tVZAA1.png
Width: 180 Height: 50
ColorType: 2 Depth: 8
Bytes: 540
BorderColor: 0 - 0 - 0
BorderWidth: 2
LineColor is equal to BorderColor
LineFound: (0,23) - (179,27)
[..]
Reading test/VTdTMQNtBmMFM1Zt.png
Width: 180 Height: 50
ColorType: 2 Depth: 8
Bytes: 540
BorderColor: 0 - 0 - 0
BorderWidth: 2
LineColor: ffffffff - ffffffff - ffffffff
LineFound: (0,42) - (179,8)
$
Podemos ver una miniatura de todas las imágenes procesadas en el ejemplo, en ellas veréis claramente que el algoritmo tiene fallos y debemos profundizar más en él (ver imagen4). Vamos a analizar el problema con detenimiento. Primero veamos que ha salido bien, la imagen es en blanco y negro tal y como queríamos, hemos sido capaces de borrar el borde sabiendo su grosor y además parece ser que realmente los únicos píxeles que tienen el mismo color que la recta son los de los números, así que todo queda bien diferenciado. En cambio en algunas, muestras 2 y 5 en este caso, vemos que la línea no queda completamente eliminada debido a que los extremos están mal cogidos. Pero por que? Vamos a analizar con detenimiento la imagen original de estas dos muestras.

IMAGEN 4

Solucionando problemas inesperados

Veamos la imagen 5, donde se ven ampliadas las dos muestras originales que nos crean problemas. Veis algo raro en el marco derecho que pueda producir error? Fijémonos en como esta hecha la línea, su disposición de píxeles y como pueden estar dichos píxeles dentro del marco (que al ser del mismo color, no se puede apreciar en el programa).

IMAGEN 5


Centrémonos en el primer y ultimo fragmento de línea que podemos ver antes de que se escondan en el borde, entendiendo como fragmento un seguido horizontal de píxeles pertenecientes a la recta. La longitud del primero es mucho más corta que la del último, de hecho, el último tiene prácticamente la totalidad de la longitud media de los fragmentos de la recta. Esto nos induce a pensar que en el marco existe un fragmento adicional, por lo que la Y es incrementada/decrementada, dependiendo del pendiente de la línea, en una unidad (y++ ó y--). Pensad también que lo que ocurre en el borde derecho, podría ocurrirnos perfectamente en el borde izquierdo, así que deberemos tenerlo en cuenta en ambos casos, y por supuesto, solamente cuando el borde y la línea sean del mismo color, porque de lo contrario no tendríamos este problema.

Ahora que sabemos que el problema se soluciona simplemente incrementando o decrementando en 1 uno de los extremos de la línea o en ambos, solo necesitamos saber como saber que nos encontramos en uno caso de estos, es decir, que el programa se de cuenta que lo ha hecho mal.

Para detectarlo, haremos uso del sentido común, si tenemos la línea mal cuadrada, significara que la nuestra tiene menos pendiente del que debería y entonces no reseguimos los primeros píxeles de la línea porque estamos una unidad de Y desplazados. Para entenderlo mejor solo hay que comparar los resultados de las Muestras 2 y 5 con las originales. Supongo que todos veréis que por el lado que nos hemos equivocado la densidad de restos de la línea es mucho mayor ( porque la nuestra pasaba una Y desplazada ), en cambio por el otro lado no hay prácticamente restos, lo cual indica que el extremo estaba bien cogido. Para ser más exactos, en la misma Y del extremo derecho, aun quedan restos de la línea original, en cambio en la Y del izquierdo no hay ni rastro de la línea original, ¿ Véis una posible manera de detección ? Exacto, reseguiremos los primeros 20 píxeles de Y1 y los últimos 20 píxeles de Y2 en busca de restos de la recta.

La implementación de esta solución es tan simple como hacer la línea inicial, comprobarla y luego re dibujarla modificada si es preciso. Las reajustaciones que hay que hacer en cada caso como el código de dicha implementación lo podéis encontrar en la imagen6. Espero que con los comentarios y la pequeña explicación adjunta en la imagen haya suficiente :), solo recordad que "colorNum" es el mismo que "LineColor".

IMAGEN 6

Comprobando resultados

Bueno ahora ya lo tenemos todo hecho, veamos como nos saca las imágenes problemáticas, tenemos el resultado en la imagen7. Perfecto! Todo parece funcionar bien, ya tenemos nuestro programa para quitar la línea de las imágenes y conseguir que un programa OCR en condiciones nos lo interprete, vamos a probar con "gocr" a ver que nos hace ahora, como "gocr" necesita el formato ".pnm" he hecho un pequeño script que pasa nuestra imagen a dicho formato y luego al "gocr". El script es el siguiente:

IMAGEN 7

$ cat start.sh
#!/bin/bash
convert ${1} ${1}TESTING.jpg
rm -f ${1}TESTING.png
djpeg -pnm ${1}TESTING.jpg > ${1}TESTING.pnm
rm -f ${1}TESTING.jpg
gocr -i ${1}TESTING.pnm -d 0 -s 1 -n 1
rm -f ${1}TESTING.pnm
exit
En realidad seria mucho más sencillo hacer un simple "convert img.png img.pnm" pero a "convert" no le gusta como guardo la imagen y da un "SegFault" :P, perdón por no tener más nivel. Utilizando un script al igual que antes, veamos que nos saca en claro:
sws@LynaXa ~/arroba/rev $ for i in `ls modified/`; do sh start.sh modified/$i; done
5 8 1 9 0 7
_ _ 3 7. _ _
0 5 3 6 4 6
5 1 0 0 7 9
8 9 3 7 7 4
sws@LynaXa ~/arroba/rev $
Jaja, esto ha mejorado bastante eh :) Pero aun tenemos problemas en algunos casos. Después de llegar a este punto, ya podríamos ser capaces de poner multitud de comentarios automáticamente con ayuda de un simple script en Perl, por ejemplo. Pero tal y como vemos, la eficiencia no es del 100%, así que en teoría algunas veces pondríamos mal el número. Claro que para arreglar este problema nos serviremos de la ayuda de los encargados de seguridad del site objetivo, miremos por ejemplo la siguiente imagen:
http://XXXXXXXXXXXXXXXX/img_validator/img.php4?code=UDUDYQBtUzENOQo5
Si vamos actualizando esta dirección veremos como la imagen cambia, pero los números siguen siendo los mismos!! Pero qué error más garrafal! nos permite bajar el mismo número varias veces con diferente disposición de la línea, colores cambiados y fuente diferente de esta manera podremos hacer infinidad de intentos y seguro que en algún caso los resolveremos bien, por ejemplo en el caso que nos falla que es la imagen con el código "UDUDYQBtUzENOQo5", en la imagen8 vemos algunas imágenes con el mismo número y el resto cambiado.

Aunque nuestro programa no fuera capaz de decodificar al completo todos los números en algún caso, no importaría porque podríamos ir completando los 6 dígitos con varios intentos.

IMAGEN 8

Conclusiones

Bueno amigos, hasta aquí el artículo, espero que les haya gustado. Todo lo que he comentado es información sacada de mis propios conocimientos e ideas. Así que si alguien sabe una manera más rápida de hacer lo mismo que me lo haga saber.

El programa comentado está disponible en la web de www.disidents.com, ahora mismo está inactiva, espero que para cuando esto se publique ya esté en servicio. Si alguien se dedica a enviar 1000 comentarios a un site usando mi programa, yo no quiero saber nada, es cosa vuestra, aunque no deberíais.

Yo por mi parte, con algo de ayuda de Pope de www.badchecksum.com, gracias amigo :), me he hecho un Cuelga-Comentarios automático, mirar que gracioso:
sws@LynaXa ~/arroba/rev $ perl rev.pl
usage: rev.pl <dirección_noticia> <comentario>
sws@LynaXa ~/arroba/rev $ perl rev.pl "XXXXXX" "probando"
IMG Code: AGBWPFA9AGMBNFRm
9 RetriesLeft.  [? ? ? ? ? ?]
The Number is: 793640

            Name: arroba_test
  Mail: arroba_test@testing.com
  Comment: probando

Sending form... SENT!
sws@LynaXa ~/arroba/rev $

Comentario

Y ahora si miramos la imagen9 veremos que el comentario ha sido colgado. Esto para que veáis que no es tan difícil hacerlo, es sólo dedicarle un rato. Desde aquí decirles a los técnicos que trabajen un poco más su seguridad y la hagan mejor, ha quedado demostrado que no es tan complicado saltarse este tipo de protecciones si hay un patrón. Y lo que no puede ser es que haya varios modelos de un mismo número y que se te permita ir bajándolos para probar. Pero bueno, ellos verán.

IMAGEN 9


Un abrazo :)

EOF