Bash port scanner

Stavo facendo qualche esperimento con la shell, e leggendo un pò a caso in rete, ho provato a realizzare un semplice port scanner in bash scripting. Molti degli elementi su Linux funzionano come dei file, ovvero è possibile accedere in lettura per ottenere informazioni e in scrittura per aggiornare il loro stato. Un esempio è il file /dev/tcp/host/port, in particolare scrivendo su questo file speciale viene aperta una connessione TCP verso host:port. Se la scrittura su file ha successo allora la porta viene aperta, altrimenti la porta è chiusa. That's the trick !

for port in {1..65535}; do
  echo >/dev/tcp/devme.it/$port &&
    echo "Yes, I found that port $port is open" ||
    echo "Ops, I found that port $port is closed"
done

Il codice di sopra funziona esattamente come un port scanner con l'unico problema che se la porta risulta chiusa, la shell la rileva dopo circa un paio di minuti, il che rende in pratica poco utilizzabile lo script di sopra. La soluzione che ho trovato in rete è quella di realizzare una sorta di allarme che interrompe lo script se il tempo impiegato per analizzare una porta supera un certo limite, passato come parametro. Riporto il codice per completezza:

alarm() {
  perl -e  '
    eval {
      $SIG{ALRM} = sub { die };
      alarm shift;
      system(@ARGV);
    };
    if ($@) { exit 1 }
   ' "$@";
}

Volendo scrivere un comando completo, il tutto diventa:

scanme() {
  if [[ -z $1 || -z $2 ]]; then
    echo "Usage: $0 <host> <port> <port-range>"
    return
  fi
 
  local host=$1
  local ports=()
  case $2 in
    *-*)
      IFS=- read start end <<< "$2"
      for ((port=start; port <= end; port++)); do
        ports+=($port)
      done
      ;;
    *,*)
      IFS=, read -ra ports <<< "$2"
      ;;
    *)
      ports+=($2)
      ;;
  esac
 
 
  for port in "${ports[@]}"; do
    alarm 1 "echo >/dev/tcp/$host/$port" &&
    echo "Yes, I found that port $port is open" ||
    echo "Ops, I found that port $port is closed"
  done
}

Testando il comando di sopra si ha: scanme devme.it 80-92

#$> scan scanme 80-92 
Yes, I found that port 80 is open
Ops, I found that port 81 is closed
Ops, I found that port 82 is closed

Esiste poi un comando di sistema che consente di lanciare un comando con un time limit, timeout. Con questo comando il tutto diventa molto più semplice:

#$> timeout 1 bash -c "echo >/dev/tcp/$host/$port" &&
    echo "Yes, I found that port $port is open" ||
    echo "Ops, I found that port $port is closed"

Stay tuned!

WordPress Themes