Tema destacado: Entra al canal IRC oficial de #elhacker.net
Autor
|
Tema: Algoritmo basico de Brute Force en C (Leído 3,991 veces)
|
|
Rojodos
|
Bueno, el rollo viene de este post en www.hackxcrack.com:http://hackxcrack.com/phpBB2/viewtopic.php?t=7994&postdays=0&postorder=asc&start=0Como veis, puse un codigo basico de hacer fuerza bruta en C. Aki va el codigo, para el que no tenga muxa idea, o kiera hacer pruebas: /* Algoritmo de Brute Force Basico en C Original en Java: CrashCool http://hackxcrack.com/phpBB2/viewtopic.php?t=7994 Convertido en C por Rojodos */
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h>
int compara (char *cadena_a_chekear){ char pass[] = {'9','1','1','o','o','o','\0'}; // 911ooo -> Password a Sacar return strcmp (cadena_a_chekear, pass); }
int main (){ printf ("Algoritmo basico de Brute Force\n"); printf ("Original en Java por CrashCool\n"); printf ("Convertido en C por Rojodos\n"); printf ("El programa trata de encontrar '911ooo' secuencialmente\n"); printf ("Se puede cambiar en el Codigo Fuente\n"); char Base[] = {'1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; int longitud = 36; char cadena[6]; char pass; unsigned long int claves = 0; clock_t reloj, reloj2; float tiempo; int i,j,k,l,m,n; // Iniciamos Brute Force printf ("Iniciando Brute Force\n"); reloj = clock(); for (i = 0; i < longitud; i++){ cadena[0] = Base[i]; for (j = 0; j < longitud; j++){ cadena[1] = Base[j]; for (k = 0; k < longitud; k++){ cadena[2] = Base[k]; for (l = 0; l < longitud; l++){ cadena[3] = Base[l]; for (m = 0; m < longitud; m++){ cadena[4] = Base[m]; for (n = 0; n < longitud; n++){ cadena[5] = Base[n]; cadena[6]='\0'; claves ++; // Chequeemos... if ( compara (cadena) == 0){ reloj2 = clock(); tiempo = ((float)reloj2-(float)reloj)/CLOCKS_PER_SEC; printf ("Password encontrado!\n\n"); printf ("Clave = %s\n", cadena); printf ("Tiempo transcurrido = %f segundos\n", tiempo); printf ("Claves Generadas = %d\n", claves); exit(0); } } } } } } } return 0; } Y la salida que da al compilarlo en Windows: D:\Dev-Cpp\bruteforce>bruteforce
Algoritmo basico de Brute Force Original en Java por CrashCool Convertido en C por Rojodos El programa trata de encontrar '911ooo' secuencialmente Se puede cambiar en el Codigo Fuente Iniciando Brute Force Password encontrado!
Clave = 911ooo Tiempo transcurrido = 38.194000 segundos Claves Generadas = 483761401 Espero que os sirva de ayuda para aclarar dudas y tal... Podeis modificar el codigo, hacer lo que os de la gana con el...  Cualkier comentario, sera mas que bien recibido. Salu2
|
|
|
|
|
En línea
|
|
|
|
soplo
Ex-Staff
Desconectado
Mensajes: 3.597
Debian rool'z
|
Hola Yo creo que funciona mejor con una función recursiva, porque tienes mas opciones (por ejemplo no tienes que conocer la longitud de la clave)
Sería algo como esto:
int compara(char *cadena_a_chequear) { // Aquí se compara la posible pass con la pass real // devuelve 0 si se ha tenido éxito return strcmp(cadena_a_chequear,pass) }
// rutina que compara claves. Devuelve la clave obtenida. Se para si se llega a 1000 caracteres o si se pulsa una tecla
int buscarclave(char *pass_a_chequear,int Codigo_ascii) Char Nueva_clave_a_chequear[1000] //una prueba para cada código ascii a partir del espacio (32) strcpy(Nueva_clave_a_chequear,pass_a_chequear); //copio la posible pass InsertarNuevoCaracterAlFinal(Nueva_clave_a_chequear) // y le añado un caracter al final if( compara(Nueva_clave_a_chequear) return 0 //devuelvo éxito else buscarclave(pass_a_chequear,++ascii) //se vuelve a probar la cadena expandida para sacarle mas combinaciones // si ascii=255 se vuelve a poner a 32 if (ascii=255) ascii=32 if (Se_ha_pulsado_tecla()) return -1 if (se_ha_llegado_a_chequear_1000_caracteres()) return -1 }
int main() { int ascii = 32; //(código ascii del espacio) // se empezará a comprobar caracteres desde este valor int longitud=0; //longitud de la cadena a chequear char Pass_a_Chequear as char[1000]; // se admiten longitudes de pass de hasta 999 caracteres clock_t hora_inicial, hora_final; float tiempo hora_inicial=clock(); if (buscarclave(Pass_a_Chequear,ascii)) { hora_final=clock(); tiempo = ((float)hora_final-(float)hora_inicial)/CLOCKS_PER_SEC; printf ("Password encontrado!\n\n"); printf ("Clave = %s\n", cadena); printf ("Tiempo transcurrido = %f segundos\n", tiempo); } return 0; } Sería mas o menos esto. No lo he probado porque se que hay errores de bulto (por ejemplo debería utilizar un puntero a ascii en vez de ascii puesto que modifico su valor), pero la idea básica se entiende.
Se trata de crear una función que partiendo de valor nulo vaya añadiendo un caracter y pruebe. Si es válida ya está, si no es válida prueba a cambiar el caracter añadido con la siguiente posibilidad y prueba. Si se le acaban las posibilidades aumenta en uno la longitud de la cadena y empieza de nuevo.
Las posibilidades empiezan con el código ascii 32 (espacio) y acaban con el 255 (último código ascii). De esta manera incluímos todas las posibilidades de letras, números, puntuación, acentuación, números, etc.
Empiezo en el 32 porque los 31 primeros carácteres del código ascii son caracteres no imprimibles como el tabulador, etc.
No incluyo las funciones de comprobar si se ha pulsado una tecla o añadir un elemento al final por ser funciones de manual. En este último caso hay que considerar que siempre hay que acabar en \0 o bien en vez de strcpy y strcmp copiar/comparar bites.
Se me ocurre que si se le pasa como parámetro el nombre de un diccionario bastaría con ir leyendo secuencialmente de un archivo, dar el valor leído a pass_a_chequear y probar combinaciones con esta palabra. Si no sale se lee de nuevo y se vuelve a probar.
Un saludo
|
|
|
|
« Última modificación: 27 Agosto 2003, 06:44 por soplo »
|
En línea
|
Callar es asentir ¡No te dejes llevar!
|
|
|
|
Rojodos
|
Bueno, varias cosas: - No se puede realizar un algoritmo recursivo en una funcion de este tipo, pues las operaciones a realizar son muchas y es mas que probable que el sistema pete o se vuelva inestable. - 1000 caracteres es algo nimio a probar, pues en una clave "corta" (corta en el sentido de que por orden alfabetico se llega antes) ya genera 100 millones de claves en 10 segundos, con lo cual con 1000 caracteres no tenemos para empezar. - Me gustaria ver el codigo que propones funcional, porque con el esquema que has puesto, me hago un lio y no se por donde van los tiros.... yo tarde 1hora mas o menos en hacer el codigo iterativo, no creo que tardes mucho mas en hacerlo recursivo. Ademas, asi queda mas chulo  - Lo de ascii++ me da mala espina.... probaria mayusculas, minusculas, numeros y signos de puntuacion, con lo que el proceso seria mas completo pero mucho mas lento.... si funciona.... Salu2
|
|
|
|
|
En línea
|
|
|
|
soplo
Ex-Staff
Desconectado
Mensajes: 3.597
Debian rool'z
|
Hola Pues tienes mucha razón en todo lo que dices. Solo fue un ejercicio que me hice al leer tu post. Pensé en alguna rutina sencilla que dejara clara una idea de como hacer brute force por otro método. La iteración no es un mal método. Símplemente pensé utilizar la recursividad, pero es obvio que puede ser inestable si se utiliza con gran cantidad de combinaciones y se disponen de recursos limitados. Escogí 1000 caracteres por poner un número. No es importante el número sino como se van obteniendo. Me parece una ventaja tener un algoritmo que vaya probando combinaciones y cuando acabe con ellas aumente la longitud de la cadena a probar. Al poner ascii++ simplemente pensé en incluir todos los códigos ascii a partir del espacio. Obviamente esto lo hace mucho mas largo pero también mucho mas seguro de que pille. Bueno, sobre esto que es simplemente un ejercicio mental voy a hacer la rutina y la compilo. Si funciona la posteo, aunque seguramente será inestable si no se tienen muchos recursos Esto no es un concurso de quien es mejor programador o tontería semejante. Lo que has puesto está bien y probablemente funciona bien. Esto es una prueba que quizá funcione, quizá mejor, quizá peor y quizá no funcione.  Un saludo
|
|
|
|
|
En línea
|
Callar es asentir ¡No te dejes llevar!
|
|
|
|
Rojodos
|
 Kien ha dixo que sea un "concurso" ? Simplemente tengo curiosidad, porque no se me habia ocurrido lo de la recursion cuando hice el codigo.. y tengo interes en como verlo. Asi aprendemos los dos 8)
|
|
|
|
|
En línea
|
|
|
|
soplo
Ex-Staff
Desconectado
Mensajes: 3.597
Debian rool'z
|
Aquí dejo el algoritmo por el método recursivo. Lo he compilado con Dev-C++, pero no consigo ejecutarlo. Creo que tengo memoria defectuosa porque también me pasa con otras rutinas (o quizá es el propio compilador que le pasa algo). El caso es que me salen errores de protección general en cuanto intento ejecutar. Si encontrais algún error decidlo. Basta con copiar y pegar el código. La rutina básica a comprobar es la de BuscarClave. El resto son pequeñas rutinas para complementarla. La lógica es la siguiente: Parto de una cadena vacía. Le voy a añadir un caracter y probaré. Si no vale, sobre esta cadena obtenida (que tiene un caracter probaré todas las combinaciones posibles añadiendo otro caracter. A cada una de ellas les voy probando todas las combinaciones posibles añadiendo un caracter. De esta forma he reducido el problema a una rutina a la que se le pasa una cadena y la comprueba. Si no vale hace diversas combinaciones sobre esta cadena añadiendo un caracter y las prueba. Cuando ha terminado con todas las combinaciones de 1 caracter añade otro caracter y vuelve a empezar. Es un algoritmo recursivo. *********************************************
include <iostream> #include <stdlib.h> #include <time.h>
using namespace std; /* Declaración de funciones */ int CompararClaves(char *p); char *BuscarClave(char *p); char ObtenerNuevoCaracter(char p); char *ExpandirClave(char *p, char q);
/* Declaración de variable Global donde guardaré el Resultado */ char *ClaveDescubierta;
/* Rutina a la que se envía un caracter y devuelve el siguiente caracter a comprobar En este caso solamente paso al caracter siguiente y si es 256 significa que he terminado con el último caracter y vuelvo a empezar desde el espacio (código 32) */ char ObtenerNuevoCaracter(char Caracter) { ++Caracter; if(Caracter==256) /* ¿He sobrepasado el último caracter posible? */ { Caracter=32; /* si es cierto volver al comienzo */ }; return Caracter; } /* Rutina que expande una clave añadiendo un elemento nuevo a la clave */ char *ExpandirClave(char *Clave,char Caracter) { char *ClaveExpandida=(char *) malloc(strlen(Clave)+1); /* crear espacio en ClaveExpandida para Clave +1 */ strcpy(ClaveExpandida,Clave); /* Copiar lo que hay en Clave a ClaveExpandida */ strcat(ClaveExpandida,Caracter); /* añadir el último caracter */ return ClaveExpandida; } /* Rutina que compara la clave obtenida con la clave buscada. En este caso pongo la clave a buscar '1234' solamente a modo de prueba */ int CompararClaves(char *ClaveaComparar) { char ClaveBuscada[]="1234"; return strcmp(ClaveaComparar,ClaveBuscada); } /* Rutina a la que se le pasa una clave hace lo siguiente: En clave2 guarda CLAVE + UN_CARACTER y comprueba si es la clave. Si no lo es guarda en clave2 el valor CLAVE + OTRO_CARACTER. Este nuevo caracter se obtiene mediante la función ObtenerNuevoCaracter */ char *BuscarClave(char *Clave) { char *Clave2; /* Lugar donde voy a ir añadiendo CLAVE + caracter */ char x; for (x=32;x<256;++x) /* para cada posible caracter */ { /* Aquí pongo la funcion ObtenerNuevoCaracter para que se vea donode un algoritmo de este tipo, pero en este caso no es necesario porque x ya es el código ascii que quiero añadir. En este caso la línea sería: Clave2=ExpandirClave(Clave, x); */ Clave2=ExpandirClave(Clave,ObtenerNuevoCaracter(x)); /* añadir un caracter nuevo a clave y dejar el resultado en clave2 */ if (!CompararClaves(Clave2)) /* comparar clave2 con la clave auténtica si es 0 clave encontrada */ { return Clave2; } else { return BuscarClave(Clave2); /* Volver a buscar ahora con la Clave2 */ } }; } int main(int argc, char *argv[]) { /* Declaración de clave a probar. Inicialmente está vacía */ char ClaveaProbar[1]=""; /* Definir variables de hora inicial y final para poder calcular el tiemp que tarda */ clock_t HoraInicial, HoraFinal; /* Definir variable que calcula la diferencia en segundos entre hora inicial y final */ float TiempoTranscurrido; HoraInicial=clock(); /* poner la hora inicial de búsqueda de clave */ ClaveDescubierta=BuscarClave(ClaveaProbar); /* algoritmo que devuelve la clave. */ if (strlenClaveDescubierta)>0) { HoraFinal=clock(); /* poner la hora final de búsqueda de clave */ TiempoTranscurrido = ((float)HoraFinal-(float)HoraInicial)/CLOCKS_PER_SEC; /*calcular el tiempo transcurrido */ printf ("¡Password encontrada!\n\n"); printf ("Clave = %s\n", ClaveDescubierta); printf ("Tiempo transcurrido = %f segundos\n", TiempoTranscurrido); }
system("PAUSE"); return 0; }
Un saludo
|
|
|
|
« Última modificación: 6 Septiembre 2003, 07:52 por soplo »
|
En línea
|
Callar es asentir ¡No te dejes llevar!
|
|
|
|
Rojodos
|
No lo puedo probar ahora porque estoy en "otras cosas"  , pero si te peta por fallo de memoria o algo asi, es por lo que te dije, es muy probable que el algoritmo recursivo te deje sin pila, al abarcarla toda para guardar los parametros del proceso... Salu2
|
|
|
|
|
En línea
|
|
|
|
soplo
Ex-Staff
Desconectado
Mensajes: 3.597
Debian rool'z
|
Hola Si, puede ser. También puede ser que haya algún fallo. Estas cosas es conveniente ejecutarlas y ver que sale.
En cualquier caso solo es un ejercicio. A quien le interese la recursividad tiene un ejemplo.
Un saludo
|
|
|
|
|
En línea
|
Callar es asentir ¡No te dejes llevar!
|
|
|
|
HaCkeR-BoY
|
VALE MUY INTERESANTE PERO DONDE PUEDO HACER SERVIR ESTE PROGRAMA ?????????
|
|
|
|
|
En línea
|
|
|
|
m4rc14n0sk4t3
Desconectado
Mensajes: 5
|
A lo bien, ese programa no lo soporta ningun computador, pues digo yo. Si lo han tratado de ejecutar, si lo ejecutan miren el administrador de tareas y me cuentan cuanta memoria les ocupo. suerte
|
|
|
|
|
En línea
|
SKATE ALL DAY ................................... ...........................DRINK ALL NIGHT!!!!!!
|
|
|
zheo
Desconectado
Mensajes: 707
|
Solo una cosa, por lo general no es bueno utilizar una recursión para superproblemas, es decir, para los problemas en los que en cada llamada recursiva el problema a tratar es mayor que el problema que estamos tratando actualmente. O expresado formalemente, recurrencias con este tipo de ecuaciones:
T(n) --> c1 si caso base --> T(n+1) si otro caso
Principalmente porque no podemos fijar un buena condición de terminación. En este caso, si la clave tiene 20 caracteres no acabará nunca...
Luego, algo debe de estar mal, porque con una clave de un sólo caracter falla. No lo he mirado en profundidad, pero de mano, en la línea 33 haces un malloc y lo asignas a un puntero que ya contenía memoria, con lo cual ahí ya tenemos una fuga de memoria. La solución es cambiarlo por realloc.
Lo he mirado un poco mejor y ya se cual es el problema. haces un bucle for para buscar el primer carácter de la clave, y entonces la expandes y luego compruebas.
Debería ser, primero comprobar, y luego expandir y pasárselo a la función recursiva. Y además, no deberías recorrer sólo el primer carácter de la clave, sino todos hasta el tamaño de la clave, lo que indica que a la función BuscarClave has de pasarle un parámetro más.
En definitiva, que en este caso la recursión no es un buen ejemplo IMHO, no sólo por eficiencia sinó por claridad.
Luego me pongo a estudiar la función de rojodos, y la paso a recursivo formalmente (si se hacerlo, claro) a ver cómo queda.
Un saludo.
|
|
|
|
|
En línea
|
|
|
|
soplo
Ex-Staff
Desconectado
Mensajes: 3.597
Debian rool'z
|
Tienes toda la razón Zheo (también la tuvo Rojodos a las críticas que me hizo en su día) Primero la recursividad es una mala solución para este problema. Solo me lo planteé como ejercicio mental y luego me picó, pero no pude llegar a ejecutarlo, por lo que puede haber errores. Tengo algunas cosillas en otro sitio que están a medias y debo terminarlas, pero luego repasaré esto porque lo puse como ejemplo y efectivamente debería ser claro y no contener errores porque sino, no vale como ejemplo. Creo que lo que haré es partir del código de Rojodos y adaptarlo para que pueda utilizar diccionarios o algún tipo de búsqueda "inteligente" Bueno, bueno que siempre digo que voy a hacer y lo dejo todo a medias, primero terminar lo que tengo a medias y luego esto  Un saludo
|
|
|
|
|
En línea
|
Callar es asentir ¡No te dejes llevar!
|
|
|
xiam
Desconectado
Mensajes: 49
There's no place like 127.0.0.1
|
Hola, tb andaba con la curiosidad de como hacer esto, se me ocurrieron dos formas, (en realidad la primera, la basada en mapa dado fue mi primer idea, pero resultó ser algo lenta, asi que pensé que era mas fácil con límites). Bueno, les dejo  . // // wgen.c 1.0 - Motor generador de palabras // -------------------------------------------------------------------- // Autor: J. Carlos Nieto <jkn@menteslibres.net> // Copyright (C) 2004, J. Carlos Nieto //
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
Si cambias el motor para hacerlo mas rapido, mejor o usarlo en un proyecto me gustaria verlo :). Por favor escribeme.
*/
// Probado bajo GNU/Linux Kernel 2.6.7; GCC Version: 3.2 // Compilar: gcc -o wgen wgen.c // Ejecutar: ./wgen // Para cambiar de motor se debe comentar el otro o removerlo.
#include <stdio.h> #include <stdlib.h> #include <time.h>
// NOTA: los acentos en los comentarios han sido omitidos por asuntos de incompatibilidad.
// conf: general #define DEF_MNL 0 // longitud de palabra minima. #define DEF_MXL 4 // longitud de palabra maxima.
// conf: engine 2 // caracteres a usar #define DEF_CHARSET "abcdefghijklmnopqrstuvwxzy0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" // default charset
// conf: engine 1 // inicio y fin del mapa de caracteres a usar #define DEF_CHARSET_BGN 33 #define DEF_CHARSET_END 126
int main (int argc, char *argv[]) { int i; // en lugar de las constantes puedes usar los argumentos int mnl = DEF_MNL; int mxl = DEF_MXL; unsigned int csb = DEF_CHARSET_BGN; unsigned int cse = DEF_CHARSET_END; clock_t stime, etime; double gtime; unsigned char s[128] = { 0 }; int c, w; c = i = w = 0;
printf ("%s: wgen.c 1.0 comenzando...\n", argv[0]); // ----- <engine 1> ----- // Este es mi motor mas rapido, basado en un limite minimo y maximo del mapa normal de caracteres. // Velocidad maxima en mi Celeron 500MHz: 43210457.71428 p/s // c = longitud de palabra // s = palabra //
mnl--; if (mnl < 0) mnl = 0; c = mnl; for (i = 0; i <= mnl; i++) { s[i] = csb; } s[c]--;
printf("Longitud de palabra: %i\n", c+1); stime = clock(); while (c < mxl) { s[c]++; if (s[c] >= cse) { for (i = c; s[i] >= cse; i--) { s[i] = csb; if (i) { s[i-1]++; } else { s[i+1] = s[c+1] = csb; c++; printf("Longitud de palabra: %i\n", c+1); } } } // activa este printf si deseas ver las palabras generadas, esto es realmente lento. //printf("\%s\n", s); w++; } etime = clock(); // ---- </engine 1> ----
/* // ---- </engine 2> ---- char chs[] = DEF_CHARSET; unsigned char n[128] = { 0 }; int chl = strlen(chs);
// este es otro buen motor, pero es mas lento, se basa en un mapa dado y un array de contadores (n). // Velocidad maxima en mi Celeron 500MHz: 24223501.612903 p/s mnl--; if (mnl < 0) mnl = 0; c = mnl; for (i = 0; i <= mnl; i++) { n[i] = 0; s[i] = chs[0]; } w = 0; n[c]--;
printf("Longitud de palabra: %i\n", c+1); stime = clock(); while (c < mxl) { n[c]++; for (i = c; n[i] >= chl; i--) { n[i] = 0; s[i] = chs[0]; if (i) { n[i-1]++; s[i-1] = chs[n[i-1]]; } else { n[i+1] = n[c+1] = 0; s[i+1] = s[c+1] = chs[0]; c++; printf("Longitud de palabra: %i\n", c+1); } } s[c] = chs[n[c]]; // activa este printf si deseas ver las palabras generadas, es realmente lento. //printf("%s\n", s); w++; } etime = clock(); // ---- <engine 2> ---- */
// estadisticas gtime = ((double) (etime - stime)) / CLOCKS_PER_SEC; printf("Estado: Finalizado\n"); printf("Palabras generadas: %d \n", w); printf("Tiempo tomado: %f segundos\n", gtime); printf("Velocidad Media: %f p/s\n", w/gtime); }
|
|
|
|
« Última modificación: 20 Julio 2004, 03:17 por xiam »
|
En línea
|
El blog de xiam.La civilización no suprime la barbarie, la perfecciona. (Voltaire).
|
|
|
|
|