El libro "Bash y ciberseguridad: ataque, defensa y análisis desde la línea de comando de Linux"

imagenHola habrozhiteli! La línea de comando puede ser una herramienta ideal para la ciberseguridad. La increíble flexibilidad y la disponibilidad absoluta convierten la interfaz de línea de comando estándar (CLI) en una solución fundamental si tiene la experiencia adecuada.

Los autores Paul Tronkon y Karl Albing hablan sobre herramientas y trucos de la línea de comando que ayudan a recopilar datos con protección proactiva, analizar registros y monitorear el estado de la red. Los Pentesters aprenderán cómo realizar ataques utilizando una funcionalidad colosal integrada en casi cualquier versión de Linux.


¿Para quién es este libro?


El libro "Bash y ciberseguridad" está destinado a aquellos que desean aprender a trabajar con la línea de comandos en el contexto de la seguridad informática. Nuestro objetivo no es reemplazar las herramientas existentes con scripts de línea de comandos, sino más bien enseñarle cómo usar efectivamente la línea de comandos para mejorar la funcionalidad existente.

A lo largo del libro, proporcionamos ejemplos de métodos de seguridad como la recopilación de datos, análisis y pruebas de penetración. El propósito de estos ejemplos es demostrar las capacidades de la línea de comandos y presentarle algunos de los métodos fundamentales utilizados en las herramientas de nivel superior.

Este libro no es una introducción a la programación, aunque algunos conceptos generales están cubiertos en la Parte I.

Monitoreo de registros en tiempo real


La capacidad de analizar una revista después de un evento es una habilidad importante. Pero es igualmente importante poder extraer información del archivo de registro en tiempo real para detectar acciones maliciosas o sospechosas en el momento en que ocurren. En este capítulo, consideraremos métodos para leer entradas de diario a medida que se crean y formatean para mostrar análisis y generar alertas basadas en indicadores de amenazas conocidos para la operación de un sistema o red (indicadores de compromiso).

Monitoreo de registro de texto


La forma más fácil de monitorear el registro en tiempo real es usar el comando tail con el parámetro –f: lee continuamente el archivo y lo muestra en stdout a medida que se agregan nuevas líneas. Como en los capítulos anteriores, para ejemplos usaremos el registro de acceso al servidor web Apache, pero los métodos descritos son relevantes para cualquier registro de texto. Para rastrear el registro de acceso de Apache usando el comando tail, ingrese lo siguiente:

tail -f /var/logs/apache2/access.log

La salida del comando tail se puede pasar al comando grep, por lo que solo se mostrarán los registros que coincidan con ciertos criterios. El siguiente ejemplo rastrea el registro de acceso de Apache y muestra las entradas correspondientes a una dirección IP específica:

tail -f /var/logs/apache2/access.log | grep '10.0.0.152'

También puedes usar expresiones regulares. En este ejemplo, solo se mostrarán los registros que devuelvan el código de estado HTTP 404 "Página no encontrada"; La opción -i se agrega para ignorar el caso de los caracteres:

tail -f /var/logs/apache2/access.log | egrep -i 'HTTP/.*" 404'

para borrar la información extraña, la salida se debe pasar al comando de corte. Este ejemplo monitorea el registro de acceso para consultas que conducen al código de estado 404, y luego usa el método de corte para mostrar solo la fecha / hora y la página solicitada: Luego, para eliminar los corchetes y las comillas dobles, puede dirigir la salida a tr -d ' [] "'.

$ tail -f access.log | egrep --line-buffered 'HTTP/.*" 404' | cut -d' ' -f4-7
[29/Jul/2018:13:10:05 -0400] "GET /test
[29/Jul/2018:13:16:17 -0400] "GET /test.txt
[29/Jul/2018:13:17:37 -0400] "GET /favicon.ico




Nota: aquí se usa la opción --line-buffering del comando egrep. Esto obliga a egrep a imprimir en stdout cada vez que se produce un salto de línea. Sin este parámetro, se producirá el almacenamiento en búfer y la salida no se enviará al comando de corte hasta que el búfer esté lleno. No queremos esperar tanto. Esta opción permite que el comando egrep escriba cada línea a medida que se encuentra.

BUFFERS DE LINEA DE MANDO

¿Qué sucede durante el buffering? Imagine egrep encuentra muchas cadenas que coinciden con el patrón especificado. En este caso, egrep tendrá mucha salida. Pero la salida (de hecho, cualquier entrada o salida) es mucho más costosa (lleva más tiempo) que el procesamiento de datos (búsqueda de texto). Por lo tanto, cuantas menos llamadas de E / S, más eficiente será el programa.

grep , , . . grep . , grep 50 . , 50 , , . 50 !

egrep, , . egrep , , . , , , , . , .

, , tail -f ( ), . , « », . . .

, egrep , . , .


