Skip to content

3. Control de secuencias de comandos

Entrada y Salida

Control de entrada

Este paso es muy importante ya que permite hacer que el script espere nuestras instrucciones, eso lo podemos lograr con read, veamos un ejemplo

Code: bash
# Available options
<SNIP>
echo -e "Additional options available:"
echo -e "\t1) Identify the corresponding network range of target domain."
echo -e "\t2) Ping discovered hosts."
echo -e "\t3) All checks."
echo -e "\t*) Exit.\n"

read -p "Select your option: " opt

case $opt in
    "1") network_range ;;
    "2") ping_host ;;
    "3") network_range && ping_host ;;
    "*") exit 0 ;;
esac

el parámetro -p que acompaña a read sirve para indicarle al script que la entrada permanezca en la misma Linea

Control de salida

Ya hemos aprendido sobre las redirecciones de salida de la salida en el módulo Fundamentos de Linux. Sin embargo, el problema con las redirecciones es que no obtenemos ninguna salida del comando respectivo. Se redirigirá al archivo correspondiente. Si nuestros scripts se vuelven más complicados más adelante, pueden tardar mucho más tiempo que unos pocos segundos. Para evitar quedarnos inactivos y esperar los resultados de nuestro script, podemos usar la utilidad [[https://man7.org/linux/man-pages/man1/tee.1.html | tee]]. Esta garantiza que veamos los resultados que obtenemos inmediatamente y que se almacenen en los archivos correspondientes. En nuestro script CIDR.sh, hemos usado esta utilidad dos veces de diferentes maneras.

Code: bash
<SNIP>

# Identify Network range for the specified IP address(es)
function network_range {
    for ip in $ipaddr
    do
        netrange=$(whois $ip | grep "NetRange\|CIDR" | tee -a CIDR.txt)
        cidr=$(whois $ip | grep "CIDR" | awk '{print $2}')
        cidr_ips=$(prips $cidr)
        echo -e "\nNetRange for $ip:"
        echo -e "$netrange"
    done
}

<SNIP>

# Identify IP address of the specified domain
hosts=$(host $domain | grep "has address" | cut -d" " -f4 | tee discovered_hosts.txt)

<SNIP>

Al utilizar tee, transferimos la salida recibida y utilizamos la barra vertical (|) para reenviarla a tee. El parámetro "-a / --append" garantiza que el archivo especificado no se sobrescriba, sino que se complete con los nuevos resultados. Al mismo tiempo, nos muestra los resultados y cómo se encontrarán en el archivo.

Input and Output
1i8n@htb[/htb]$ cat discovered_hosts.txt CIDR.txt

165.22.119.202
NetRange:       165.22.0.0 - 165.22.255.255
CIDR:           165.22.0.0/16

Control de flujo - Bucles

El control del flujo de nuestros scripts es esencial. Ya hemos aprendido sobre las condiciones if-else, que también forman parte del control de flujo. Después de todo, queremos que nuestro script funcione de manera rápida y eficiente, y para ello, podemos utilizar otros componentes para aumentar la eficiencia y permitir un procesamiento sin errores. Cada estructura de control es una rama o un bucle. Las expresiones lógicas de valores booleanos generalmente controlan la ejecución de una estructura de control. Estas estructuras de control incluyen: - Branches: - If-Else Conditions - Case Statements - Loops: - For Loops - While Loops - Until Loops

Bucles For

Iterando listas

Code: bash
for variable in 1 2 3 4
do
    echo $variable
done

iterando archivos

Code: bash
for variable in file1 file2 file3
do
    echo $variable
done

Iterando IPv4

Code: bash
for ip in "10.10.10.170 10.10.10.174 10.10.10.175"
do
    ping -c 1 $ip
done

Tambien podemos escribirlo com un comando de una sola Linea, es decir directamente el la terminal

Flow Control - Loops
1i8n@htb[/htb]$ for ip in 10.10.10.170 10.10.10.174;do ping -c 1 $ip;done

PING 10.10.10.170 (10.10.10.170): 56 data bytes
64 bytes from 10.10.10.170: icmp_seq=0 ttl=63 time=42.106 ms

--- 10.10.10.170 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 42.106/42.106/42.106/0.000 ms
PING 10.10.10.174 (10.10.10.174): 56 data bytes
64 bytes from 10.10.10.174: icmp_seq=0 ttl=63 time=45.700 ms

--- 10.10.10.174 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 45.700/45.700/45.700/0.000 ms

Ejemplo

Code: bash
<SNIP>

# Identify Network range for the specified IP address(es)
function network_range {
    for ip in $ipaddr
    do
        netrange=$(whois $ip | grep "NetRange\|CIDR" | tee -a CIDR.txt)
        cidr=$(whois $ip | grep "CIDR" | awk '{print $2}')
        cidr_ips=$(prips $cidr)
        echo -e "\nNetRange for $ip:"
        echo -e "$netrange"
    done
}

<SNIP>

Bucles While

El bucle while es conceptualmente simple y sigue el siguiente principio: - Una declaración se ejecuta siempre que se cumpla una condición (sea verdadera).

Code: bash
<SNIP>
        stat=1
        while [ $stat -eq 1 ]
        do
            ping -c 2 $host > /dev/null 2>&1
            if [ $? -eq 0 ]
            then
                echo "$host is up."
                ((stat--))
                ((hosts_up++))
                ((hosts_total++))
            else
                echo "$host is down."
                ((stat--))
                ((hosts_total++))
            fi
        done
<SNIP>

Trabajando con contadores

Code: bash
#!/bin/bash

counter=0

while [ $counter -lt 10 ]
do
  # Increase $counter by 1
  ((counter++))
  echo "Counter: $counter"

  if [ $counter == 2 ]
  then
    continue
  elif [ $counter == 4 ]
  then
    break
  fi
done

Until Loops

También existe el bucle Until, que es relativamente poco común. Sin embargo, el bucle Until funciona exactamente como el bucle While, pero con la diferencia: - El código dentro de un bucle hasta se ejecuta siempre que la condición particular sea falsa.

Code: bash
#!/bin/bash

counter=0

until [ $counter -eq 10 ]
do
  # Increase $counter by 1
  ((counter++))
  echo "Counter: $counter"
done
Flow Control - Loops
1i8n@htb[/htb]$ ./Until.sh

Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
Counter: 6
Counter: 7
Counter: 8
Counter: 9
Counter: 10

Ejercicio de practica

#!/bin/bash

# Decrypt function
function decrypt {
    MzSaas7k=$(echo $hash | sed 's/988sn1/83unasa/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/4d298d/9999/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/3i8dqos82/873h4d/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/4n9Ls/20X/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/912oijs01/i7gg/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/k32jx0aa/n391s/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/nI72n/YzF1/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/82ns71n/2d49/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/JGcms1a/zIm12/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/MS9/4SIs/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/Ymxj00Ims/Uso18/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/sSi8Lm/Mit/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/9su2n/43n92ka/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/ggf3iunds/dn3i8/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/uBz/TT0K/g')

    flag=$(echo $MzSaas7k | base64 -d | openssl enc -aes-128-cbc -a -d -salt -pass pass:$salt)
}

# Variables
var="9M"
salt=""
hash="VTJGc2RHVmtYMTl2ZnYyNTdUeERVRnBtQWVGNmFWWVUySG1wTXNmRi9rQT0K"

# Base64 Encoding Example:
#        $ echo "Some Text" | base64

# <- For-Loop here

# Check if $salt is empty
if [[ ! -z "$salt" ]]
then
    decrypt
    echo $flag
else
    exit 1
fi
# Crea un bucle "For" que codifique la variable "var" 28 veces en "base64". La cantidad de caracteres del hash número 28 es el valor que se debe asignar a la variable "salt".

Solución

#!/bin/bash

# Decrypt function
function decrypt {
    MzSaas7k=$(echo $hash | sed 's/988sn1/83unasa/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/4d298d/9999/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/3i8dqos82/873h4d/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/4n9Ls/20X/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/912oijs01/i7gg/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/k32jx0aa/n391s/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/nI72n/YzF1/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/82ns71n/2d49/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/JGcms1a/zIm12/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/MS9/4SIs/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/Ymxj00Ims/Uso18/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/sSi8Lm/Mit/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/9su2n/43n92ka/g')
    Mzns7293sk=$(echo $MzSaas7k | sed 's/ggf3iunds/dn3i8/g')
    MzSaas7k=$(echo $Mzns7293sk | sed 's/uBz/TT0K/g')

    flag=$(echo -n "$MzSaas7k" | base64 -d | openssl enc -aes-128-cbc -d -a -A -k $salt)
}

# Variables
var="9M"
salt=""
hash="VTJGc2RHVmtYMTl2ZnYyNTdUeERVRnBtQWVGNmFWWVUySG1wTXNmRi9rQT0K"

# Base64 encoding 28 times
for i in {1..28}
do
    var=$(echo "$var" | base64)
done

# Assign the length of the 28th encoded string to salt
# add +1 to the length of the string to account for the null terminator
salt=$((${#var} + 1))

# Check if $salt is empty
if [[ ! -z "$salt" ]]
then
    decrypt
    echo "$flag"
else
    exit 1
fi

output

*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
HTBL00p5r0x