\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 On SecDebugLog /var/log/modsecurity/debug.log SecDebugLogLevel 0 SecAuditLogParts ABIJ SecAuditLogType Serial SecAuditLog /var/log/modsecurity/audit.log # sql injection SecRule REQUEST_URI|ARGS "['\";]|--" \ SecRule REQUEST_URI|ARGS "(?i:(?:select|insert|update|delete|drop|union|create|alter|truncate)\s+.+\s+from|'[^']*'|--|;|\b(or|and)\b\s+\d+\s*=\s*\d+)" \ "id:950001,phase:1,deny,status:403,msg:'SQL INJECTION ATTACK DETECTED!!!',log,t:urlDecode,t:sqlHexDecode,t:lowercase" # xss / html injection SecRule REQUEST_URI|ARGS "(<.*>)|(%3C.*%3E)" \ "id:950003,phase:1,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 REQUEST_URI|ARGS "\%00|\%2500|\.\./|ftp|metrics|api-docs" \ "id:950007,phase:2,deny,status:403,msg:'PATH TRAVERSAL ATTEMPT!!!',log" # exposed stuff (redundante ?) SecRule REQUEST_URI|ARGS "\%00|\%2500|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 \textbf{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} A regra id:950007 e id:950008 bloqueiam o uso de \textit{null byte} codificadas 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. Logo, a flag \texttt{HttpOnly} do cookie \texttt{token} continua ausente, uma vez que esta é uma propriedade definida pelo \textit{JuiceShop}. Ainda assim, a mitigação do XSS pela regra 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} ou por outros fuzzers com \textit{SQL injections} são interceptado nesta fase. A regra de XSS/injeção HTML (id:950003) bloqueia igualmente os payloads com tags \texttt{} e \texttt{

}, neutralizando ambos estes vetores de ataque. \subsection{Testing for Error Handling} A exposição do \textit{stack trace} do \textit{Express.js} em rotas inexistentes (e.g., \texttt{/ftp/teste}) aind não é mitigada. Para suprimir estas respostas de erro detalhadas era 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{<.*>}. \section{Conclusions} Foi feita uma análise extensa dos possiveis vetores de ataque da aplicação e com isso desenvolvemos uma \textbf{WAF} que cobriu uma maioria dos ataques. Contudo, as vulnerabilidades estruturais da aplicação, como a ausência de flags \texttt{HttpOnly} em cookies, a lógica de enumeração de utilizadores e a exposição de \textit{stack traces}, competem diretamente ao desenvolvimento seguro do código e à configuração do web server. Em suma, com poucas regras simples foi possible bloquear a maioria das ameaças de injeção de código malicioso, no entanto, para cobrir uma maior superficie de ataques seria necessário mudar a lógica interna da aplicação. \end{document}