hit counter

Sistemas y servicios informáticos para Internet. Curso 2009-2010

Capítulo 9. Grid computacional

Tabla de contenidos

9.1. Introducción
9.2. Ejecución de trabajos en el grid
9.3. Ejercicio práctico: crackear contraseñas

9.1. Introducción

Antes de empezar hay que conectarse a tecgrid03.epv.uniovi.es en caso de que no lo estés ya. La conexión debe ser ssh, por lo que es necesario utilizar un cliente que soporte este protocolo. Se recomienda utilizar el PuTTY.

Crearemos un directorio para contener los ficheros con los que se va a trabajar.

$> mkdir ~/integra
$> mkdir ~/integra/computa
$> cd ~/integra/computa

Antes de poder ejecutar comandos sobre globus tenemos que obtener un proxy.

$> grid-proxy-init
Your identity: /O=Grid/OU=GlobusTest/OU=simpleCA-tecgrid03.epv.uniovi.es/OU=atc/CN=Rosco
Enter GRID pass phrase for this identity:
Creating proxy ................................ Done
Your proxy is valid until: Fri Feb  6 06:30:23 2009

9.2. Ejecución de trabajos en el grid

El grid sobre el cual se va a trabajar consta de dos clusters. Cada uno de ellos tiene instalado condor como LRMS (Local Resource Management System). Globus actua como interfaz de cada uno de los clusters, y por encima se sitúa Condor-G como metaplanificador de trabajos.

Para comprobar su funcionamiento, vamos a lanzar un trabajo que proporcione información sobre la máquina en la cual se ejecute.

$> cat > hostinfo
#!/bin/sh

echo "Execution on `hostname`"
sleep 10

Le damos permisos de ejecución y verificamos que funciona correctamente.

$> chmod +x hostinfo
$> ./hostinfo
Execution on tecgrid03.epv.uniovi.es

El siguiente paso va a consistir en crear el fichero de descripción del trabajo. Para enviar el trabajo vamos a utilizar Condor-G, por tanto, el formato del fichero de descripción será el que utiliza Condor.

$> cat > hostinfo.sub
Universe      = grid

grid_resource = gt4 $$(gatekeeper_url) $$(job_manager_type)
requirements = (TARGET.gatekeeper_url =!= UNDEFINED) && \
               (TARGET.job_manager_type =!= UNDEFINED)

Executable    = hostinfo
output        = hostinfo.$(Process).out
error         = hostinfo.error
log           = hostinfo.log
should_transfer_files   = YES
when_to_transfer_output = ON_EXIT
Queue 10

Utilizamos el universo grid y como recurso grid gt4 (Globus GRAM versión 4). Además, indicamos que queremos utilizar cualquier elemento de computación que esté disponible. Estamos utilizando Condor-G para enviar el trabajo a una máquina Globus, y esta a su vez se lo va a enviar a un gestor de trabajos (en este caso coincide que es Condor).

Envíamos el trabajo y esperamos a que termine.

$> condor_submit hostinfo.sub
Submitting job(s)..............................
Logging submit event(s)..............................
10 job(s) submitted to cluster 966.

Si compruebas el estado de los trabajos verás como aparece un nuevo trabajo denominado gridftp_wrapper.sh. Este trabajo ha sido creado por Condor para realizar la transferencia de los ficheros utilizando GridFTP.

Comprueba los procesos que se han creado para ejecutar el trabajo.

$> ps aux | grep condor

...

Uno de los procesos que aparece es condor_gridmanager, encargado de interactuar con los recursos grid.

Espera a que el trabajo termine (no te preocupes si gridftp_wrapper.sh sigue ejecutándose, terminará un rato después).

Comprueba que los trabajos se han ejecutados en máquinas pertenecientes a los dos clusters.

$> cat *.out

...

9.3. Ejercicio práctico: crackear contraseñas

El objetivo de este ejercicio es ejecutar un trabajo que sea capaz de crackear las contraseñas de los usuarios. Para ello vamos a aplicar un algoritmo de fuerza bruta basado en un diccionario.

