Archive for the ‘nerd’ Category

Apache mod auth form with OTP support as separated field

Posted: 9th febbraio 2018 by luca in nerd

In questi giorni ho avuto la necessità di modificare il modulo di autenticazione mod_auth_form di apache per aggiungere il supporto dell’OTP come campo separato e non per forza accodato alla password (questo perchè ho la necessità di salvare separatamente i due campi per successivi utilizzi in backend).

Con questa piccola patch si ottengono due nuovi parametri di configurazione inerenti a mod_auth_form, ovvero:

AuthFormOtp = Permette di impostare il nome del campo form che cotiene il campo OTP (come per AuthFormPassword) [default httpd_otp]
AuthFormOtpReuse = se impostato ad On rimanda il token otp accodato alla password al provider di autenticazione scelto anche quando tutte le credenziali arrivano dalla sessione (cookie nel nostro caso) [default off]

La logica di funzionamento è molto semplice; se nella POST il campo httpd_otp NON esiste il modulo funziona in maniera tradizionale, invece se questo campo è presente allora la password e l’otp vengono uniti in una unica stringa ed inviati al sottostante provider autenticazione scelto.
Il salvataggio dei dati nella sessione avviene mantendendo separati user password e otp.

Attenzione, l’otp e la password vengono uniti SOLO nel caso di una autenticazione proveniente da form (quindi una post http), se la ri-autenticazione sta avvenendo mediante la sessione (es: cookie) l’otp viene ignorato perchè, verosimilmente, sarà scaduto… questo comportamento però modificabile tramite l’apposita riga di configurazione AuthFormOtpReuse.

Ecco la patch:

--- mod_auth_form.c.orig	2014-06-03 14:14:22.000000000 +0200
+++ mod_auth_form.c	2018-02-09 10:11:56.274877918 +0100
@@ -40,6 +40,8 @@
 #define FORM_REDIRECT_HANDLER "form-redirect-handler"
 #define MOD_AUTH_FORM_HASH "site"
 
+#define MOD_SESSION_OTP "otp"
+
 static int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL;
 static apr_status_t (*ap_session_get_fn)(request_rec * r, session_rec * z,
         const char *key, const char **value) = NULL;
@@ -59,10 +61,14 @@
     int username_set;
     const char *password;
     int password_set;
+    const char *otp;
+    int otp_set;
     apr_size_t form_size;
     int form_size_set;
     int fakebasicauth;
     int fakebasicauth_set;
+    int otpreuse;
+    int otpreuse_set;
     const char *location;
     int location_set;
     const char *method;
@@ -95,6 +101,7 @@
     /* default form field names */
     conf->username = "httpd_username";
     conf->password = "httpd_password";
+    conf->otp = "httpd_otp";
     conf->location = "httpd_location";
     conf->method = "httpd_method";
     conf->mimetype = "httpd_mimetype";
@@ -118,12 +125,16 @@
     new->username_set = add->username_set || base->username_set;
     new->password = (add->password_set == 0) ? base->password : add->password;
     new->password_set = add->password_set || base->password_set;
+    new->otp = (add->otp_set == 0) ? base->otp : add->otp;
+    new->otp_set = add->otp_set || base->otp_set;
     new->location = (add->location_set == 0) ? base->location : add->location;
     new->location_set = add->location_set || base->location_set;
     new->form_size = (add->form_size_set == 0) ? base->form_size : add->form_size;
     new->form_size_set = add->form_size_set || base->form_size_set;
     new->fakebasicauth = (add->fakebasicauth_set == 0) ? base->fakebasicauth : add->fakebasicauth;
     new->fakebasicauth_set = add->fakebasicauth_set || base->fakebasicauth_set;
+    new->otpreuse = (add->otpreuse_set == 0) ? base->otpreuse : add->otpreuse;
+    new->otpreuse_set = add->otpreuse_set || base->otpreuse_set;
     new->method = (add->method_set == 0) ? base->method : add->method;
     new->method_set = add->method_set || base->method_set;
     new->mimetype = (add->mimetype_set == 0) ? base->mimetype : add->mimetype;
@@ -227,6 +238,14 @@
     return check_string(cmd, password);
 }
 