Puede usar los comandos tail y egrep para monitorear el registro y mostrar cualquier entrada que corresponda a patrones conocidos de actividad sospechosa o maliciosa, a menudo denominada IOC. Puede crear un sistema simple de detección de intrusos (IDS). Primero, cree un archivo que contenga los patrones de expresión regular para el COI, como se muestra en el Ejemplo 8.1.

Ejemplo 8.1 ioc.txt (1) Esta plantilla (../) es un indicador de un ataque de directorio indirecto: un atacante intenta salir del directorio de trabajo actual y acceder a archivos que no son accesibles para él. (2) Los archivos Linux etc / passwd y etc / shadow se utilizan para la autenticación del sistema y nunca se debe acceder a ellos a través de un servidor web. (3)

\.\./ (1)
etc/passwd (2)
etc/shadow
cmd\.exe (3)
/bin/sh
/bin/bash





Servir los archivos cmd.exe, / bin / sh o / bin / bash es una indicación de la conexión inversa devuelta por el servidor web. Una conexión inversa a menudo indica un intento de operación exitoso.

Tenga en cuenta que los IOC deben estar en formato regex, ya que serán utilizados más adelante por el comando egrep.

El archivo ioc.txt se puede usar con la opción egrep -f. Este parámetro le dice a egrep que busque los patrones de expresión regular del archivo especificado. Esto le permite usar el comando tail para monitorear el archivo de registro, y a medida que se agrega cada registro, la línea de lectura se comparará con todas las plantillas en el archivo IOC, mostrando cualquier registro correspondiente. Aquí hay un ejemplo:

tail -f /var/logs/apache2/access.log | egrep -i -f ioc.txt

Además, el comando tee se puede usar para mostrar simultáneamente advertencias en la pantalla y guardarlas para su posterior procesamiento en su propio archivo: Una vez más, la opción --line-buffer es necesaria para garantizar que no haya problemas causados ​​al almacenar el resultado del comando.

tail -f /var/logs/apache2/access.log | egrep --line-buffered -i -f ioc.txt |
tee -a interesting.txt




Monitoreo de registro de Windows


Como ya se mencionó, debe usar el comando wevtutil para acceder a los eventos de Windows. Aunque este comando es universal, no tiene una funcionalidad como tail, que puede usarse para recuperar nuevos registros entrantes. Pero hay una salida: use un script bash simple que pueda proporcionar la misma funcionalidad (Ejemplo 8.2).

Ejemplo 8.2. wintail.sh

#!/bin/bash -
#
# Bash  
# wintail.sh
#
# :
#    tail   Windows
#
# : ./wintail.sh
#

WINLOG="Application" (1)

