summaryrefslogtreecommitdiff
path: root/docs/chapters/setup.tex
blob: fab0a4a66ad316b9019f01bd49383d7f4cda97c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
In genere, quando vogliamo tenere traccia del traffico di richieste che vi è dentro una web app (XHR \cite{XHR:1}, caricamento di immagini, fonts, codice JS) apriamo la "console sviluppatore" che ci dà a disposizione Firefox (o qualsiasi altro browser, come Chrome) e iniziamo a guardare. 
Con questa relazione però, vogliamo fare un attacco attraverso un dispositivo mobile, quindi controlleremo il traffico in uscita nella nostra rete per scoprire a quale server la nostra mobile app sta facendo capo.
\newline\newline
Imposteremo tutto il necessario per simulare l'attacco visto nel capitolo precedente:
\begin{itemize}
	\item Una REST API con un problema di autorizzazione nell'endpoint degli utenti, il quale non verifica che l'utente loggato è effettivamente il possessore di quella risorsa. La installeremo in un server su internet;
	\item Un'applicazione mobile che fa richieste a tale API;
	\item Wireshark\cite{WIRESHARK:1} per monitorare la rete.
\end{itemize}

\section{API}

Prendendo ad esempio l'API REST di Github \cite{GITHUB:1}, si vede come, anche nella realtà, si usa un endpoint generale per visualizzare le informazioni di un determinato utente.

\textbf{Cosa proveremo a fare noi?} Diamo per assodato che un utente è autorizzato a visualizzare quell'endpoint (e così anche i corrispettivi di PUT e DELETE) solo se è l'owner di quella risorsa o se ha permessi speciali: da staffer nel nostro caso. 
\newline\newline
Il codice di questo servizio è presente al link \underline{\url{https://git.dcariotti.me/m6-ie/tree/server}}.
\newline\newline
La parte incriminata è la route qui sotto: controlla se l'utente dell'url è lo stesso del token di autorizzazione o altrimenti che l'utente dell'autorizazzione (il quale token è creato dal server) sia uno staffer.

\begin{lstlisting}
async fn get_user(Path(user_id): Path<i32>, claims: Claims) -> Result<Json<UserList>, AppError> {
    let claimed = match User::find_by_id(claims.user_id).await {
        Ok(user) => user,
        Err(_) => {
            return Err(AppError::NotFound("User not found".to_string()));
        }
    };

    if user_id != claimed.id {
        if !(claimed.is_staff.unwrap()) {
            return Err(AppError::Unauthorized);
        }
    }

    match User::find_by_id(user_id).await {
        Ok(user) => Ok(Json(user)),
        Err(_) => Err(AppError::NotFound("User not found".to_string())),
    }
}
\end{lstlisting}

in realtà qui non vi è nessun problema reale di sicurezza. È un API che funziona, ad ogni richiesta infatti controlla se il token è valido

\begin{lstlisting}
let token_data = decode::<Claims>(bearer.token(), &KEYS.decoding, &Validation::default())
            .map_err(|_| AppError::InvalidToken)?;
\end{lstlisting}

Il problema sta nell'inizializzazione della codifica/decodifica di JWT, in particolare quando definiamo il secret, dato che non fa un controllo della sicurezza di tale stringa.

\begin{lstlisting}
static KEYS: Lazy<Keys> = Lazy::new(|| {
    let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
    Keys::new(secret.as_bytes())
});

impl Keys {
    fn new(secret: &[u8]) -> Self {
        Self {
            encoding: EncodingKey::from_secret(secret),
            decoding: DecodingKey::from_secret(secret),
        }
    }
}
\end{lstlisting}

E proprio in questo "errore" nel secret che andremo ad attaccare. Useremo un attacco di bruteforcing all'header Authorization per far sì di avere i dati dell'utente con ID che noi vogliamo.

\section{App mobile}
Il codice dell'app è presente a \underline{\url{https://git.dcariotti.me/m6-ie/tree/app}}.
È un'applicazione scritta usando Ionic\footnote{https://ionicframework.com/} con 3 pagine:
\begin{enumerate}
    \item Home: ricorda cosa serve fare, ovvero il login;
    \item Sign in: permette di fare il login mediante username e password;
    \item Me: visualizza le informazioni dell'utente loggato.
\end{enumerate}

Sapendo ciò dovremo esaminare il file APK dell'applicazione per vedere come si comporta realmente.\\\\
Dentro il codice sorgente è presente il codice in JavaScript, ma a noi serve usarlo nel nostro dispositivo Android. Quindi, come faremmo realmente sviluppando un'app Ionic, lo andremo a compilare e visualizzarne l'APK dentro Android Studio\footnote{https://developer.android.com/studio/}.


\begin{lstlisting}
$ git clone https://git.dcariotti.me/m6-ie
$ cd m6-ie/app
$ npm i
$ vi .env # Chi fa la build conosce effettivamente l'URL dell'API
$ npm run build --production
$ npx cap copy android
$ npx cap sync android
$ cd android
$ export ANDROID_SDK_ROOT="<path all'sdk>"
$ ./gradlew assembleDebug
\end{lstlisting}

L'ultimo comando creerà un APK valido dentro \emph{./build/outputs/apk/debug/app-debug.apk}.
Da non confondere quindi con la creazione di pacchetti AAB\cite{APKVSAAB:1} per le release.

\subsection{Configurazione Android Studio}
Scaricato e installato il pacchetto dal link ufficiale bisognerà inoltre installare anche l'SDK e un Device, ovvero un emulatore di un dispositivo Android.

\begin{figure}[h]
\centering
\includegraphics[width=0.2\textwidth]{data/android-studio-screenshot}
\caption{Screenshot di Android Studio in Ubuntu focal}
\end{figure}


Nell'esempio qui di seguito io userò SDK 30 su un Pixel 4.\\
\\
Procediamo quindi al profiling dell'applicazione come da \textbf{Figure 3.1}.


Avviando l'emulatore attraverso \emph{Shift+F10} vedremo l'applicazione dentro il device Android, Google Pixel in questo caso.

\begin{figure}[h]
\centering
\includegraphics[width=0.2\textwidth]{data/pixel-device}
\caption{Screenshot dell'emulatore}
\end{figure}

Se provassimo ad intercettare il traffico usando il \emph{Network profiler} integrato non vedremmo nulla perché non vengono esaminate le richieste HTTP fatte in maniera ibrida; ecco che viene in aiuto Wireshark.