Como siempre, vamos a empezar creando un directorio para contener los ficheros de ejercicio.

$> mkdir ~/integra/pcrack
$> cd ~/integra/pcrack

A continuación vamos a crear el diccionario, que va a consistir en un fichero con una palabra en cada línea. Escribe las palabras que quieras, pero haz que alguna de ellas sea "0abcdef" (sin comillas).

$> cat > dict-$USER

Una vez que hayas creado el diccionario, vamos a crear el fichero shadow.

$> cat > shadow
hasan:$1$/Uesk54D$JDsAQMucfPz45gjYcIgW00:14285:0:99999:7:::

El fichero shadow contiene las contraseñas encriptadas en el formato habitual de los sistemas Unix.

A continuación vamos a crear el programa que se va a encargar de desencriptar las contraseñas utilizando fuerza bruta.

$> cat > pcrack.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import crypt, string, time, sys, codecs

if len(sys.argv) != 3:  
	sys.exit("Usage: crypto <shadow> <dict>")

# Leer palabras del diccionario
dict_words = []
dict_file = open(sys.argv[2])
for line in dict_file.readlines():
	dict_words.append(line.strip())
dict_file.close()

# Leer fichero de contraseñas
passwords = {}
pw_file = open(sys.argv[1])
for line in pw_file.readlines():
	pw_fields = string.splitfields(line, ':')
	if pw_fields[1] != "*" and pw_fields[1] != "!":
		passwords[pw_fields[0]] = pw_fields[1]
pw_file.close()

start_time = time.time() 

# Buscar
for word in dict_words:
	for user, password in passwords.iteritems():
		salt = password[:14]
		if crypt.crypt(word, salt) == password:
			print user, " = ", word

elapsed_sec = time.time() - start_time
crypt_calls = len(passwords)*len(dict_words)
print crypt_calls,"words in", elapsed_sec, "sec, speed:", crypt_calls/elapsed_sec, "words/sec"

El funcionamiento del programa anterior es bastante claro. Recibe como argumentos el nombre del fichero shadow y el nombre del fichero con el diccionario. Lee el shadow y el diccionario, y a continuación, encripta cada palabra del diccionario. Si el resultado de la encriptación de una palabra coincide con alguna de las que hay en el shadow significada que ha tenido éxito, imprimiendo la palabra utilizada como contraseña junto con el nombre del usuario. Además, al terminar imprime el tiempo que tardó y el número medio de contraseñas encriptadas por segundo.

Prueba el programa para verificar que funciona correctamente. Acuérdate de darle permisos de ejecución previamente.

$> chmod +x pcrack.py
$> ./pcrack.py shadow dict-$USER

...

Una vez que hemos comprobado que funciona, vamos a descargar un diccionario real y un fichero shadow mayor.

Antes debemos borrar el fichero shadow que hemos creado de ejemplo.

$> rm shadow
$> wget http://www.atc.uniovi.es/doctorado/6grid/data/dict.txt
--2009-02-10 09:19:19--  http://www.atc.uniovi.es/doctorado/6grid/data/dict.txt
Resolving proxy.uniovi.es... 156.35.14.6
Connecting to proxy.uniovi.es|156.35.14.6|:8888... connected.
Proxy request sent, awaiting response... 200 OK
Length: 745249 (728K) [text/plain]
Saving to: `dict.txt'

100%[===========================================>] 745,249     --.-K/s   in 0.1s

2009-02-10 09:19:20 (4.87 MB/s) - `dict.txt' saved [745249/745249]

$> wget http://www.atc.uniovi.es/doctorado/6grid/data/shadow
--2009-02-28 13:00:41--  http://www.atc.uniovi.es/doctorado/6grid/data/shadow
Resolving proxy.uniovi.es... 156.35.14.6
Connecting to proxy.uniovi.es|156.35.14.6|:8888... connected.
Proxy request sent, awaiting response... 200 OK
Length: 468 [text/plain]
Saving to: `shadow'

100%[============================================================>] 468         --.-K/s   in 0s

2009-02-28 13:00:41 (40,3 MB/s) - `shadow' saved [468/468]