LASTLOG=$(wevtutil qe "$WINLOG" //c:1 //rd:true //f:text) (2)

while true
do
      CURRENTLOG=$(wevtutil qe "$WINLOG" //c:1 //rd:true //f:text) (3)
      if [[ "$CURRENTLOG" != "$LASTLOG" ]]
      then
            echo "$CURRENTLOG"
            echo "----------------------------------"
            LASTLOG="$CURRENTLOG"
      fi
done

(1) Esta variable define el registro de Windows que desea rastrear. Para obtener una lista de los registros actualmente disponibles en el sistema, puede usar el comando wevtutil el.

(2) Aquí, wevtutil se ejecuta para solicitar el archivo de registro especificado. El parámetro c: 1 devuelve solo una entrada de registro. El parámetro rd: true permite que el comando lea la entrada de registro más reciente. Finalmente, f: text devuelve el resultado en texto plano, no en formato XML, lo que facilita la lectura del resultado desde la pantalla.

(3)Las siguientes líneas ejecutan nuevamente el comando wevtutil y la entrada de registro recién recibida se compara con la última impresa en la pantalla. Si difieren entre sí, esto significa que ha habido cambios en el registro. En este caso, se muestra una nueva entrada. Si los registros que se comparan son los mismos, no sucede nada y el comando wevtutil retrocede y comienza a buscar y comparar nuevamente.

Creación de histogramas en tiempo real.


El comando tail -f proporciona el flujo de datos actual. Pero, ¿qué sucede si desea contar la cantidad de líneas que se agregaron al archivo durante un cierto período de tiempo? Puede observar este flujo de datos, iniciar un temporizador y realizar el conteo durante un período de tiempo específico; entonces se debe detener el conteo y reportar los resultados.

Este trabajo se puede dividir en dos procesos de script: un script leerá las líneas y el otro mirará la hora. El temporizador notifica al contador de línea utilizando un mecanismo de comunicación entre procesos POSIX estándar llamado señal. Una señal es una interrupción de software, y hay varios tipos de señales. Algunos de ellos son fatales: conducen al final del proceso (por ejemplo, una excepción en una operación de coma flotante). La mayoría de estas señales pueden ignorarse o capturarse. Se toman medidas cuando se detecta una señal. Muchas de estas señales tienen un propósito predefinido en el sistema operativo. Utilizaremos una de las dos señales disponibles para los usuarios. Esta es la señal SIGUSR1 (la otra es SIGUSR2).

Los scripts de shell pueden detectar interrupciones utilizando el comando trap incorporado. Con su ayuda, puede seleccionar un comando que determina qué acción desea realizar cuando se recibe una señal, y una lista de señales que activan una llamada a este comando. Por ejemplo:

trap warnmsg SIGINT

Esto hace que se llame al comando warnmsg (nuestro propio script o función) cada vez que el script de shell recibe una señal SIGINT, por ejemplo, cuando presiona Ctrl + C para interrumpir un proceso en ejecución.

El ejemplo 8.3 muestra un script que realiza un recuento.

Ejemplo 8.3 looper.sh

#!/bin/bash -
#
# Bash  
# looper.sh
#
# :
#    
#
# : ./looper.sh [filename]
# filename —  ,   ,
#  : log.file
#

function interval ()                                           (1)
{
      echo $(date '+%y%m%d %H%M%S') $cnt                       (2)
      cnt=0
}

declare -i cnt=0
trap interval SIGUSR1                                          (3)

shopt -s lastpipe                                              (4)

tail -f --pid=$$ ${1:-log.file} | while read aline             (5)
do
     let cnt++
done

(1) Se llamará a la función de intervalo al recibir cada señal. Por supuesto, el intervalo debe definirse antes de que podamos nombrarlo y usar trap en nuestra expresión.

(2) Se invoca el comando de fecha para proporcionar una marca de tiempo para el valor de la variable cnt que estamos imprimiendo. Una vez que se muestra el contador, restablecemos este valor a 0 para comenzar la cuenta regresiva del siguiente intervalo.

(3) Ahora que el intervalo está definido, podemos indicar que se llama a la función cada vez que nuestro proceso recibe la señal SIGUSR1.

(4)Este es un paso muy importante. Por lo general, cuando hay una tubería de comandos (por ejemplo, ls-l | grep rwx | wc), partes de la tubería (cada comando) se ejecutan en subredes y cada proceso finaliza con su propio identificador de proceso. Esto podría ser un problema para este escenario, porque el bucle while estará en una subshell con un identificador de proceso diferente. Independientemente del proceso que se inicie, el script looper.sh no conocerá el identificador del proceso del bucle while para enviarle una señal. Además, cambiar el valor de la variable cnt en el subshell no cambia el valor cnt en el proceso principal, por lo que la señal para el proceso principal establecerá cada vez el valor en 0. Puede resolver este problema con el comando shopt, que establece el parámetro (-s) en lastpipe. Le dice al shell que no cree un subshell para el último comando en la tubería,y ejecuta este comando en el mismo proceso que el script mismo. En nuestro caso, esto significa que el comando tail se ejecutará en una subshell (es decir, en otro proceso), y el ciclo while pasará a formar parte del proceso del script principal. Nota: esta opción de shell solo está disponible en la versión bash 4.xy superior y solo para shells no interactivos (es decir, scripts).

(5) Este es el comando tail -f con otro parámetro --pid. Indicamos el identificador del proceso, que, al finalizar este proceso, terminará el comando de cola. Especificamos el ID de proceso del script de shell actual $$ para ser visto. Esta acción le permite limpiar procesos y no dejar el comando de cola ejecutado en segundo plano (si, por ejemplo, este script se ejecuta en segundo plano; Ejemplo 8.4).

El script tailcount.sh comienza y detiene el script con un cronómetro (temporizador) y cuenta los intervalos de tiempo.

Ejemplo 8.4. tailcount.sh

#!/bin/bash -
#
# Bash  
# tailcount.sh
#
# :
#    n 
#
# : ./tailcount.sh [filename]
#     filename:  looper.sh
#

#  —    
function cleanup ()
{
      [[ -n $LOPID ]] && kill $LOPID          (1)
}

trap cleanup EXIT                             (2)
bash looper.sh $1 &                           (3)
LOPID=$!                                      (4)
#   
sleep 3

while true
do
      kill -SIGUSR1 $LOPID
      sleep 5
done >&2                                      (5)

(1) Dado que este script ejecutará otros scripts, debería limpiarse después del trabajo. Si el identificador de proceso se almacenó en LOPID, la variable almacenará el valor, por lo tanto, la función enviará una señal a este proceso utilizando el comando kill. Si no especifica una señal específica en el comando kill, la señal SIGTERM se enviará por defecto.

(2) El comando EXIT no es una señal. Este es un caso especial cuando la instrucción trap le dice al shell que llame a esta función (en este caso, limpieza) si el shell que ejecuta este script está a punto de cerrarse.

(3)Ahora comienza el verdadero trabajo. Se inicia el script looper.sh, que se ejecutará en segundo plano: para que este script funcione durante todo el ciclo (sin esperar a que el comando complete el trabajo), se desconecta del teclado.

(4) Aquí, se almacena el identificador del proceso de script que acabamos de comenzar en segundo plano.

(5) Esta redirección es simplemente una precaución. Todos los resultados que provienen de un ciclo while o de las instrucciones kill / sleep (aunque no los esperamos) no deben mezclarse con ningún resultado de la función looper.sh, que, aunque se ejecuta en segundo plano, todavía los envía a stdout. Por lo tanto, redirigimos los datos de stdout a stderr.

Para resumir, vemos que aunque la función looper.sh se colocó en segundo plano, su identificador de proceso se almacena en una variable de shell. Cada cinco segundos, el script tailcount.sh envía una señal SIGUSR1 a este proceso (que se ejecuta en la función looper.sh), que, a su vez, llama al script looper.sh para imprimir el número actual de líneas fijadas en él y reiniciar el conteo. Después de salir, el script tailcount.sh se borrará enviando una señal SIGTERM a la función looper.sh para interrumpirlo.

Con la ayuda de dos guiones, un guión que realiza el recuento de líneas y un guión con un cronómetro (temporizador) que controla el primer guión, puede obtener la salida (el número de líneas para un período determinado), en función del cual el próximo guión creará un histograma. Se llama así:

bash tailcount.sh | bash livebar.sh

El script livebar.sh lee datos de stdin e imprime el resultado en stdout, una línea para cada línea de entrada (Ejemplo 8.5).

Ejemplo 8.5 livebar.sh

#!/bin/bash -
#
# Bash  
# livebar.sh
#
# :
#    «» 
#
# :
# <output from other script or program> | bash livebar.sh
#

function pr_bar ()                                         (1)
{
      local raw maxraw scaled
      raw=$1
      maxraw=$2
      ((scaled=(maxbar*raw)/maxraw))
      ((scaled == 0)) && scaled=1 #   
      for((i=0; i<scaled; i++)) ; do printf '#' ; done
      printf '\n'

} # pr_bar

maxbar=60     #         (2)
MAX=60
while read dayst timst qty
do
      if (( qty > MAX ))                                   (3)
      then
           let MAX=$qty+$qty/4    #   
           echo "                      **** rescaling: MAX=$MAX"
      fi
      printf '%6.6s %6.6s %4d:' $dayst $timst $qty         (4)
      pr_bar $qty $MAX
done

(1) La función pr_bar muestra una cadena de hashtags que se escalan según los parámetros proporcionados al tamaño máximo. Esta característica puede parecer familiar, ya que la usamos anteriormente en el script histogram.sh.

(2) Este es el tamaño de línea de hashtag más largo que podemos permitir (sin envolver la línea).

(3)¿Qué tan grandes serán los valores que se mostrarán? Sin saber esto de antemano (aunque estos datos se pueden proporcionar al script como argumento), el script realizará el seguimiento del máximo. Si se excede este máximo, el valor comenzará a "escalar" y las líneas que ahora se muestran, y las líneas futuras también se escalarán a un nuevo máximo. El script agrega un 25% al ​​valor máximo, por lo que no tiene que escalar el valor si el siguiente valor nuevo cada vez aumenta solo un 1-2%.

(4)printf define el ancho mínimo y máximo de los dos primeros campos que se imprimirán. Estas son marcas de fecha y hora que se truncarán si se exceden los valores de ancho. Para mostrar el valor completo, especifique su ancho de cuatro caracteres. En este caso, a pesar de las restricciones, se imprimirán todos los valores. Si el número de caracteres en los valores es inferior a cuatro, los que faltan se completarán con espacios.

Dado que este script se lee desde stdin, puede ejecutarlo usted mismo para ver cómo se comporta. Aquí hay un ejemplo:

$ bash  livebar.sh
201010 1020 20
201010     1020 20:####################
201010 1020 70
                       **** rescaling: MAX=87
201010     1020 70:################################################
201010 1020 75
201010 1020 75:###################################################
^C

En este ejemplo, la entrada se mezcla con la salida. También puede poner la entrada en un archivo y redirigirlo a un script para ver solo la salida:

$ bash livebar.sh < testdata.txt
bash livebar.sh < x.data
201010 1020 20:####################
                 **** rescaling: MAX=87
201010 1020 70:################################################
201010 1020 75:###################################################
$

»Se puede encontrar más información sobre el libro en el sitio web del editor
» Contenido
» Extracto de

Khabrozhiteley 25% de descuento en el cupón - Bash

Tras el pago de la versión en papel del libro, se envía un libro electrónico por correo electrónico.

All Articles