Ultima modificación : miércoles, 10 de diciembre de 2009
Necesitaba abrir un pdf protegido por contraseña. Era un pdf con las notas de mi novia, y el cual el profesor se iba equivocado metiendo la contraseña y la pobre se iba a quedar todas las navidades sin saber la nota, asi que intentamos hacer fuerza bruta sobre el fichero, con exito.
Desarrolle un script en python que generara palabras de una longitud máxima a partir de un cadena que define un alfabeto. En mi ejemplo configuro las variables con estos valores:
LONGITUD = 6 ALFABETO = "abcdefghijklmnopqrstuvwxyz0123456789_-."
Generar todas las combinaciones posibles conlleva no solo considerar las de longitud 6, si no tambien las de longitud 5,4,3,2 e incluso 1. El alfabeto tiene 39 caracteres por tanto todas las combinaciones posibles son:

cálculo de combinaciones
Contraseñas de longitud mayor que 8 son muy costosas computacionalmente, por ello el script que he realizado me interesa que de mucha información de cuanto queda y cuanto lleva. En concreto 3 cosas:
- El porcentaje que lleva del total.
- Tiempo estimado restante (en horas, lo he puesto).
- Velocidad: en palabras generadas por segundo
Con el dual core de mi portatil a 2.2 Ghz y con el ejemplo que pongo de palabras de hasta 6 caracteres y un alfabeto de 39 caracteres, los tiempos son muy buenos (aunque queda pendiente el uso de paralelización por MPI o algo así):
- Velocidad media aprox: 610.000 palabras generadas / seg
- Tiempo total : 1 hora 50 min
A continuación os pasteo el script (abrir un gedit generarDiccionario ):
#!/usr/bin/python # # :: Invasion Tux # :: Ultima modificacion : miercoles, 10 de diciembre de 2009 # :: Script realizado por makiolo (makiolo@gmail.com) (Licencia Creative Commons con reconocimiento) # :: Ultima version : https://blogricardo.wordpress.com/2008/12/28/script-para-generar-diccionarios-de-fuerza-bruta/ # :: Dependencias : python 2.5 # import sys, math, hashlib from time import time, localtime, strftime from hashlib import md5, sha1, sha224, sha256, sha384 ########################### CONFIGURACION BASICA ######################### LONGITUD = 5 ALFABETO = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789_-." #################################################################### ########################### CONFIGURACION EXTRA #################### CALCULAR_TIEMPO_RESTANTE = True LLAMAR_EVENTO = False GENERAR_FICHERO = True DESTINO_FICHERO = "diccionario.txt" BUSCAR_HASH = True HASH_ALGORITMO = md5 # Opciones: md5, sha1, sha224, sha256, sha384 HASH_BUSCADO = "6091ece73d7b32b63e2f7db82e3bfe9d" #################################################################### ########################## CALLBACK ############################### # ES UN CALLBACK MODIFICABLE SEGUN LA FUNCIONALIDAD A IMPLEMENTAR def eventoPalabraGenerada(palabra): print palabra #################################################################### ########################## FUNCIONES ############################### def getVariacionesConRepeticion(ALFABETO , LONGITUD): sumatorio = 0 for i in range(LONGITUD): producto = 1 for j in range(i+1): producto = producto * len(ALFABETO) sumatorio = sumatorio + producto return sumatorio #################################################################### ##################### VARS AUXILIARES ############################## variacionesConRepeticion = getVariacionesConRepeticion(ALFABETO , LONGITUD) PERIODO_MOSTRAR_ESTADISTICAS = 600000 inicioReloj = time() cont = 0 progreso = 0 #################################################################### if GENERAR_FICHERO: f = open(DESTINO_FICHERO,"w") LONGITUD_MAXIMA = LONGITUD LONGITUD = 1 while LONGITUD <= LONGITUD_MAXIMA: try: contadores = [] # ponemos los contadores a 0 for i in range(LONGITUD): contadores.append(0) fin = False while not fin: palabra=[] # Creas una lista vacia (y liberas de paso) for i in range(LONGITUD): palabra.append(ALFABETO[contadores[i]]) # Vas metiendo al final letra a letra palabra_formada = "".join(palabra) if GENERAR_FICHERO: f.write("%s\n" % palabra_formada) if LLAMAR_EVENTO: eventoPalabraGenerada(palabra_formada) # Envias a tu callback tada la lista unida if BUSCAR_HASH: # algorimos disponibles: HASH = HASH_ALGORITMO(palabra_formada).hexdigest() if HASH == HASH_BUSCADO: print "\n\nDesencriptado el HASH %s !!!!\n" % HASH print "Su valor desencriptado es \"%s\"\n\n" % palabra_formada raise KeyboardInterrupt if CALCULAR_TIEMPO_RESTANTE: if (cont % PERIODO_MOSTRAR_ESTADISTICAS == 0) and (cont != 0): try: progreso = cont*100.0 / variacionesConRepeticion # porcentaje hasta ahora finReloj = time() - inicioReloj # finReloj es lo que esta tardando el calculo velocidad = cont / finReloj # palabras procesadas por segundo estimado = finReloj * variacionesConRepeticion / cont # es lo que se estima en realizar todo el proceso restante = estimado - finReloj # es lo que se estima en realizar lo restante if restante > 60: restante = restante / 60 # lo pasamos a minutos if restante > 60: restante = restante / 60 # lo pasamos a horas unidad = "horas" else: unidad = "mins" else: unidad = "segs" sys.stderr.write("%.2f%% - Quedan %.2f %s. La velocidad es de %.2f palabras/seg\n" % (progreso, restante, unidad, velocidad)) except ZeroDivisionError: pass cont = cont + 1 actual = LONGITUD - 1 # Pongo actual a la derecha del todo contadores[actual] = contadores[actual] + 1 # Sumo 1 a las unidades while(contadores[actual] == len(ALFABETO)) and not fin: # Propago el carry if(actual == 0): fin = True # FIN else: contadores[actual] = 0 # reinicia el actual contador actual = actual - 1 # avanza a la izquierda contadores[actual] = contadores[actual] + 1 # y le sumo 1 LONGITUD = LONGITUD + 1 # combinaciones para uno menos except KeyboardInterrupt: sys.stderr.write("Proceso interrumpido\n") fin = True # Fuerzo las condiciones de salida LONGITUD = LONGITUD_MAXIMA+1 if cont == variacionesConRepeticion: sys.stderr.write("Terminado al 100%\n") else: if CALCULAR_TIEMPO_RESTANTE: sys.stderr.write("Terminado al %.2f%%\n" % progreso) sys.stderr.write("Realizadas %d combinaciones de %d\n" % (cont, variacionesConRepeticion)) if GENERAR_FICHERO: f.close()
Importante cosas que teneis que tener en cuenta:
- P0deis configurar perfectamente la longitud máxima y el alfabeto a uno de vuestro gusto.
- No hace falta decir, que como script debeis darle permisos.
- Tampoco hace falta decir que el uso de este script es con fines didácticos.
- Lo importante es que las palabras salen por el stdout
- Toda la información de cuanto queda para acabar, velocidad … Todo lo «verbose» o «debug» sale por stderr
- Como consecuencia de lo anterior surgen 2 comandos útiles:
- Generar un diccionario:stdout a un ficherostderr a la basura(/dev/null) o mejor no lo redireccionas y va a la pantallaPara estar informados del proceso os recomiento :./generarDiccionario > diccionario.txt
- Es interesante combinarlo con awk pero aqui si que debemos mandar a la basura toda la información de cuanto queda. Probar esto :./generarDiccionario 2> /dev/null | awk ‘{print «La password es » $1}’Bueno, print es un comando de salida de awk, otro comando más interesante es system(), mirar un ejemplo para ver si conecto a mi propio servidor mysql por fuerza bruta:
./generarDiccionario 2> /dev/null | awk '{print "Probando con " $1;system("mysql -h\"localhost\" -u\"root\" -p\"" $1 "\" -e\"quit\" && echo Password " $1 " CORRECTA >> ataque.log");}'
Si consiguiera conectarse con alguna contraseña quedaría registrado en ataque.log . Para cortar la ejecución os recomiendo Ctrl + Z y poner kill %1
Esta es una posibilidad de miles, al ser un script, su verdadero potencial esta en combinarlo con otros programas de shell, ya os digo yo realmente lo uso con «pdftotext fichero.pdf -upw PASSWORD» combinando igual awk + comando de shell.
EDITO: En vista a algunos comentarios he decidido añadir algunas modificaciones:
- Refaztorizado parte del código. Variables con más semántica, redondeos mediante %.2f, lista de parametros en los print. Limpieza de código.
- Para facilitar la tarea a los usuarios de windows, que no suelen estar tan acostumbrados a la redirección a archivos, ahora se genera el diccionario en un txt.
- He añadido soporte para dado un Hash en alguno de los siguientes algoritmos: md5, sha1, sha224, sha256, sha384. Por fuerza bruta se encuentre la semilla del hash.
- Todo esto es configurable en las seccion CONFIGURACION BÁSICA Y EXTRAS.
Filed under: comandos, hack, hacking, ingenieria, python | Tagged: awk, bruta, fuerza, generar, mysql, password, pdf, python, script |
Tal vez te interese utilizar para una próxima vez PDFCrack:
http://pdfcrack.sourceforge.net/
Es un programa con la misma utlidad pero bastante refinado al estar escrito en C y utilizar ensamblador.
Cuando yo lo utilice con gnome cargado tenia unas 20 mil comprobaciones por
segundo e iniciando el pc solo como root en modo recovery conseguia unas 22 mil
(en un portatil que tiene ya 4 años y de un core).
No obstante me ha gustado mucho ver tu script en Python.
Saludos
Gracias por la sugerencia sobre lo del pdfcrack : P Realmente lo conocía pero su flexibilidad es nula, pero vamos para lo que sirve es un programa muy bueno
Si no se entiende algo del código, pregunta : D
De todas maneras por si a alguien le interesa, el quiz de la cuestión esta en generar indices de esta forma:
00000
00001
00002
00003
…….
99999
Es decir una numeración, como pudiera ser la de una matrícula.
Esto que generamos son los indices del array alfabeto[indice], entonces por ejemplo obtenemos realmente:
aaaaaa
aaaaab
aaaaac
…..
zzzzzzzz
me gustaria saber como hacer que el generador me genere en vez de convinaciones de 4 que sean de 18 o mas. muchas grascias
Muy currado el script, lo usaremos algún dia xD
Hola makiolo, exelente trabajo, pero tengo una duda.. como podría hacer para que cada indice generado o sea cada posible clave se guarde en una variable.
Esto para pasar esta variable a una funcion :
funcion(indicegenrado)
saludo2 :)
Es facil lo que planteas, pero esta semana no tengo nada de tiempo, tengo que entregar 2 prácticas, cuando tenga tiempo te respondo. Pero amos la cosa esta en:
for i in range(LONGITUD):
sys.stdout.write(ALFABETO[contadores[i]])
sys.stdout.write(«\n»)
En lugar de sacarlo por pantalla, acumularlo en un buffer y llama a tu función.
Me has dado la idea de rehacerlo orientado a objetos como una clase abstracta, el usuario se hará su propio clase que heredará de esta y simplemente tendrá que implementar el método abstracto que recibe como parámetro la password. ; D
No veo para que una clase abstracta si en java, podes hacer directamente un app, con un par de Jtext Jlabel, y 1 boton :S
Compilas en un jar ejecutable :S
Bueno ya logre hacerlo hacia un buffer con StringIO, voy a estudiar lo de clases abstractas a ver si te comprendo :)
puedes poner tu código aqui.
Una clase abstracta es una clase normal pero que tiene método abstractos que sabes que se ejecutarán, pero no sabes como, hasta que una clase herede de la abstracta e implemente ese método.
Típico ejemplo la clase «Figura» tiene el metodo abstracto «dibujar» por lo que se convierte en clase abstracta, después heredando de esta clase podemos poner Circulo, Cuadrado, Triangulo, estas clases no son abstractas e implementan una método concreto y no tan abstracto.
Un saludo
Esto fue lo que cambie:
import StringIO
for i in range(LONGITUD):
file.write(ALFABETO[contadores[i]])
# sys.stdout.write(ALFABETO[contadores[i]])
# sys.stdout.write(«\n»)
clave = file.getvalue()
print clave
Ahora voy a probarlo con mi función y te cuento
estas usando ficheros? eso es muy ineficiente en una iteración que se va repetir 600000 veces por seg. Mejor usar listas.
perate 5 min y te lo hago, k me has picado xD
Ya esta, es muy facil.
He añadida la función callback que recoge el evento de «palabra generada» y actua como antes, lo saca por pantalla:
def eventoPalabraGenerada(palabra):
print palabra
Para que este evento salte que sustituido las 3 lineas de las que estabamos hablando por :
palabra=[] # Creas una lista vacia (y liberas de paso)
for i in range(LONGITUD):
palabra.append(ALFABETO[contadores[i]]) # Vas metiendo al final letra a letra
eventoPalabraGenerada(«».join(palabra)) # Envias a tu callback tada la lista unida
He actualizado el código del post.
No, no estoy usando ficheros, creo un buffer con StringIO
file = StringIO.StringIO()
ok, no conocía esa clase :P
un saludo
muchisimas gracias por esta fantastica leccion. Buscaba algo asi.
De todas formas soy un nuevo en linux y queria saber como modificar el script para que genere un archico en un a ruta especifica y lo guarde.
Si no se puede no paasa nada, mil gracias
No hace falta modificarlo, ya hace lo que tu kieres.
Estudiate un poco que es el stdout y el stderr.
El script tienes las palabras generadas salen por el stdout y el resto de cosas como información del proceso, etc .. salen por stderr.
En linux puedes redireccionar la salida de un comando a un archivo, enconcreto te interesa el stdout, como creo k he explicado medianamente bien en el post.
Pones:
./generarDiccionario > /tu/ruta/diccionario.txt
Creo que eso quieres, si no es así, dimelo.
gracias makiolo, un placer
cuento pesa el diccionario con los caracteres por defecto que pusiste?
Hola Makiolo
estoy probando tu script con un pdf
este pdf tiene una contraseña de 4 digitos,pero no me muestra la clave en pantalla
en terminal pongo
python diccionarioFB.py pdfconcontraseña.pdf
y al parecer todo bien,el problema es que no veo por ningun lado la contraseña
ah en longitud del script puse 4 pero ya esta no toque nada mas
me imagino que estare haciendo algo mal o me faltara algun dato en la consola
Si me puedes aclarar este pequeño problema te estaria muy agradecido
un saludo y gracias por compartir este script ;)
Hola noname:
El script es para generar todas las palabras posibles, dado un alfabeto y una longitud maxima..
Ahora mismo, lo unico que hace con cada palabra generada, es mostrarlo por pantalla:
def eventoPalabraGenerada(palabra):
print palabra
Esa función la puedes modificar para que haga llamadas al sistema, por ejemplo hazte un script de bash(comprobarPassword.sh) que haga «exit 0» si la contraseña es valida, «exit 1» si es invalida, y modifica el callback:
def eventoPalabraGenerada(palabra):
salida = os.system(«./comprobarPassword.sh %s» % palabra)
if salida == 0:
print «El password es %s» % palabra
O como propongo en el tutorial, usando tuberías.
Makiolo gracias por contestar
la verdad es que acabo de empezar en el mundillo de los scripts y hay muchas cosas que me suenan a chino
para generar el script comprobarPassword.sh que seria este codigo que tu has puesto
def eventoPalabraGenerada(palabra):
salida = os.system(”./comprobarPassword.sh %s” % palabra)
if salida == 0:
print “El password es %s” % palabra
sabes me gustaria poder probar este script que tu has hecho para compararlo con el pdfcrack puesto que el pdfcrack no es capaz de sacarme una contraseña de 5 digitos,estuve como 2 horas y media y lo cancele por aburrimiento.
el pass que le puse : «noname»
buscare informacion sobre tema tuberias a ver que tal,tambien acepto consejos y todo tipo de ayuda.
Cuando lo consiga te digo algo.
un saludo y gracias de nuevo.
te hago una pregunta? si quisiera que cada combinacion o respuesta posible sea almacenada en un archivo txt, que tendría que modificar?
es decir si quiero que me de como resultado 3611342280 archivos, cada uno con una posibilidad ¿es muy complicado de modificar?
Hola Victoria:
Es muy facil de modificar, pero ese numero de archivos es brutal. ¿Que quieres hacer? poder se puede, sería algo así:
La función callback (que solo hace print) quedaría sustituida por:
def eventoPalabraGenerada(palabra):
f = open(‘%s.txt’ % palabra, «w»)
f.write(«%s\n» % palabra)
f.close()
El sentido de hacer eso, solo lo sabes tu xD
Este script hay que guardarlo como un archivo vbs osea FuerzaBruta.vbs
saludos y gracias por tu trabajo
este scrip para Vb parece bueno, voy a probarlo, ando intentando realizar un programa de fuerza bruta en visual 6, tengo todo listo y estoy viendo la manera más sencilla de generar palabras, que si bien son aleatorias, no es como deberia, ya que la pagina web a la cual quiero realizar atakes me permite el ingreso de infinitos usuarios y claves (ke gran error)
Gracias, saludos.
@nonimo
entonces como se ejecutaria este script en sistemas windows,por ms-dos???
como lo puedo hacer que cunado guarda el dicc guarde la palabras de mayor a menor
juan mmmm pues asi una solución muy facil es invertir el alfabeto. Ya que el diccionario se genera en el mismo orden que el alfabeto.
Puedes invertirlo así:
ALFABETO = ALFABETO[::-1]
Hola makiolo, tengo una consulta que seguro resultara un poco tonta, pero es que mis conocimientos de programacion son algo escasos (y practicamente nulos en este lenguaje) pero espero una ayuda de vuestra parte.
Mi problema es que estoy utilizando tu script en windows 7 64bits y no tengo ni idea de como hacer para que se me genere un archivo con el listado de combinaciones.
ademas querria saber si este se puede ejecutar para que aproveche el procesador multicore que tengo.
Un saludo y gracias de antemano.
El tutorial en principio es para linux, pero en windows la salida de un comando de shell tambien se puede redireccionar a fichero con >. En windows no hay awk pero pienso que el siguiente comando te debería funcionar:
./generarDiccionario > diccionario.txt
Aca esta el codigo modificado para buscar MD5
makiolo: Gracias por el post, pero te lo borro por que lo has pasteado sin identar.
Con el script md5 me da error con los . y con -…
Tambien me da error en
File «./pass1», line 24
sumatorio = 0
^
IndentationError: expected an indented block
@Marcelo:
Gracias por tu post, debido a que la funcionalidad de md5 en este tipo de script se puede considerar básica, he añadido la funcionalidad en el script del post principal, aunque he hecho algún cambio mas, mira el final del post.
@jose:
El script de marcelo no pasteo correctamente, en python la identación es de vital importancia, por eso se recomienda configurar tu editor de python para que tabule con espacios en lugar de tabs, precisando para evitar ese tipo de copy pastes conflictivos. Edito el post de Marcelo y prueba el del post principal que funciona perfectamente tambien.
Un saludo.
Si, perdon, se ve que no mire bien cuando lo pastee y quedo mal. Bueno, ahi le puse ademas los sha con lo cual puedo ampliar aun mas la busqueda ;) me permito agregar en este post el codigo de unas modificaciones mas que hice sobre el codigo original:
1- Algo que me rompia el coco era que si por alguna razon apagaba la maquina debia empezar todo de cero, pues ahora no pasa asi, cada x tiempo graba un archivo de log con el cual si se inicia nuevamante el programa recupera de donde habia cortado la ejecucion.
2- Para ser mas rapido y usar potencia de la maquina agrego una opcion que es -r con lo cual arranca en inverso…. ;) 2 busquedas son mas rapidas que una.
Salu2
Script pasteado aqui: http://paste.dprogramming.com/dpxmybuw
Hola a todos, sera posible con algun script como este, o mejor dicho modificarlo para sacar palabras de una pagina web, es decir generar un diccionario apartir de las palabras de una pagina web
si alguien sabe porfa ayudenme, o denme algun dato de como buscar o como hacerlo
Quizas el CeWL te sirva para lo que quieres hacer, pero si quieres modificarlo por tu cuenta, debes saber que esta hecho en Ruby.
Hola a todos, sera posible con algun script como este, o mejor dicho modificarlo para sacar palabras de una pagina web, es decir generar un diccionario apartir de las palabras de una pagina web
si alguien sabe porfa ayudenme, o denme algun dato de como buscar o como hacerlo
Hola makiolo, Necesito desencriptar un pdf. Llevo un día entero corriendo el pdfcrack y me topé con tu blog. Me he cansado y al ver lo de generar un diccionario me llamó la atención un montón… porque creo que es la solución a mi problema, lo que pasa es que si bien es cierto que te explicas muy bien, yo no estoy al nivel y no tengo por donde coger el tema… He creado un archivo de texto donde aparece completamente todas las instrucciones de tu blog. Supongo que eso habrá que compilarlo o algo ¿cómo? (luego te haré más preguntas). Aunque me ahorrarías un montón si me pasaras el archivo de texto que origina el programa al correo que te pongo:
ninojezus@yahoo.com
Saludos y gracias
he probado wifiway 2.0.3 en CD,PENDRIVE USB,DISCO DURO EXTERNO,VMWARE.
Me ocurre que en el generador de diccionarios me dice: ERROR NO SPACE LEFT ON DEVICE.
En la configuraciòn del diccionarios le puse longitud:10 y alfabeto:1234567890
alguna soluciòn?
maxphone@live.cl
saludos
Buenas tardes, gracias por el script aunque no se mucho de programación lo estoy haciendo correr, pero me asaltan dos dudas:
1. No acepta la «ñ», sin embargo le puse la m(reemplazandola)
2. Como hago para que me tome una palabra como si fuera una sola letra. Me explico: Se me perdio una contraseña propia y se que tiene esta palabra «c0ntraseña», y un juego de caracteres mas.
Ahora deseo que me combine esa palabra con el resto de caracteres siempre teniendo la palabra completa
Hola!. Una dudita!. Usando el generador de diccionario con tu script, integrado en wifiway, no he dado con la forma de que al generarlo me indique donde quiero guardarlo. Es decir, como lo uso desde una maquina virtual, quiero guardar el resultado en un pendrive, por ejemplo.
Gracias. Un gran saludo a esta comunidad.
Sino me equivoco ya use tu codigo, es el que esta en wifiway 2.0.2, lo ase muy bien, pero ¿si quisiera ejecutarlo en windows 7? se podria?.
Sino me equivoco ya use tu codigo, es el que esta en wifiway 2.0.2, lo ase muy bien, pero ¿si quisiera ejecutarlo en windows 7? se podria?. O necesitaria algun otro programa?
Use este código adaptandolo a Java. Sin embargo no lo entiendo del todo. Podría alguien explicarme un poco mas sobre el?
Es que quisiera hacer una versión para que corriera en paralelo. Pero aún no comprendo del todo
Buenas tardes alguien me podria auxiliar encontre un script para generar un diccionario con hex pero no se como ocuparlo me podrian auxiliar?
Me gusto mucho tu script la verdad que para contraseñas va de miedo.
Te doy la enorabuena.
Si algun dia desarrolo algo con el seras notificado.
Makiolo, porfa ayudame con esto, me gustaria saber como hacer que el generador me genere en vez de convinaciones de 4 que sean de 18 o mas. muchas grascias