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!

Autenticazione facebook: la guida definitiva

logo_facebookSalve a tutti, negli ultimi tempi mi sto divertendo con diverse tecnologie, tra cui le app facebook. In realtà, il progetto ha richiesto lo sviluppo di un’applicazione facebook relativamente semplice, in cui il punto centrale è costituito dalla app request, ovvero le notifiche inviate all’utente dall’applicazione in uso dall’utente, una sorta di notifiche Push iOS style.
Al netto di questa cosa, ho trovato difficoltà nell’implementare il meccanismo di autenticazione richiesto da facebook, ma non perché lo stesso sia difficile, ma semplicemente perché sul sito ufficiale è molto confusa la spiegazione delle API open graph 2, e poi non ho trovato nessuna guida o tutorial che ne descrivesse l’utilizzo. Per questo motivo voglio condividere l’implementazione del meccanismo di autenticazione che ho realizzato all’interno della mia applicazione.

Cominciamo col dire che il back-end dell’applicazione è Java (strano eh!), nello specifico ho utilizzato delle API restFB, che consentono l’interazione con i servizi REST messi a disposizione da facebook. L’applicazione Java utilizza le servlet per interagire con l’utente, quindi in sostanza è un’applicazione web. Per poter utilizzare i servizi REST di facebook è necessario avere a disposizione un access-token, una chiave che consente di identificare l’entità che sta effettuando la richiesta e se la stessa possiede i privilegi per poterla invocare.

Di seguito la procedura per ottenere un access token:

1. https://graph.facebook.com/oauth/authorize?client_id=FACEBOOK_APP_ID&redirect_uri=REDIRECT_URL

2. https://graph.facebook.com/oauth/access_token?client_id=FACEBOOK_APP_ID&redirect_uri=REDIRECT_URL&code=CODE&
client_secret=APP_SECRET

3. Risposta con access token. 

Si parte con una richiesta HTTP all’indirizzo di cui al punto 1, fornendo come parametro la FACEBOOK_APP_ID, ovvero l’id dell’applicazione facebook creata ed un REDIRECT_URL, ovvero un indirizzo di rimando a cui verrà restituita una response contenente un codice, CODE. Lo stesso CODE, dovrà essere fornito come parametro all’indirizzo di cui al punto 2, assieme al FACEBOOK_APP_ID e di nuovo un REDIRECT_URL. Infine, a quest’ultimo verrà restituito una response contenente l’access token, come valore del primo parametro presente nell’URL.

Il punto centrale dell’applicazione Java web è costituito da una servlet filter, la quale viene invocata ogni qual volta si tenta di accedere ad una risorsa dall’applicazione facebook. La filter verifica che sia presente in sessione l’access token, il quale viene messo lì per ovvi motivi di comodità, non appena viene recuperato dalla procedura di autenticazione. Di seguito il codice della servlet filter:

 

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    HttpSession session = httpRequest.getSession();
 
    if (session.getAttribute(FacebookAuthConfig.OAUTH_TOKEN)==null) {
            FacebookAuthConfig facebookConfig = session.getFacebookConfiguration();
 
            String redirectURL = httpRequest.getRequestURL().toString();
            String code = StringUtils.noNullAndTrim(request.getParameter("code"));
            if (code.length()==0) {
                String tokenReqUrl = "https://graph.facebook.com/oauth/authorize?client_id="+facebookConfig.getAppID()+
                                     "&redirect_uri="+redirectURL;
                httpResponse.sendRedirect(tokenReqUrl);
                return;
            }
 
            String tokenUrl = "https://graph.facebook.com/oauth/access_token?client_id="+facebookConfig.getAppID()+
                             "&redirect_uri="+redirectURL+"&code="+code+"&client_secret="+facebookConfig.getAppSecret();
 
            DefaultWebRequestor webRequestor = new DefaultWebRequestor();
            Response fbresponse = webRequestor.executeGet(tokenUrl);
            String rawAccessToken = new String(fbresponse.getBody());
 
            String accessToken;
            if (rawAccessToken.indexOf("&") > -1) {
                rawAccessToken = rawAccessToken.split("&")[0];
            }
            accessToken = rawAccessToken.split("=")[1];
            session.setAttribute(FacebookAuthConfig.OAUTH_TOKEN, accessToken);
            User user = null;
 
            FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
            int attempt = 0;
            do {
                attempt++;
                log.info("* Fetching single objects *");
                try {
                    user = facebookClient.fetchObject("me", User.class);
                    logger.info("User name: " + user.getName());
                } catch (Exception e) {
                     if (attempt==1) {
                        log.warn("Error while quering data to Facebook service. Try again..");
                        continue;
                     } else {
                        log.info("Request error. Can't retrieve data from facebook service.");
                        httpResponse.sendRedirect(errorPage);
                        return;	
                    }
                }
                break;
            } while (true);
 
            session.setAttribute(FACEBOOK_USER_OBJ, user);
            session.setAttribute(OAUTH_TOKEN, accessToken);                    
    }
}

 La prima richiesta HTTP viene invocata per ottenere il CODE da rimandare come parametro nella seconda richiesta HTTP, si noti che nella prima richiesta, il REDIRECT_URL coincide con la stessa risorsa invocata. In questo modo, alla risposta in cui è presente il parametro CODE, è possibile procedere e quindi invocare la seconda richiesta. Quest’ultima viene invocata utilizzando le restFB API, ottenendo quindi la risposta raw direttamente nel body della response. Da lì viene estratta e resa disponibile in sessione. Successivamente viene eseguita una chiamata al servizio REST di facebook per ottenere informazioni riguardo l’utente che ha invocato la risorsa, e se la chiamata va a buon fine, viene aggiunto in sessione l’oggetto User messo a disposizione dalle restFB API. 

That’s all. Stay connected !

WordPress Themes