+static const char *set_cookie_form_otp(cmd_parms * cmd, void *config, const char *otp)
+{
+    auth_form_config_rec *conf = (auth_form_config_rec *) config;
+    conf->otp = otp;
+    conf->otp_set = 1;
+    return check_string(cmd, otp);
+}
+
 static const char *set_cookie_form_method(cmd_parms * cmd, void *config, const char *method)
 {
     auth_form_config_rec *conf = (auth_form_config_rec *) config;
@@ -342,6 +361,14 @@
     return NULL;
 }
 
+static const char *set_disable_otp_reuse(cmd_parms * cmd, void *config, int flag)
+{
+    auth_form_config_rec *conf = (auth_form_config_rec *) config;
+    conf->otpreuse = flag;
+    conf->otpreuse_set = 1;
+    return NULL;
+}
+
 static const char *set_disable_no_store(cmd_parms * cmd, void *config, int flag)
 {
     auth_form_config_rec *conf = (auth_form_config_rec *) config;
@@ -358,6 +385,8 @@
                   "The field of the login form carrying the username"),
     AP_INIT_TAKE1("AuthFormPassword", set_cookie_form_password, NULL, OR_AUTHCFG,
                   "The field of the login form carrying the password"),
+    AP_INIT_TAKE1("AuthFormOtp", set_cookie_form_otp, NULL, OR_AUTHCFG,
+                  "The field of the login form carrying the OTP"),
     AP_INIT_TAKE1("AuthFormLocation", set_cookie_form_location, NULL, OR_AUTHCFG,
                   "The field of the login form carrying the URL to redirect on "
                   "successful login."),
@@ -396,6 +425,10 @@
                  NULL, OR_AUTHCFG,
                  "Set to 'On' to pass through authentication to the rest of the "
                  "server as a basic authentication header."),
+    AP_INIT_FLAG("AuthFormOtpReuse", set_disable_otp_reuse,
+                 NULL, OR_AUTHCFG,
+                 "Set to 'On' for reuse OTP number from cookie and send'it to "
+                 "to authentication provider."),
     AP_INIT_FLAG("AuthFormDisableNoStore", set_disable_no_store,
                  NULL, OR_AUTHCFG,
                  "Set to 'on' to stop the sending of a Cache-Control no-store header with "
@@ -432,7 +465,7 @@
  * notes table.
  */
 static void set_notes_auth(request_rec * r,
-                                const char *user, const char *pw,
+                                const char *user, const char *pw, const char *otp,
                                 const char *method, const char *mimetype)
 {
     apr_table_t *notes = NULL;
@@ -456,6 +489,9 @@
     if (pw) {
         apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-pw", NULL), pw);
     }
+    if (otp) {
+        apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-otp", NULL), otp);
+    }
     if (method) {
         apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-method", NULL), method);
     }
@@ -471,7 +507,7 @@
  */
 static void get_notes_auth(request_rec *r,
                            const char **user, const char **pw,
-                           const char **method, const char **mimetype)
+                           const char **method, const char **mimetype, const char **otp)
 {
     const char *authname;
     request_rec *m = r;
@@ -493,6 +529,9 @@
     if (pw) {
         *pw = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-pw", NULL));
     }
+    if (otp) {
+        *otp = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-otp", NULL));
+    }
     if (method) {
         *method = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-method", NULL));
     }
@@ -506,9 +545,9 @@
     }
 
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
-                  "from notes: user: %s, pw: %s, method: %s, mimetype: %s",
-                  user ? *user : "", pw ? *pw : "",
-                  method ? *method : "", mimetype ? *mimetype : "");
+                  "from notes: user: %s, pw: %s, method: %s, mimetype: %s, otp: %s",
+                  user ? *user : "", pw ? *pw : "", 
+                  method ? *method : "", mimetype ? *mimetype : "",otp ? *otp : "");
 
 }
 
@@ -519,7 +558,7 @@
  * and/or password will be removed from the session.
  */
 static apr_status_t set_session_auth(request_rec * r,
-                                     const char *user, const char *pw, const char *site)
+                                     const char *user, const char *pw, const char *site, const char *otp)
 {
     const char *hash = NULL;
     const char *authname = ap_auth_name(r);
@@ -533,6 +572,7 @@
     ap_session_load_fn(r, &z);
     ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_USER, NULL), user);
     ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_PW, NULL), pw);
