\documentclass[11pt,a4paper]{article}
\usepackage[portuguese]{babel}
\usepackage[lining]{ebgaramond}
\usepackage{style}
\setlength{\parindent}{0em}
\setlength{\parskip}{2ex}
\title{Practical Assignment \#3}
\author{
João Neto -- 2023234004\\[1em]
Vasco Alves -- 2022228207
}
\begin{document}
\maketitle
\newpage
\tableofcontents
\newpage
\section{Introduction}
% FAZER EM ENGLISH??? O prof é BR temos que fazer em Brazileiro
Este trabalho tem como objetivo realizar testes de penetração numa aplicação
cobaia (o \textit{Juicebox}) desenhada para aprendizagem.
Este trabalho tem como objetivo utilizar o \textbf{WSTG} (Web security
testing guide) e configurar um ModSecurity reverse proxy como uma
\textbf{WAF}. Para esse fim temos uma aplicação cobaia (o \textit{Juicebox})
desenhada para aprendizagem que vamos utilizar num ambiente controlado
para aprender como descobrir vulnerabilidades (aplicando o \textbf{WSTG}
e recorrendo ao \textbf{OWASP ZAP}) e prevenir antes do serviço estar
online (elaborando uma \textbf{WAF}).
\section{Architecture Considered for Both Stages}
Utilizámos somente duas máquinas virtuais: um servidor a correr \textit{CentOS 9}
e um cliente a correr \textit{Kali Linux}. O servidor contém o serviço \textit{Apache},
que age como \textit{firewall} através do módulo \textit{ModSecurity}, e um servidor
\textit{Node.js} que aloja o \textit{Juicebox} --- a aplicação que vai
servir de cobaia (\textit{dummy}).
% Vão ser realizadas duas etapas de testes: primeiro, sem WAF (\textit{Web Application Firewall})
% e com foco em explorar vulnerabilidades na aplicação; e, posteriormente, com uma WAF configurada para
% mitigar as várias vulnerabilidades que foram encontradas na etapa anterior.
% Para simular utilizámos \textit{Virtual Box}, como nos outros projetos, para criar as maquinas virtuais. O cenario que foi criado tem duas máquinas virtuais (servidor e cliente), e ambas as maquinas estão ligadas há mesma rede interna. O servidor vai ser executado numa das maquinas e vai ter o sistema operativo \textit{CentOS 9}, edereço 20.60.0.1, alojar um servidor \textit{Node.js} com o \textit{Juicebox} (a aplicação cobaia) na port 3000 e contém o seviço \textit{Apache} que através do módulo \textit{ModSecurity} funcionará como \textbf{WAF}. O cliente vai ser processado na maquina com o sistema operativo \textit{Kali Linux} e vai ter o edereço 20.60.0.2.
Com o ambiente criado foram realizadas duas etapas de testes:
\begin{itemize}
\item \texttt{Primeira etapa}: Explorar vulnerabilidades na aplicação que existem sem a \textbf{WAF}
\item \texttt{Segunda etapa}:Verificar que vulnerabilidades foram mitigadas da primeira etapa com o uso de uma \textbf{WAF} configurada.
\end{itemize}
Realisticamente estas etapas podiam continuar a repetir-se, até que
estivessemos satisfeitos com o resultado, mas para o fim deste projeto
estas etapas serão suficientes.
\subsection{Network structure}
\begin{itemize}
\item \textbf{Client (20.60.0.0/24)} Cliente.
\item \textbf{Server (10.60.0.0/24)} Apache+ModSecurity e JuiceShop.
\end{itemize}
\subsection{Servers}
\begin{itemize}
\item \textbf{10.60.0.1} Servidor CentOS 9 com WAF e aplicação JuiceShop.
\end{itemize}
\subsection{Services}
\begin{center}
\begin{tabular}{ll}
\toprule
Service & Port \\\midrule
NodeJS (JuiceShop) & 3000 \\
Apache (WAF) & 80 \\
\bottomrule
\end{tabular}
\end{center}
\section{Web application security testing}
\subsection{Information Gathering}
Utilizámos a política por omissão (\textit{default policy}) para a
realização do \textit{Active Scan} através do OWASP ZAP. Com esta
abordagem, obtivemos múltiplos alertas automáticos. De forma a priorizar
a análise, investigamos as alertas principais com base no maior nível de
risco e grau de confiança reportados pela ferramenta.
% Para conseguir informação inicial realizamos um \textit{Active Scan} através do \textit{OWASP ZAP}, o policy utilizado para esse scan foi \textit{Default Policy}. Foi obtido vários aletas automáticos devido a esse scan e decidimos investigar as alertas principais com base no nível de risco e grau de confiança reportado pela ferramenta.
Adicionalmente, realizámos testes de infraestrutura utilizando ferramentas especializadas:
\begin{codeblock}{bash}
sqlmap -u "http://192.168.1.1:3000/rest/products/search?q=apple" -p q --level=5 --risk=3 --banner
\end{codeblock}
Ao executar o \textit{sqlmap}, descobrimos que o sistema de gestão de
base de dados subjacente é o \textit{SQLite}.
Paralelamente, realizámos uma descoberta de ficheiros e diretórios
através de técnicas de \textit{fuzzing} de URLs no OWASP ZAP recorrendo
à lista de permissões da \textit{DirBuster}. Esta exploração revelou os
seguintes endpoints publicamente expostos:
\begin{itemize}
\item \texttt{/ftp}: Servidor de armazenamento e transferência de ficheiros exposto. (Figura \ref{fig:ftp})
\item \texttt{/metrics}: Métricas internas da infraestrutura expostas. (Figura \ref{fig:metrics})
\item \texttt{/api-docs}: Documentação e esquemas estruturais da API. (Figura \ref{fig:swagger})
\end{itemize}
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{ftp}
\caption{ftp}
\label{fig:ftp}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{metrics}
\caption{metrics}
\label{fig:metrics}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=\textwidth]{swagger}
\caption{swagger}
\label{fig:swagger}
\end{figure}
\subsection{Configuration and Deployment Management Testing}
\subsubsection*{Enumerate Infrastructure and Application Admin Interfaces}
Identificámos e testámos o acesso ao endpoint \texttt{/api-docs}
(\textit{Swagger UI}), validando que as interfaces de documentação
interna do sistema e as definições da API estavam publicamente expostas
sem qualquer tipo de controlo de acesso ou autenticação prévia.
\subsubsection*{Test HTTP Methods}
Testámos os métodos HTTP permitidos pelo servidor através do envio de
pedidos \texttt{OPTIONS}. Verificámos que o servidor aceita métodos
potencialmente perigosos ou desnecessários para utilizadores comuns em
rotas específicas, expandindo a superfície de ataque da aplicação.
\subsubsection*{Test File Permission}
Analisámos as permissões de acesso no diretório \texttt{/ftp}.
Verificámos que a falta de restrições rígidas ao nível do sistema de
ficheiros permite a qualquer utilizador anónimo listar o conteúdo de
diretórios estruturais e descarregar ficheiros não indexados na
interface principal da aplicação.
\subsection{Identity Management Testing}
\subsubsection*{Test Role Definitions}
Efetuámos testes de manipulação de parâmetros do lado do cliente através
das ferramentas de programador do navegador. Adicionámos manualmente os
cookies \texttt{isAdmin} com o valor \texttt{true} e \texttt{role} com o
valor \texttt{admin}. Após a atualização da página, não observámos
qualquer escalonamento de privilégios, indicando que a aplicação não
valida perfis administrativos com base nestes cookies específicos.
\subsubsection*{Test User Registration Process}
Utilizámos o OWASP ZAP para intercetar o tráfego de rede e definir um
\textit{breakpoint} no pedido HTTP POST de registo de novos utilizadores.
Modificámos o corpo do pedido JSON, injetando manualmente o parâmetro
\texttt{"role":"admin"}:
\begin{codeblock}{json}
{
"email": "johnGomas@gmail.com",
"role": "admin",
"password": "password",
"passwordRepeat": "password",
"securityQuestion": {
"id": 2,
"question": "Mother's maiden name?",
"createdAt": "2026-05-30T12:28:33.216Z",
"updatedAt": "2026-05-30T12:28:33.216Z"
},
"securityAnswer": "poker"
}
\end{codeblock}
O servidor backend processou o pedido sem validar se o utilizador
possuía autorização para definir o seu próprio perfil, o que resultou
na criação bem-sucedida de uma conta com permissões totais de
administrador (\textit{Mass Assignment Vulnerability}).
\subsubsection*{Testing for Account Enumeration and Guessable User Account}
Ao tentar registar um utilizador com o e-mail
\texttt{admin@juice-sh.op}, verificámos que a aplicação devolve uma
mensagem de erro explícita indicando que o e-mail já se encontra
registado no sistema. Este comportamento confirma a vulnerabilidade de
enumeração de contas, permitindo a um atacante mapear quais os e-mails
válidos na plataforma.
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\textwidth]{email-unique}
\caption{email-unique}
\label{fig:email-unique}
\end{figure}
\subsubsection*{Testing for Weak or Unenforced Username Policy}
Após testar vários caracteres especiais no formulário de registo,
criámos um utilizador com os seguintes dados nos campos de input:
\begin{itemize}
\item \textbf{E-mail:} \texttt{son'or1=1--@gmail.com}
\item \textbf{Nome/Campos Adicionais:} \texttt{
STRONG}
\end{itemize}
A aplicação aceitou o registo sem validar a presença de carateres de
injeção SQL ou tags HTML. Contudo, verificámos que é impossível efetuar
login com esta conta posteriormente, uma vez que o processo de
autenticação falha e resulta num erro genérico do tipo
\texttt{[object Object]} no ecrã.
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\textwidth]{email-invalido}
\caption{email-invalido}
\label{fig:email-invalido}
\end{figure}
\subsection{Authentication Testing}
Realizámos testes de \textit{fuzzing} automatizado contra o formulário
de login utilizando dicionários de credenciais. Identificámos que a
aplicação não implementa mecanismos de bloqueio de conta ou limitação
de taxa de pedidos \textit{rate limiting}, permitindo ataques contínuos
de \textit{brute force}.
\subsection{Authorization Testing}
Testámos as permissões de acesso ao diretório \texttt{/ftp} e
verificámos que o servidor está configurado para permitir nativamente
apenas a visualização de ficheiros com as extensões \texttt{.md} e
\texttt{.pdf}.
Seguidamente, explorámos falhas na validação de inputs através de uma
injeção de \textit{Null Byte} codificado (\texttt{\%2500.md} ou
\texttt{\%2500.pdf}). O ataque foi bem-sucedido e contornou a validação
de extensões do servidor, garantindo o acesso e descarregamento de
ficheiros confidenciais restritos: \texttt{encrypt.pyc} e
\texttt{suspicious\_errors.yml}.
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\textwidth]{suspiciouserrors}
\caption{suspiciouserrors}
\label{fig:suspiciouserrors}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\textwidth]{suspiciouserrors2}
\caption{suspiciouserrors2}
\label{fig:suspiciouserrors2}
\end{figure}
\subsection{Session Management Testing}
Identificámos que o cookie \texttt{token}, responsável por armazenar o
identificador da sessão ativa do utilizador, possui a flag
\texttt{HttpOnly} configurada como \texttt{false}. A ausência desta
proteção significa que o token está totalmente exposto e pode ser lido
por scripts do lado do cliente, tornando a sessão criticamente vulnerável
a roubo por Cross-Site Scripting (XSS).
\subsection{Input Validation Testing}
\subsubsection*{Testing for Reflected Cross Site Scripting}
Durante a auditoria à barra de pesquisa de produtos, validámos a
existência de uma vulnerabilidade de \textit{Reflected Cross-Site
Scripting} (XSS) devido à ausência de higienização do input do
utilizador.
\begin{enumerate}
\item \textbf{Injeção HTML:} Introduzimos o valor \texttt{apple} na pesquisa e verificámos que o resultado foi renderizado no navegador como um título estrutural, confirmando que o código HTML é injetado diretamente na página.
\item \textbf{Tentativa com Script Direto:} Inserimos o payload tradicional \texttt{apple}. Esta tentativa não foi executada, demonstrando a presença de uma validação simples contra tags explícitas de script.
\item \textbf{Evasão com Evento de Erro:} Para contornar a restrição, injetámos uma tag de imagem com um caminho inválido acompanhado do manipulador de eventos \texttt{onerror}:
\begin{codeblock}{html}
apple
\end{codeblock}
O filtro falhou ao inspecionar este atributo e o navegador executou o código JavaScript com sucesso quando a imagem falhou o carregamento.
\end{enumerate}
\subsubsection{Testing for SQL Injection}
Adicionalmente, explorámos o mesmo parâmetro de pesquisa recorrendo ao
\textit{sqlmap} para validar falhas de injeção SQL, conseguindo extrair
com sucesso a estrutura de 22 tabelas da base de dados:
\begin{codeblock}{bash}
sqlmap -u "http://10.60.0.1:3000/rest/products/search?q=apple" -p q --dbms=sqlite --prefix="'%" --suffix="%'--" --tables --batch
[22 tables]
+-----------------------+
| Addresses |
| BasketItems |
| Baskets |
| Captchas |
| Cards |
| ChallengeDependencies |
| Challenges |
| Complaints |
| Deliveries |
| Feedbacks |
| Hints |
| ImageCaptchas |
| Memories |
| PrivacyRequests |
| Products |
| Quantities |
| Recycles |
| SecurityAnswers |
| SecurityQuestions |
| Users |
| Wallets |
| sqlite_sequence |
+-----------------------+
\end{codeblock}
Apesar de não ter sido detetado pelo active scan foi feito fuzzing nos
detalhes de login para saber se estava vulneravel a esse tipo de ataques
visto que existia essa vulnerabilidade noutros paremetros. Verificamos
que de facto também estava vulneravel a SQL Injection, e que a resposta
era a tabela com o
\subsection{Testing for Error Handling}
Ao tentar forçar o acesso a uma página ou ficheiro inexistente no
servidor de ficheiros, como por exemplo na rota \texttt{/ftp/teste},
a aplicação falhou ao tratar a exceção de forma segura. Em vez de
apresentar uma página de erro genérica (404), o servidor devolveu uma
resposta detalhada expondo o \textit{stack trace} completo do ambiente
\textit{Express.js}, revelando caminhos internos do sistema de ficheiros
do servidor.
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\textwidth]{stack-trace}
\caption{stack-trace}
\label{fig:stack-trace}
\end{figure}
\subsection{Client Side Testing}
Validámos que o token de sessão (JWT) do utilizador autenticado está
armazenado diretamente no \texttt{localStorage} do navegador. Uma vez
que o \texttt{localStorage} não possui mecanismos de proteção
equivalentes à flag \texttt{HttpOnly} dos cookies, qualquer script
executado no contexto da página consegue ler estes dados.
Utilizando a falha de XSS identificada anteriormente na barra de pesquisas, injetámos o seguinte payload direcionado:
\begin{codeblock}{html}
apple
\end{codeblock}
A execução deste vetor permitiu extrair o conteúdo do token diretamente
do armazenamento local da vítima. Isto prova que um atacante pode
automatizar a exfiltração destas informações e assumir a identidade de
qualquer utilizador afetado sem necessitar de saber as credenciais de
acesso de forma persistente.
\section{Web Application Security Firewall}
\begin{codeblock}{modsecurity.conf}
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess Off
SecDebugLog /var/log/modsecurity/debug.log
SecDebugLogLevel 0
SecAuditLogParts ABIJ
SecAuditLogType Serial
SecAuditLog /var/log/modsecurity/audit.log
# sql injection
SecRule ARGS "['\";]|--" \
"id:950001,phase:2,deny,status:403,msg:'SQL Injection Attack Detected',log"
# xss / html injection
SecRule ARGS "<.*>" \
"id:950003,phase:2,deny,status:403,msg:'XSS/HTML Injection Detected',log"
# command injection
SecRule ARGS "(\"role\".*:.*\"admin\")|exec|cat|more|ls|dir|/etc/passwd" \
"id:950006,phase:2,deny,status:403,msg:'Command Injection Detected',log"
# path traversal
SecRule ARGS "(\./|\.\./)|ftp|metrics|api-docs" \
"id:950007,phase:2,deny,status:403,msg:'Path Traversal Attempt',log"
# exposed stuff
SecRule REQUEST_URI "ftp|metrics|api-docs" \
"id:950008,phase:2,deny,status:500,msg:'Attempt to access ftp, metrics, api-docs',log"
# rate limiting on login endpoint (max 5 requests per 30s per IP)
SecAction \
"id:950009,phase:1,initcol:ip=%{REMOTE_ADDR},pass,nolog"
SecRule REQUEST_URI "@streq /rest/user/login" \
"id:950010,phase:2,pass,nolog,setvar:ip.login_count=+1,expirevar:ip.login_count=30"
SecRule IP:LOGIN_COUNT "@gt 5" \
"id:950011,phase:2,deny,status:429,msg:'Rate Limit Exceeded on Login',log"
\end{codeblock}
\subsection{Information Gathering}
O acesso direto via URL (e.g., \texttt{/ftp}, \texttt{/metrics}, \texttt{/api-docs}) é
mitigado pela regra id:950008, que inspeciona o caminho do pedido (\texttt{REQUEST\_URI})
e devolve \texttt{500} ao bloquear qualquer acesso direto a estes endpoints!
A mitigação desta categoria é, portanto, completa ao nível de pedidos HTTP.
\subsection{Configuration and Deployment Management Testing}
A restrição de métodos HTTP e a validação de permissões de diretório requerem
intervenção ao nível do servidor Apache ou da aplicação, estando fora do âmbito
das regras \texttt{SecRule} definidas.
\subsection{Identity Management Testing}
A regra de XSS/injeção HTML (id:950003) bloqueia eficazmente o registo de utilizadores
com tags HTML nos campos de \textit{input}, como \texttt{STRONG}, devolvendo um erro
\texttt{403 Forbidden} antes que o pedido chegue à aplicação.
A vulnerabilidade de escalonamento de permissões (injeção do campo
\texttt{"role":"admin"} no corpo JSON do registo) \textbf{é mitigada
pela regra id:950006}, que deteta a sequência
\texttt{"role".*:.*"admin"} nos argumentos do pedido e devolve
\texttt{403 Forbidden}, impedindo a criação de contas com perfil de
administrador. A enumeração de contas via mensagens de erro da aplicação
permanece sem mitigação ao nível da WAF.
\subsection{Authentication Testing}
As regras id:950009--950011 implementam um mecanismo de \textit{rate limiting} sobre o
endpoint de autenticação (\texttt{/rest/user/login}). Para cada endereço IP, é mantido
um contador de pedidos com janela deslizante de 30 segundos: ao ultrapassar 5 tentativas
nessa janela, o servidor devolve \texttt{429 Too Many Requests}, bloqueando eficazmente
ataques de \textit{brute force} por dicionário. O bloqueio de contas após múltiplas
tentativas falhadas permanece fora do âmbito da WAF, exigindo lógica aplicacional.
\subsection{Authorization Testing}
O ataque de \textit{Null Byte} (\texttt{\%2500.pdf}) utilizado para
contornar a validação de extensões de ficheiro no diretório
\texttt{/ftp} não é diretamente mitigado pelas regras configuradas,
pois o payload não contém nenhum dos padrões definidos (e.g.,
\texttt{../}, \texttt{ftp} como argumento). A regra id:950007 teria de
ser estendida para incluir sequências de \textit{null byte} codificadas
(\texttt{\%00}, \texttt{\%2500}) para cobrir este vetor de ataque.
\subsection{Session Management Testing}
A configuração da WAF não tem capacidade de alterar os atributos dos
cookies definidos pela aplicação. A flag \texttt{HttpOnly} do cookie
\texttt{token} continua ausente, uma vez que esta é uma propriedade
definida pela camada aplicacional do \textit{JuiceShop}. Ainda assim,
a mitigação do XSS (id:950003), descrita na subsecção seguinte, reduz
indiretamente o risco de roubo de sessão ao bloquear os vetores que
permitiriam a sua exploração.
\subsection{Input Validation Testing}
A regra de SQL Injection (id:950001) bloqueia com sucesso pedidos ao
endpoint de pesquisa de produtos que contenham caracteres como
\texttt{'}, \texttt{"}, \texttt{;} ou a sequência \texttt{--},
devolvendo \texttt{403 Forbidden}. O payload utilizado pelo
\textit{sqlmap} é interceptado nesta fase, impedindo a extração de dados
da base de dados. A regra de XSS/injeção HTML (id:950003) bloqueia
igualmente os payloads com tags
\texttt{
} e \texttt{}, neutralizando
ambos os vetores de \textit{Reflected XSS} identificados na primeira
etapa.
\subsection{Testing for Error Handling}
A WAF atua sobre os pedidos antes de estes chegarem à aplicação, mas
não filtra as respostas do servidor, uma vez que a diretiva
\texttt{SecResponseBodyAccess} se encontra configurada como
\texttt{Off}. Por consequência, a exposição do \textit{stack trace} do
\textit{Express.js} em rotas inexistentes (e.g., \texttt{/ftp/teste})
não é mitigada. Para suprimir respostas de erro detalhadas seria
necessário ativar a inspeção do corpo da resposta e definir regras sobre
o seu conteúdo, ou configurar páginas de erro personalizadas no Apache.
\subsection{Client Side Testing}
O payload de exfiltração do token JWT via XSS
(\texttt{
})
é bloqueado pela regra id:950003, uma vez que contém a expressão
\texttt{<.*>} nos argumentos do pedido de pesquisa. Desta forma, a
cadeia de ataque identificada na primeira etapa --- que combinava a
falha de XSS com o armazenamento inseguro do token --- é eficazmente
neutralizada pela WAF ao nível da injeção inicial, impedindo a execução
do código malicioso no contexto do navegador da vítima.
\section{Conclusions}
\end{document}