Establecemos la variable de entorno $HOST para que contenga el nombre de la máquina sobre la que vamos a trabajar.

$> export HOST=tecgrid01.epv.uniovi.es
$> echo $HOST
tecgrid01.epv.uniovi.es

Copiamos el diccionario a tecgrid01.epv.uniovi.es.

$> globus-job-run $HOST /bin/mkdir /tmp/$USER
$> globus-url-copy file:///$PWD/dict.txt gsiftp://$HOST/tmp/$USER/

Realizamos una petición al servidor de RLS para que establezca un mapeo entre el fichero que acabamos de transferir y un nombre lógico denominado dict-$USER.

$> globus-rls-cli create dict-$USER gsiftp://$HOST/tmp/$USER/dict.txt rls://$HOST

Comprobamos que el servidor de RLS ha registrado el nombre lógico, tanto en el LRC como en el RLI.

$> globus-rls-cli query lrc lfn dict-$USER rls://$HOST
  dict-ruf: gsiftp://tecgrid01.epv.uniovi.es/tmp/ruf/dict.txt
$> globus-rls-cli query rli lfn dict-$USER rls://$HOST
  dict-ruf: rls://tecgrid01.epv.uniovi.es:39281

A continuación vamos a crear otro programa denominado wrapper_pcrack. Este programa será el encargado de configurar el entorno de ejecución antes de ejecutar el programa pcrack.py. En concreto, establecerá las variables de entorno y transferirá el diccionario a la máquina donde se ejecute el programa.

$> cat > wrapper_pcrack
#!/bin/sh

echo "Execution on `hostname`"

# Se establecen las variables de entorno
source /opt/vdt/setup.sh

# Se transfiere el diccionario a partir del nombre lógico
./getlfn.py dict-_USER_ rls://_HOST_

# Se ejecuta el programa
./pcrack.py shadow dict-_USER_

Sustituímos _USER_ y _HOST_.

$> sed -i "s/_USER_/$USER/" wrapper_pcrack
$> sed -i "s/_HOST_/$HOST/" wrapper_pcrack
$> cat wrapper_pcrack
#!/bin/sh

echo "Execution on `hostname`"

# Se establecen las variables de entorno
source /opt/vdt/setup.sh

# Se transfiere el diccionario a partir del nombre lógico
./getlfn.py dict-ruf rls://tecgrid01.epv.uniovi.es

# Se ejecuta el programa
./pcrack.py shadow dict-ruf

Le debemos dar permisos de ejecución.

$> chmod +x wrapper_pcrack

Debemos copiar al directorio actual el programa getlfn.py.

$> cp ~/datagrid/rls/getlfn.py .

El siguiente paso va a consistir en crear el fichero de descripción del trabajo. Para enviar el trabajo vamos a utilizar Condor-G, por tanto, el formato del fichero de descripción será el que utiliza Condor.

$> cat > pcrack.sub
Universe      = grid

grid_resource = gt4 $$(gatekeeper_url) $$(job_manager_type)
requirements = (TARGET.gatekeeper_url =!= UNDEFINED) && \
               (TARGET.job_manager_type =!= UNDEFINED)

Executable    = wrapper_pcrack
output        = pcrack.out
error         = pcrack.error
log           = pcrack.log
should_transfer_files   = YES
when_to_transfer_output = ON_EXIT
transfer_input_files    = getlfn.py,pcrack.py,shadow
Queue

Utilizamos el universo grid y como recurso grid gt4 (Globus GRAM versión 4). Además, indicamos que queremos utilizar cualquier elemento de computación que esté disponible. Estamos utilizando Condor-G para enviar el trabajo a una máquina Globus, y esta a su vez se lo va a enviar a un gestor de trabajos (en este caso coincide que es Condor). Cuando el trabajo se ejecute accederá al fichero de datos que se encuentra distribuido por nuestro grid.