+    ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_OTP, NULL), otp);
     ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_AUTH_FORM_HASH, NULL), hash);
 
     return APR_SUCCESS;
@@ -544,10 +584,12 @@
  * notes table, if present.
  */
 static apr_status_t get_session_auth(request_rec * r,
-                                     const char **user, const char **pw, const char **hash)
+                                     const char **user, const char **pw, const char **hash, const char **otp)
 {
     const char *authname = ap_auth_name(r);
     session_rec *z = NULL;
+    auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config,
+                                                      &auth_form_module);
 
     ap_session_load_fn(r, &z);
 
@@ -557,6 +599,11 @@
     if (pw) {
         ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_PW, NULL), pw);
     }
+    if (conf->otpreuse) {
+	    if (otp) {
+	        ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_OTP, NULL), otp);
+	    }
+    }
     if (hash) {
         ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_AUTH_FORM_HASH, NULL), hash);
     }
@@ -568,9 +615,10 @@
 
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
                   "from session: " MOD_SESSION_USER ": %s, " MOD_SESSION_PW
-                  ": %s, " MOD_AUTH_FORM_HASH ": %s",
+                  ": %s, " MOD_AUTH_FORM_HASH ": %s, " MOD_SESSION_OTP ": %s (reuse %s)" ,
                   user ? *user : "", pw ? *pw : "",
-                  hash ? *hash : "");
+                  hash ? *hash : "", otp ? *otp : "",
+                  conf->otpreuse ? "On" : "Off");
 
     return APR_SUCCESS;
 
@@ -590,12 +638,14 @@
 static int get_form_auth(request_rec * r,
                              const char *username,
                              const char *password,
+                             const char *otp,
                              const char *location,
                              const char *method,
                              const char *mimetype,
                              const char *body,
                              const char **sent_user,
                              const char **sent_pw,
+                             const char **sent_otp,
                              const char **sent_loc,
                              const char **sent_method,
                              const char **sent_mimetype,
@@ -612,7 +662,7 @@
     char *buffer;
 
     /* have we isolated the user and pw before? */
-    get_notes_auth(r, sent_user, sent_pw, sent_method, sent_mimetype);
+    get_notes_auth(r, sent_user, sent_pw, sent_method, sent_mimetype, sent_otp);
     if (*sent_user && *sent_pw) {
         return OK;
     }
@@ -639,6 +689,14 @@
             buffer[len] = 0;
             *sent_pw = buffer;
         }
+        else if (otp && !strcmp(pair->name, otp) && sent_otp) {
+            apr_brigade_length(pair->value, 1, &len);
+            size = (apr_size_t) len;
+            buffer = apr_palloc(r->pool, size + 1);
+            apr_brigade_flatten(pair->value, buffer, &size);
+            buffer[len] = 0;
+            *sent_otp = buffer;
+        }
         else if (location && !strcmp(pair->name, location) && sent_loc) {
             apr_brigade_length(pair->value, 1, &len);
             size = (apr_size_t) len;
@@ -669,11 +727,12 @@
     }
 
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
-                  "from form: user: %s, pw: %s, method: %s, mimetype: %s, location: %s",
+                  "from form: user: %s, pw: %s, method: %s, mimetype: %s, location: %s, otp: %s",
                   sent_user ? *sent_user : "", sent_pw ? *sent_pw : "",
                   sent_method ? *sent_method : "",
                   sent_mimetype ? *sent_mimetype : "",
-                  sent_loc ? *sent_loc : "");
+                  sent_loc ? *sent_loc : "",
+		  sent_otp ? *sent_otp : "");
 
     /* set the user, even though the user is unauthenticated at this point */
     if (sent_user && *sent_user) {
@@ -702,7 +761,7 @@
      * save away the username, password, mimetype and method, so that they
      * are available should the auth need to be run again.
      */
-    set_notes_auth(r, *sent_user, *sent_pw, sent_method ? *sent_method : NULL,
+    set_notes_auth(r, *sent_user, *sent_pw, *sent_otp ? *sent_otp : NULL, sent_method ? *sent_method : NULL,
                    sent_mimetype ? *sent_mimetype : NULL);
 
     return OK;
@@ -756,12 +815,20 @@
  *
  * Return an HTTP code.
  */
-static int check_authn(request_rec * r, const char *sent_user, const char *sent_pw)
+static int check_authn(request_rec * r, const char *sent_user, const char *sent_pw, const char *sent_otp)
 {
     authn_status auth_result;
     authn_provider_list *current_provider;
     auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config,
                                                       &auth_form_module);
+    char *sent_secret = NULL;
+
+    // -lm
+    if (sent_otp) {
+	sent_secret = apr_pstrcat(r->pool, sent_pw, sent_otp, NULL);
+    } else {
+	sent_secret = apr_pstrcat(r->pool, sent_pw, NULL);
+    }
 
     current_provider = conf->providers;
     do {
@@ -794,7 +861,12 @@
             break;
         }
 
-        auth_result = provider->check_password(r, sent_user, sent_pw);
+	ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+                  "provider->check_password - sent_user : %s, sent_secret: %s (pw: %s - otp: %s)", 
+		  sent_user, sent_secret, sent_pw, sent_otp);
+
+        auth_result = provider->check_password(r, sent_user, sent_secret);
+        //auth_result = provider->check_password(r, sent_user, sent_pw);
 
         apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
 
@@ -883,7 +955,7 @@
 {
     auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config,
                                                       &auth_form_module);
-    const char *sent_user = NULL, *sent_pw = NULL, *sent_hash = NULL;
+    const char *sent_user = NULL, *sent_pw = NULL, *sent_hash = NULL, *sent_otp = NULL;
     const char *sent_loc = NULL, *sent_method = "GET", *sent_mimetype = NULL;
     const char *current_auth = NULL;
     const char *err;
@@ -919,11 +991,11 @@
     r->ap_auth_type = (char *) current_auth;
 
     /* try get the username and password from the notes, if present */
-    get_notes_auth(r, &sent_user, &sent_pw, &sent_method, &sent_mimetype);
+    get_notes_auth(r, &sent_user, &sent_pw, &sent_method, &sent_mimetype, &sent_otp);
     if (!sent_user || !sent_pw || !*sent_user || !*sent_pw) {
 
         /* otherwise try get the username and password from a session, if present */
-        res = get_session_auth(r, &sent_user, &sent_pw, &sent_hash);
+        res = get_session_auth(r, &sent_user, &sent_pw, &sent_hash, &sent_otp);
 
     }
     else {
@@ -941,7 +1013,7 @@
 
     /* otherwise test for a normal password match */
     if (APR_SUCCESS == res && sent_user && sent_pw) {
-        rv = check_authn(r, sent_user, sent_pw);
+        rv = check_authn(r, sent_user, sent_pw, sent_otp);
         if (OK == rv) {
             fake_basic_authentication(r, conf, sent_user, sent_pw);
             return OK;
@@ -990,9 +1062,9 @@
         ap_run_insert_filter(rr);
 
         /* parse the form by reading the subrequest */
-        rv = get_form_auth(rr, conf->username, conf->password, conf->location,
+        rv = get_form_auth(rr, conf->username, conf->password, conf->otp, conf->location,
                            conf->method, conf->mimetype, conf->body,
-                           &sent_user, &sent_pw, &sent_loc, &sent_method,
+                           &sent_user, &sent_pw, &sent_otp, &sent_loc, &sent_method,
                            &sent_mimetype, &sent_body, conf);
 
         /* make sure any user detected within the subrequest is saved back to
@@ -1028,10 +1100,10 @@
 
         /* check the authn in the main request, based on the username found */
         if (OK == rv) {
-            rv = check_authn(r, sent_user, sent_pw);
+            rv = check_authn(r, sent_user, sent_pw, sent_otp);
             if (OK == rv) {
                 fake_basic_authentication(r, conf, sent_user, sent_pw);
-                set_session_auth(r, sent_user, sent_pw, conf->site);
+                set_session_auth(r, sent_user, sent_pw, conf->site, sent_otp);
                 if (sent_loc) {
                     apr_table_set(r->headers_out, "Location", sent_loc);
                     return HTTP_MOVED_TEMPORARILY;
@@ -1115,7 +1187,7 @@
     auth_form_config_rec *conf;
     const char *err;
 
-    const char *sent_user = NULL, *sent_pw = NULL, *sent_loc = NULL;
+    const char *sent_user = NULL, *sent_pw = NULL, *sent_otp = NULL, *sent_loc = NULL;
     int rv;
 
     if (strcmp(r->handler, FORM_LOGIN_HANDLER)) {
@@ -1131,14 +1203,14 @@
 
     conf = ap_get_module_config(r->per_dir_config, &auth_form_module);
 
-    rv = get_form_auth(r, conf->username, conf->password, conf->location,
+    rv = get_form_auth(r, conf->username, conf->password, conf->otp, conf->location,
                        NULL, NULL, NULL,
-                       &sent_user, &sent_pw, &sent_loc,
+                       &sent_user, &sent_pw, &sent_otp, &sent_loc,
                        NULL, NULL, NULL, conf);
     if (OK == rv) {
-        rv = check_authn(r, sent_user, sent_pw);
+        rv = check_authn(r, sent_user, sent_pw, sent_otp);
         if (OK == rv) {
-            set_session_auth(r, sent_user, sent_pw, conf->site);
+            set_session_auth(r, sent_user, sent_pw, conf->site, sent_otp);
             if (sent_loc) {
                 apr_table_set(r->headers_out, "Location", sent_loc);
                 return HTTP_MOVED_TEMPORARILY;
@@ -1202,7 +1274,7 @@
     conf = ap_get_module_config(r->per_dir_config, &auth_form_module);
 
     /* remove the username and password, effectively logging the user out */
-    set_session_auth(r, NULL, NULL, NULL);
+    set_session_auth(r, NULL, NULL, NULL, NULL);
 
     /*
      * make sure the logout page is never cached - otherwise the logout won't
@@ -1249,7 +1321,7 @@
     }
 
     /* get the method and mimetype from the notes */
-    get_notes_auth(r, NULL, NULL, &sent_method, &sent_mimetype);
+    get_notes_auth(r, NULL, NULL, &sent_method, &sent_mimetype, NULL);
 
     if (r->kept_body && sent_method && sent_mimetype) {

Qualche giorno addietro mi si è presentata la necessità di inviare, a valle di un reverse proxy, il contenuto di un cookie cifrato.

Apache2 implementa (almeno in teoria) questa funzionalità e si chiama SessionHeader (potete vedere qui le specifiche in “Integrating Sessions with External Applications”).

Tutto molto figo pensavo… peccato non funziona nulla!

La cosa mi ha lasciato abbastanza perplesso e dopo una serie di ricerche ha trovato la segnalazione di un bug di un utente che, come me, si era scontrato con la medesima problematica… bug segnalato sul Bugzilla di apache (Bug n. 56495) in data 2014-05-06 19:19 UTC by David Goldfarb.

Figo ho pensato… quelli di apache se ne sono largamente sbattuti della problematica!

Per fortuna l’utente proponeva una piccola patch a mod_session.c per risolvere la problematica (che è palesemente una dimenticanza nel codice), la patch però risulta instabile per cui ho apportato qualche piccola modifica per evitare il segfault di apache, ecco il diff:

--- httpd-2.4.9.orig/modules/session/mod_session.c   2014-01-24 07:02:42.000000000 -0600
+++ httpd-2.4.9/modules/session/mod_session.c   2014-05-06 13:59:09.084183389 -0500
@@ -385,6 +385,13 @@

     /* decode what we have */
     encoded = apr_pstrdup(r->pool, z->encoded);
+
+    /* Add the Decoded session info into the Input Headers
+     *  for the application to find */
+    session_dir_conf *conf = ap_get_module_config(r->per_dir_config,
+                                                  &session_module);
+    if (conf->header) {  
+         apr_table_set(r->headers_in, conf->header, encoded);
+    }  
+
     pair = apr_strtok(encoded, sep, &last);
     while (pair && pair[0]) {
         char *plast = NULL;

 

La teoria della montagna di merda

Posted: 4th luglio 2017 by luca in me?!, nerd

Niente in questi giorni ho riletto questo articolo di samuele dal suo blog, sostanzialmente una rielaborazione del pensiero che deriva dalla teorema della scimmia instancabile (qui).

Grazie per la riflessione, ora ho capito che “L’internet” non è altro che il bar dello sport a livello globale, grazie umanità.

 

Ok, il titolo di questo post è complicato ed è per addetti ai lavori, ovviamente non scendo troppo in tecnicismi… magari anche l’utente comune capisce che cosa sto raccontando.

Durante l’analisi di malware giunto alla mia casella e-mail personale ho scoperto una nuova tecnica di comunicazione di malware con il proprio centro di controllo, nonostante l’indirizzo HTTP di questo centro di controllo ritorni un HTTP Status 404; vediamola nel dettaglio.

  • STAGE 1

Lo stage 1 si presenta come mail innoqua che mi spinge a cliccare sul finto file excel allegato, facendomi credere si tratti di una fattura a me intestata.
Ovviamente non si tratta di un file excel ma di un file eseguibile:

dreams@ai:~/Desktop/Malware/malware$ file Fat._febbraio_2016\ xls_.XLS.exe
Fat._febbraio_2016 xls_.XLS.exe: PE32 executable (GUI) Intel 80386, for MS Windows

Per ora ignoriamo i dettagli di funzionamento di questo specifico malware sapendo che il suo obbiettivo è solo quello di scaricare lo stage 2 una volta avviato, download che avviene dall’indirizzo hxxp[:]//www.tajjquartet.com/ff/serif/payload.exe.
Difatto lo stage 1 si caratterizza per un attacco di phishing verso l’utente con l’incoulazione di un trojan-downloader.

  • STAGE 2

A questo punto inizia la vera e propria infezione della macchina, payload.exe oltre ad effettuare alcune verifiche tecniche (ad es: se sta girando su un ambiente virtuale, se si tratta di una sandbox etc etc) si preoccupa di disattivare il firewall di windows e altre feature di sicurezza e successivamente rilascia (drop) un ulteriore eseguibile contenuto al suo interno, lo avvia e gli garantisce la persistenza al riavvio (crea la chiave di registro per l’autostart), il file droppato si chiama winhelp.exe posizionato nella home directory dell’utente.
Lo stage 2 si caratterizza per l’esecuzione di un trojan-dropper e la modifica della politica di sicurezza della macchina (all’insaputa dell’utente).

  • STAGE 3

A questo punto la macchina risulta compromessa, ad ogni avvio viene avviato winhelp.exe ipotizzo che il suo compitoa principale sia quello di mantenere attiva la comunicazione con il C&C, ok in che modo??
Dall’analisi delle stringhe in memoria non si trova nessun riferimento a URL in particolare, però mi ha colpito immediatamente la presenza di header HTTP e di un base64

dreams@ai:~/Desktop/Malware/malware$ strings winhelp.exe.txt | grep “=”
=uhj
=hH8A
hh=A
exec=1&task_id=%S
cmd=1&uid=%s&os=%s&av=%s&version=%s&quality=%i
fail=1&task_id=%S
OPEN=%s
action=Run
aHR0cDovL2NvbnNpbGRlcnR1ZnVuLnh5ei9jc3MvYWpheC5waHA= <—- BASE64
auth=1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 <—- header
Accept-Language: en-us,en;q=0.5
[…]

A questo punto passo la stringa base64 al motore di decodifica e vediamo che accade:

dreams@ai:~/Desktop/Malware/malware$ decode aHR0cDovL2NvbnNpbGRlcnR1ZnVuLnh5ei9jc3MvYWpheC5waHA=
Decoding base64
hxxp[:]//consildertufun.xyz/css/ajax.php

“bingo!” mi viene da affermare anche perchè dal resto dell’analisi non emerge alcun altro URL ne, tanto meno, altri metodi di comunicazione verso l’esterno, quindi non può essere che questo il mio c&c.
Purtroppo qualcosa non torna, difatto facendo una prova per vedere se effettivamente il C&C fosse ancora attivo ottengo come risultato un bel 404 file not found.

A questo punto un analista normalmente penserebbe che il C&C non è più attivo e quindi l’analisi finisce qui… eppure il giorno successivo accade un altro fatto, ricevo una nuova mail contenente un nuovo stage 1, nome diverso, mittente diverso allegato diverso ma l’analisi di questo emerge che punta al medesimo stage 2, ovvero payload.exe.

Perchè continua la distrubuzione di un malware verso un C&C che non funziona?
Probabilmente sono stato troppo frettoloso nel classificare il centro di controllo come morto.. inizio a vagliare le possibilità, magari il C&C viene attivato solo in determinati orari o in determinati giorni… o forse… forse c’è dell’altro..  così ricontrollo meglio le stringhe di winhelp.exe e noto una caratterista che pensavo fosse semplicemente un camuffamento per far sembrare la sessione http in uscita più uamana.

dreams@ai:~/Desktop/Malware/malware$ strings winhelp.exe.txt | grep cooki -i
document.cookie=
Cookie: %s
Cookie: authkeys=21232f297a57a5a743894a0e4a801fc3
Cookie: authkeys=21232f297a57a5a743894a0e4a801fc3
Cookie: authkeys=21232f297a57a5a743894a0e4a801fc3
Cookie: authkeys=21232f297a57a5a743894a0e4a801fc3

Perchè utilizzare veramente un cookie?
Incuriosito da questo dettaglio passo a fare una analisi del malware in contesto reale, con una reale connessione ad internet. Dopo qualche tempo recupero il file pcap generato con tutte le connessioni di rete e noto che effettivamente i post avvengono verso il sito, ed il sito risponde 404, ma qualcosa cambiava:

wireshark

La dimensione (Length) della sessione variava, e anche di tanto… come era possibile? cosa stava facendo realmente questo malware?
Approfondisco l’analisi di una specifica sessione HTTP (la prima, tanto per iniziare), ed ecco l’estratto:

POST

Per chi è abituato a vedere codice HTML noterà subito il commento appeso a fine pagina tra le righe chiamate DEBUG, anche in questo caso abbiamo un bel base64 che passato subito al motore di decodifica ci mostra quanto segue:

dreams@ai:~/Desktop/Malware/malware$ decode cG9uZw==
Decoding base64
pong

PONG? ebbene si… il c&c è vivo e risponde correttamente…
Ovviamente l’analisi poi è continuata, il malware ha scaricato ulteriori stage per effettuare altre attività che ora ometto.
Nella mia piccola carriera di analisi malware e di attacchi informatici non ero mai capitato in una casisitica come questa.
Mi ha colpito la semplice genialità dell’utilizzare una stato HTTP permesso e “valido” ma per abitudine considerato “non valido” per ingannare tutte le potenziali analisi.

Ne vedremo delle belle…

sicurezza_informatica__quale_futuro__6380

 

In questi giorni mi domando quale sarà il futuro del campo in cui lavoro, ovvero la sicurezza informatica, fino a non poco tempo fa si diceva che la cyberwar non esisteva o che l’APT fosse inventato invece ora questa attività, reali, sembrano già vecchie.
Personalmente credo che il mercato della sicurezza si dovrà ampliare mostrusamente visto ormai come l’informatica venga applicata anche a realtà che “informatiche” non erano; pensiamo allo scandalo della jeep cherokee uscito in questi giorni.
In particolare quello che mi affascina di più sono tutte le future applicazioni nel campo della domatica; stiamo andando verso la casa iper-connessa ma con una livello di sicurezza non adeguato (almeno a mio parere) sopratutto visto quanto sarà calata nella riservatezza o alla privacy tutta domestica.

Che sia ora di mandare il CV a BTicino? 🙂

Generazione senza identità?

Posted: 14th dicembre 2014 by luca in lavoratore, nerd

Siamo la generazione della guerra digitale.

Guerra senza limiti

Posted: 1st febbraio 2014 by luca in me?!, nerd
Guerra senza limiti

Guerra senza limiti. L’arte della guerra asimmetrica fra terrorismo e globalizzazione
Qiao Liang; Wang Xiangsui

[…]
L’epoca dei “soldati forti e coraggiosi, eroici difensori della patria” è tramontata. In un mondo in cui persino l’espressione “guerra nucleare” diverrà forse gergo militare obsoleto, è probabile che un pallido, occhialuto studioso sia più adatto a diventare un soldato moderno rispetto ad un giovane muscoloso senza grosse pretese intelletuali. La miglior dimostrazione di questo è forse una storia, che circola negli ambienti militari occidendali, di un tenente che ha utilizzato un modem per mettere in ginocchio una divisione navale.
[…]
Nel 1994 in tema di sicurezza vi sono state 230.000 intrusioni nelle reti della difesa americana. Quante di queste erano atti distruttivi organizzati da combattenti non professionisti?
[…]
Proprio come la tecnologia moderna sta modificando le armi e il campo di battaglia, nello stesso tempo sta offuscando il concetto di partecipanti alla guerra. D’ora in poi, i soldati non avranno più il monopolio della guerra.
[…]
(“chi combatte” – Guerra senza limiti)

Cyberwar

Posted: 27th novembre 2012 by luca in nerd

Faceva caldo, la notte che bruciammo Chrome. Nei viali e nelle piazze le falene sbattevano fino a morire contro le luci al neon, ma nella mansarda di Bobby l’unica luce era quella del monitor

La notte che bruciammo Chrome – William Gibson

Oggi in pausa pranzo sono rimasto affascinato da questo articolo apparso su corriere:

E il Pentagono crea una cyber city per difendersi dagli attacchi hacker

(leggi tutto)

Ovviamente l’articolo è scritto da un giornalista Italiano, quindi sarà molto approsimativo, però quello che mi interessa è la notizia in sè…si perché questi scenari sono stati argomento di dibattito da “bar” con alcuni amici e insomma… credo di aver sbagliato paese.

Il Grillo Parlante

Posted: 2nd ottobre 2012 by luca in me?!, nerd
Tags: ,

Grillo Parlante

Che ricordo incredibile d’infanzia che è questo…. ora penso che tutti quelli della mia generazione in passato abbiano avuto a che fare con il grillo parlante (io lo avevo… e spero di averlo ancora in cantina!)

Per fortuna su internet è possibile trovare tanto materiale video al riguardo ma per prima cosa, lo spot:

Notevole… sopratutto gli effetti di speciali… diavolo erano gli anni 80 !!! 😀 ahahah

Comunque, sostanzialmente, era un minicomputer che faceva text-to-speach e spelling (tra l’altro il nome originale era speak & spell prodotto dalla Texas Instruments e distribuito in Italia dalla Clementoni).

Comunque devo ammettere che era veramente bello… e teoricamente anche istruttivo… anche se ora non ne sono più così convinto…(viste le mie scarse capacità calligrafiche!)

Ma ancora oggi mi rimane un dubbio… perchè quando non capiva diceva “NON RICEVO” ?

Giusto per farvi capire (o commuovere) eccovi come funzionava:

Ilota a tutti!!!

il K&R

Articolo tratto da mal di tech (corriere.it)

Addio Dennis e grazie per tutto il pesce

Dennis Ritchie se n’è andato 6 giorni fa (ma la notizia si è diffusa in rete ieri). Senza grande clamore, se non fra gli addetti ai lavori. Il che è comprensibile. Non era un venditore e i suoi gadget non sono entrati nelle case di miliardi di persone. Non guidava aziende quotate al Nasdaq. Né faceva keynote ammaliando le folle.

Ma senza di lui non esisterebbero Linux, né Mac Os X. E neppure Windows. E parecchia altra roba. Di fatto Ritchie, una delle colonne dei Bell Labs, ha inventato – con altri – l’informatica moderna. Tra i “figli” di Ritchie c’è Unix, il primo sistema operativo che ha conquistato l’ambiente professionale (server, super-computer). Grazie Unix è nato Linux. E più tardi anche Mac Os X.

L’altra creazione di Ritchie è il linguaggio di programmazione C. Il cosiddetto K&R (il titolo italiano è Il linguaggio C) dai nomi degli autori (Brian) Kernighan e (Dennis) Ritchie, è tuttora uno dei testi fondamentali per impadronirsi della materia.  Una gran bella fetta del kernel (il “nocciolo”) di Windows NT e delle sue evoluzioni come Xp e Seven, è stata scritta proprio in C. Il C ha figliato altri diffusissimi linguaggi come il C++ e Objective-C, che tanta importanza ha per le app di iOs. Insomma, senza Ritchie forse non giochereste neanche a Angry Birds. Pensateci mentre tirate giù quei maledetti porcelli.