Ya sólo nos queda la parte fácil, enviar el trabajo y esperar por los resultados.

$> condor_submit pcrack.sub
Submitting job(s).
Logging submit event(s).
1 job(s) submitted to cluster 170.

Observamos la evolución de la ejecución del trabajo.

$> condor_q


-- Submitter: tecgrid03.epv.uniovi.es : <192.168.100.200:55623> : tecgrid03.epv.uniovi.es
 ID      OWNER            SUBMITTED     RUN_TIME ST PRI SIZE CMD
 170.0   ruf             2/10 09:38   0+00:00:00 I  0   0.0  pcrack_wrapper

1 jobs; 1 idle, 0 running, 0 held
$> condor_q


-- Submitter: tecgrid03.epv.uniovi.es : <192.168.100.200:55623> : tecgrid03.epv.uniovi.es
 ID      OWNER            SUBMITTED     RUN_TIME ST PRI SIZE CMD
 170.0   ruf             2/10 09:38   0+00:00:00 I  0   0.0  pcrack_wrapper
 171.0   ruf             2/10 09:38   0+00:00:01 R  0   0.0  gridftp_wrapper.sh

2 jobs; 1 idle, 1 running, 0 held

Nuevamente aparece un nuevo trabajo denominado gridftp_wrapper.sh. Este trabajo ha sido creado por Condor para realizar la transferencia de los ficheros utilizando GridFTP.

Nota

Mientras esperas a que el trabajo termine, revisa los ejercicios que hemos estado haciendo y aprovecha para preguntar las dudas que te hayan surgido si no lo habías hecho antes. Puedes aprovechar para examinar más detalladamente los programas en python y el script que los arranca.

Comprueba el log del trabajo.

$> cat pcrack.log
000 (098.000.000) 02/28 13:04:11 Job submitted from host: <156.35.171.92:44536>
...
017 (098.000.000) 02/28 13:04:40 Job submitted to Globus
    RM-Contact: tecgrid01.epv.uniovi.es:9443
    JM-Contact: https://156.35.171.90:9443/wsrf/services/ManagedExecutableJobService?e4659ba0-058f-11de-811a-a0c92eacbd7e
    Can-Restart-JM: 0
...
027 (098.000.000) 02/28 13:04:40 Job submitted to grid resource
    GridResource: gt4 tecgrid01.epv.uniovi.es:9443 Condor
    GridJobId: gt4 https://156.35.171.90:9443/wsrf/services/ManagedExecutableJobService?e4659ba0-058f-11de-811a-a0c92eacbd7e
...
001 (098.000.000) 02/28 13:04:44 Job executing on host: gt4 tecgrid01.epv.uniovi.es:9443 Condor
...
005 (098.000.000) 02/28 13:05:42 Job terminated.
        (1) Normal termination (return value 0)
                Usr 0 00:00:00, Sys 0 00:00:00  -  Run Remote Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Run Local Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Total Remote Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Total Local Usage
        0  -  Run Bytes Sent By Job
        0  -  Run Bytes Received By Job
        0  -  Total Bytes Sent By Job
        0  -  Total Bytes Received By Job
...

Comprueba los resultados del trabajo, con un poco de suerte incluso es posible que hayas encontrado alguna contraseña.

$> cat pcrack.out

...

Nota

Imagínate tener a nuestra disposición cientos de máquinas. Con el programa anterior sería sencillo utilizar múltiples diccionarios para enviar muchos trabajos a un grid. Todo esto da una idea de lo importante que es utilizar una contraseña segura.

Antes de terminar acuértate de borrar los ficheros que has subido a tecgrid01.epv.uniovi.es.

$> globus-job-run $HOST /bin/rm -r /tmp/$USER

Nota

Si te queda tiempo busca por internet diccionarios adicionales. Transfiérelos al grid y regístralos en el RLS. A continuación parametriza el fichero de descripción de trabajo para enviar múltiples trabajos que utilicen los diccionarios disponibles (deberás utilizar el atributo arguments de forma similar a como vimos en los ejercicios de Condor).