Compare commits

...

71 Commits

Author SHA1 Message Date
vasco
81e6fb8aa4 rip 2026-06-03 11:43:39 +01:00
vasco
ab3cbb9081 the council 2026-06-03 11:39:05 +01:00
vasco
a6860e338d kys20 2026-06-03 11:32:02 +01:00
vasco
30a9483402 kys18 2026-06-02 23:57:15 +01:00
vasco
bc450ebbb3 kys17 2026-06-02 23:46:21 +01:00
vasco
0992d4a6e0 kys16 2026-06-02 23:38:20 +01:00
vasco
c053a064b2 kys15 2026-06-02 23:28:02 +01:00
vasco
cfa62d8ce0 kys14 2026-06-02 23:22:37 +01:00
vasco
0f3e2044a0 kys13 2026-06-02 23:20:25 +01:00
vasco
e9616a8c7c kys12 2026-06-02 23:10:52 +01:00
vasco
361f34c19f kys11 2026-06-02 22:49:55 +01:00
vasco
1f6bb854c3 kys10 2026-06-02 22:44:16 +01:00
vasco
05cbbfbe18 kys9 2026-06-02 22:16:25 +01:00
vasco
ad84c1ba29 kys8 2026-05-31 22:40:18 +01:00
jelly Tomas
53c4898efe kys7 2026-05-31 22:00:19 +01:00
vasco
c7b5f0e436 oops 2026-05-31 21:53:41 +01:00
vasco
51060422d1 kys6 2026-05-31 21:42:41 +01:00
e3d7b83059 mod security 2026-05-31 20:11:27 +01:00
73c5b1c5d5 kys4 2026-05-31 19:47:48 +01:00
vasco
aa58c0cb1d kys3 2026-05-31 19:30:39 +01:00
vasco
183901ab31 kys2 2026-05-31 19:11:32 +01:00
vasco
3e0237c6f3 httpd 2026-05-31 19:04:42 +01:00
vasco
e90263b3c5 kys 2026-05-31 18:50:32 +01:00
vasco
f69d1d3b38 son ;( 2026-05-31 18:37:17 +01:00
vasco
00f537bc3a fixed 4 (the return of the family) 2026-05-31 15:26:31 +01:00
vasco
c528f4844b fixed 3 (for real this time) 2026-05-31 15:24:32 +01:00
vasco
fdc85d9109 syntax error? 2026-05-31 15:18:35 +01:00
vasco
8136c49f50 fix 2026-05-31 15:16:13 +01:00
vasco
ded74f1a45 modsecurity 2026-05-31 14:55:52 +01:00
vasco
a17feb0e1b Merge 2026-05-31 13:35:20 +01:00
vasco
89b17901a9 hmmmmm 2026-05-31 13:14:42 +01:00
jelly Tomas
5059041ec7 Batman added 2026-05-31 13:05:19 +01:00
vasco
9b38b6385b erros de formatcao 2026-05-30 22:05:26 +01:00
vasco
bd0f136ccc pdf 2026-05-30 22:02:31 +01:00
vasco
21c9633755 relatorio 2026-05-30 21:38:33 +01:00
vasco
6cd77929f4 introducao 2026-05-29 20:45:43 +01:00
2b76e850a5 Testes Realizados sem Firewall 2026-05-28 13:02:16 -04:00
vasco
2f44f7327d mais coisas 2026-05-26 14:24:13 +01:00
vasco
8ee1c901fe movi webserver para o firewall 2026-05-26 13:37:17 +01:00
vasco
b4ff1c0018 owasp zap 2026-05-23 20:14:21 +01:00
vasco
7a5767ef64 fix 2026-05-23 14:24:00 +01:00
vasco
ddcaf33130 fix? 2026-05-23 13:20:24 +01:00
vasco
a20876fb1e web server fix 2026-05-23 13:01:06 +01:00
vasco
e38f655080 comeÃo 2026-05-18 11:45:48 +01:00
vasco
66534a1648 assignment 3 enunciado 2026-05-11 11:38:51 +01:00
vasco
b03a6987f4 entrega 2026-05-11 11:20:47 +01:00
jelly Tomas
e0fa8291fe I am chudding out 2026-05-03 11:29:26 +01:00
jelly Tomas
3225a90f1e I am chudding out 2026-05-03 11:28:49 +01:00
jelly Tomas
553f6ece60 I am such a chub. *splaps big fat belly.* 2026-05-02 22:44:49 +01:00
jelly Tomas
0c1bade0f2 I am such a chud. 2026-05-01 23:39:16 +01:00
jelly Tomas
f8597d72f9 Fuck...... 2026-05-01 22:55:07 +01:00
jelly Tomas
c277f65fb5 Cooked. 2026-04-29 20:34:13 +01:00
Vasco
9656c2bee4 oops 2026-04-28 17:42:17 +01:00
Vasco
96c9666a89 praying 2026-04-28 16:11:26 +01:00
jelly Tomas
1de30d80d0 FIXED 2026-04-28 12:55:30 +01:00
Vasco
288b10550c kill me 2026-04-28 11:20:26 +01:00
Vasco
0b337a2117 fixed? 2026-04-28 00:53:37 +01:00
Vasco
37bb4821e3 fix 2026-04-28 00:45:26 +01:00
Vasco
79d62754a3 merginton 2026-04-28 00:19:02 +01:00
Vasco
7cae69b945 OCSP atualizado 2026-04-28 00:18:28 +01:00
jelly Tomas
c175b85239 Fuck... 2026-04-28 00:04:30 +01:00
jelly Tomas
c31c4602f2 Fuck... 2026-04-28 00:04:02 +01:00
Vasco
10e2db0f38 grupo totp 2026-04-27 23:24:27 +01:00
Vasco
53e24aa2ea http redirect 2026-04-27 22:24:14 +01:00
Vasco
a0fbbe210d relatorio: vpn gateway 2026-04-27 20:44:27 +01:00
Vasco
ddb5ad81ac hmmmm4 2026-04-27 13:21:58 +01:00
jelly Tomas
5bd7355e8b I guess its a merge 2026-04-25 21:07:05 +01:00
jelly Tomas
f1f40e9ebb Changed one line 2026-04-25 21:06:27 +01:00
Vasco
ebc05382b3 EURETHRA! 2026-04-25 19:11:44 +01:00
Vasco
eb5a014949 npsec 2026-04-25 18:13:21 +01:00
Vasco
457018b127 www 2026-04-25 17:28:37 +01:00
122 changed files with 12447 additions and 793 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.log
*.aux
*.synctex.gz

18
CLIENT.sh Normal file
View File

@@ -0,0 +1,18 @@
#/bin/bash
# CONFIGURACAO DO CLIENTE
# (KALI LINUX)
function instalar() {
apt list installed "$1" &>/dev/null && echo "$1 já instalado" || sudo apt install -y "$1"
}
IP="20.60.0.2"
sudo ifconfig eth1 $IP netmask 255.255.255.0
sudo route add default gw 20.60.0.1
sudo apt update
instalar zaproxy
# exploits

View File

@@ -1,6 +1 @@
# Coisas para leres que sao fixes wowowowowowow !!!!! (Assignment 2)
- Os slides (duh)
- Okay o mais importante é os slides.
- [X.509 (ssl.com)](https://www.ssl.com/faqs/what-is-an-x-509-certificate/)
- [X.509 (youtube)](https://www.youtube.com/watch?v=kAaIYRJoJkc)
kys

66
SERVER.sh Normal file
View File

@@ -0,0 +1,66 @@
#!/bin/bash
# SERVIDOR INTERNO
# (CentOS 9)
alias "s"="sudo systemctl"
function instalar() {
yum list installed "$1" &>/dev/null && echo "$1 já instalado" || sudo yum install -y "$1"
}
IP_EXTERNAL="20.60.0.1"
IP_INTERNAL="10.60.0.1"
sudo ifconfig enp0s8 $IP_EXTERNAL netmask 255.255.255.0
sudo ifconfig enp0s9 $IP_INTERNAL netmask 255.255.255.0
# instalar packages
if ! command -v node &> /dev/null || [[ "$(node -v)" != v24.* ]]; then
echo "Configurando repositório do Node.js 24..."
curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash -
sudo yum remove -y nodejs
fi
instalar nodejs
# instalar mod security e apache
instalar epel-release
instalar httpd
instalar mod_security
instalar iptables-services
s stop firewalld
s disable firewalld
s mask firewalld
s enable iptables
sudo iptables -F
# nat
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -F
sudo iptables -A FORWARD -i enp0s9 -o enp0s8 -j ACCEPT
sudo iptables -A FORWARD -i enp0s8 -o enp0s9 -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o enp0s8 -j MASQUERADE
sudo iptables-save > /etc/sysconfig/iptables
sudo cp conf/httpd.conf /etc/httpd/conf/httpd.conf
sudo cp conf/modsecurity.conf /etc/httpd/conf/modsecurity.conf
sudo mkdir -p /var/log/modsecurity/
sudo rm -f /etc/httpd/conf.d/mod_security.conf
sudo rm -f /etc/httpd/modsecurity.d/*.conf
# instalar juice-shop se nao existir
jspath="/var/juice-shop"
if [[ ! -f "$jspath/package.json" ]]; then
sudo mkdir -p "$jspath"
curl -L -o js.tar.gz "https://github.com/juice-shop/juice-shop/releases/download/v20.0.0/juice-shop-20.0.0_node24_linux_x64.tgz"
sudo tar -xzvf js.tar.gz -C "$jspath" --strip-components=1
rm js.tar.gz
sudo chown -R $USER:$USER "$jspath"
fi
sudo systemctl stop httpd
# correr juice shop via npm
cd "$jspath"
npm start &
httpd -X

View File

@@ -1,7 +0,0 @@
# Objectivos de acordo com o enunciado
## Goals
- [X] Configure a tunnel in the "road warrior"
- [ ] Enable two factor authentication with OpenSSL and Apache services
- [ ] Manage PKI: certification authorities, X.509 certificates, revocation and OCSP.

8
VM_CONFIG.sh → assignment2/VM_CONFIG.sh Executable file → Normal file
View File

@@ -7,7 +7,7 @@ if [[ "$USER" != "root" ]]; then
fi
yum install -y epel-release
yum install -y openvpn iptables-services dhcp-client
yum install -y openvpn iptables-services dhcp-client ntpsec
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
@@ -28,9 +28,3 @@ mkdir -p /etc/openvpn/client
systemctl stop chronyd
ntpdate pool.ntp.org
systemctl start chronyd
# NOTE(vasco): o openvpn não consegui aceder ao home e ler os secrets
# do google authenticator, por isso fiz isto:
mkdir -p /etc/systemd/system/openvpn-server@.service.d
echo -e "[Service]\nProtectHome=false" > /etc/systemd/system/openvpn-server@.service.d/override.conf
systemctl daemon-reload

View File

@@ -5,6 +5,11 @@ source VM_CONFIG.sh
sudo yum install -y epel-release
sudo yum install -y openssl httpd mod_ssl mod_authnz_pam google-authenticator
sudo yum install -y mod_session
# utilizador
id -u john &>/dev/null || useradd john
echo "password" | passwd --stdin john
if_dentro="enp0s8"
ip_dentro="10.60.0.1"
@@ -26,28 +31,22 @@ cp ca/dh2048.pem $CA_DIR
killall openssl 2>/dev/null
openssl ocsp -index $CA_DIR/index.txt -port 8888 -rsigner $CA_DIR/ca.crt -rkey $CA_DIR/ca.key -CA $CA_DIR/ca.crt -text &
# apache
mkdir -p /etc/httpd/ssl
cp ca/ca.crt /etc/httpd/ssl/
cp ca/apache.crt /etc/httpd/ssl/
cp ca/apache.key /etc/httpd/ssl/
cp conf/ssl.conf /etc/httpd/conf.d/ssl.conf
cp conf/httpd.conf /etc/httpd/conf/httpd.conf
cp conf/httpd-totp /etc/pam.d/httpd-totp
# NOTA(vasco) é preciso desativar home protection outra vez
mkdir -p /etc/systemd/system/httpd.service.d
echo -e "[Service]\nProtectHome=false" > /etc/systemd/system/httpd.service.d/override.conf
systemctl daemon-reload
# sim, é preciso fazer isto para carregar serviços
echo "LoadModule session_module modules/mod_session.so" > /etc/httpd/conf.modules.d/01-session.conf
echo "LoadModule session_cookie_module modules/mod_session_cookie.so" >> /etc/httpd/conf.modules.d/01-session.conf
echo "LoadModule auth_form_module modules/mod_auth_form.so" > /etc/httpd/conf.modules.d/01-auth_form.conf
# serviço !!!
systemctl enable --now httpd
# mega paginas webs
cp -r www/* /var/www/html/
chown -R apache:apache /var/www/html/
# acho ?????
sudo chgrp apache /etc/shadow
sudo chmod o+x /home/john
sudo chown apache /home/john/.google_authenticator
sudo chmod 400 /home/john/.google_authenticator
sudo chmod o+x /home/user
sudo chown apache /home/user/.google_authenticator
sudo chmod 400 /home/user/.google_authenticator
httpd -X

View File

@@ -16,4 +16,5 @@ cp ca/ca.crt $vpn_dir
cp ca/user.key $vpn_dir
cp ca/user.crt $vpn_dir
cp conf/client.conf $vpn_dir
openvpn --config "${vpn_dir}/client.conf"

View File

@@ -8,7 +8,6 @@
source VM_CONFIG.sh
yum install -y google-authenticator qrencode ntpsec
# --- forwarding --- #
if_fora="enp0s8"
ip_fora="193.136.212.1"
@@ -23,13 +22,13 @@ ifconfig $if_dentro $ip_dentro netmask 255.255.255.0
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT # :O
iptables -I FORWARD 1 -i $mega_tunel -o $if_dentro -j ACCEPT # :P
iptables -I FORWARD 1 -i $if_dentro -o $mega_tunel -j ACCEPT # ;)
iptables -I FORWARD 1 -i $mega_tunel -o $if_fora -j ACCEPT # faltava isto ?
iptables -I FORWARD 1 -i $if_fora -m state --state ESTABLISHED,RELATED -j ACCEPT # faltava isto ?
iptables -t nat -A POSTROUTING -s $ip_mega_tunel -o $if_fora -j MASQUERADE # :D
iptables-save > /etc/sysconfig/iptables # :3
iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT
iptables -I FORWARD 1 -i $mega_tunel -o $if_dentro -j ACCEPT
iptables -I FORWARD 1 -i $if_dentro -o $mega_tunel -j ACCEPT
iptables -I FORWARD 1 -i $mega_tunel -o $if_fora -j ACCEPT
iptables -I FORWARD 1 -i $if_fora -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $ip_mega_tunel -o $if_fora -j MASQUERADE
iptables-save > /etc/sysconfig/iptables
# --- vpn server --- #
vpn_dir="/etc/openvpn/server"
@@ -41,4 +40,9 @@ cp ca/dh2048.pem $vpn_dir
cp conf/vpn.conf $vpn_dir
cp conf/ocsp-verify.sh $vpn_dir
cp conf/totp /etc/pam.d/
systemctl enable --now openvpn-server@vpn.service
# --- utilizador --- #
id -u john &>/dev/null || useradd john
echo "password" | passwd --stdin john
openvpn --config /etc/openvpn/server/vpn.conf

View File

0
ca/revoke_user.sh → assignment2/ca/revoke_user.sh Executable file → Normal file
View File

View File

@@ -0,0 +1,20 @@
ServerRoot "/etc/httpd"
Include conf.modules.d/*.conf
LoadModule authnz_pam_module modules/mod_authnz_pam.so
LoadModule mpm_event_module modules/mod_mpm_event.so
User apache
Group apache
Listen 80
Listen 443
Include conf.d/*.conf
DocumentRoot "/var/www/html"
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>

View File

@@ -0,0 +1,15 @@
#!/bin/bash
depth=$1
if [ "$depth" -eq 0 ]; then
if [ -n "$tls_serial_0" ]; then
# é preciso converter o serial para hexadecimal porque o openssl espera em hex
hex_serial=$(printf '%x' "$tls_serial_0")
status=$(openssl ocsp -issuer /etc/openvpn/server/ca.crt -serial "0x$hex_serial" -url http://10.60.0.1:8888 -CAfile /etc/openvpn/server/ca.crt 2>/dev/null)
if echo "$status" | grep -q "good"; then
exit 0 # sucesso
fi
exit 1 # revogado ou não encontrado
fi
exit 1
fi

64
assignment2/conf/ssl.conf Normal file
View File

@@ -0,0 +1,64 @@
<VirtualHost *:443>
ServerName 10.60.0.1
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/apache.crt
SSLCertificateKeyFile /etc/httpd/ssl/apache.key
SSLCACertificateFile /etc/httpd/ssl/ca.crt
# mutual authentication
SSLVerifyClient require
SSLVerifyDepth 1
# ocsp validation
SSLOCSPEnable on
SSLOCSPDefaultResponder "http://10.60.0.1:8888"
SSLOCSPOverrideResponder on
SSLOCSPUseRequestNonce off
# session management
Session On
SessionCookieName session path=/;HttpOnly;Secure
# proteger
<Location "/">
AuthType Form
AuthName "Coimbra VPN"
AuthFormProvider PAM
AuthPAMService httpd-totp
AuthFormLoginRequiredLocation "/login.html"
Require valid-user
</Location>
# public login page
<Location "/login.html">
AuthType None
Require all granted
</Location>
# login handler
<Location "/dologin">
SetHandler form-login-handler
AuthType Form
AuthName "Coimbra VPN"
AuthFormProvider PAM
AuthPAMService httpd-totp
Require all granted
AuthFormLoginSuccessLocation "/index.html"
AuthFormLoginRequiredLocation "/login.html?error=1"
</Location>
# logout handler
<Location "/logout">
SetHandler form-logout-handler
AuthFormLogoutLocation "/login.html?loggedout=1"
</Location>
</VirtualHost>
# redirect para https
<VirtualHost *:80>
ServerName 10.60.0.1
Redirect permanent / https://10.60.0.1/
</VirtualHost>

View File

@@ -3,16 +3,16 @@ port 1194
proto udp
dev tun
verb 4
# Bro is too honorable
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/vpn.crt
key /etc/openvpn/server/vpn.key
dh /etc/openvpn/server/dh2048.pem
server 10.8.0.0 255.255.255.0
verb 4
topology subnet
server 10.8.0.0 255.255.255.0
push "route 10.60.0.0 255.255.255.0"
# OCSP and Revocation

BIN
assignment2/entrega.zip Normal file

Binary file not shown.

4702
assignment2/entrega.zip.asc Normal file

File diff suppressed because it is too large Load Diff

BIN
assignment2/enunciado.pdf Normal file

Binary file not shown.

143
assignment2/enunciado.txt Normal file
View File

@@ -0,0 +1,143 @@
FSI 2025/2026
Practical Assignment #2
1. Goals
Configure a VPN tunnel in the “road warrior” scenario.
Enable two-factor user authentication with OpenVPN and Apache services.
Manage PKI: certification authorities, X.509 certificates, revocation and OCSP.
2. General description
Figure 1 illustrates the scenario considered for our practical assignment. As illustrated, secure communications are
supported by a VPN tunnel established between a remote client (road warrior) and the VPN gateway, with the purpose of
enabling accesses to services in the Internal Network, particularly a web server running Apache. To enable the VPN tunnel,
we will use OpenVPN (https://openvpn.net).
Figure 1 Scenario for the Practical Assignment #1
Regarding authentication, the two communication entities participating in the VPN tunnel (road warrior and the VPN
gateway) should possess valid X.509 certificates, which are created with a private Certification Authority (CA). Users
establishing remote connections to the VPN gateway (road warriors), as well as users connecting to the Apache server, will
also use two-factor authentication, as described below. Apache must also implement client authentication via X.509
certificates. Figure 2 provides an illustration of the interactions between all the entities involved in this setup.
Figure 2 X.509 mutual authentication and OCSP
As we can observe in Figure 2, the VPN gateway and the Apache web server must verify the status of validity of certificates
using OCSP (Online Certificate Status Protocol) and revocation information from the CA. OCSP verification in not
required for the road warrior. Next, we describe the configuration requirements for the various components of the
assignment.
3. Configuration requirements
VPN tunnel for remote access (road warriors)
As illustrated in Figure 1, remote clients (road warriors) are able to connect to the Coimbra VPN gateway, and using the
tunnel remotely access hosts in the Internal network. The following configuration requirements should be considered:
In order to establish a VPN tunnel with the Coimbra gateway, the road warrior must be in the possession of a valid
X.509 certificate, issued by the private CA of the scenario.
The road warrior and the Coimbra VPN gateway must perform mutual authentication using X.509 digital certificates.
The Coimbra VPN gateway should verify the validity of the X.509 certificate presented by the road warrior using OCSP
and, in case the certificate is revoked, the gateway should refuse the connection.
In order to authorize the remote user, the Coimbra gateway should also enforce two other authentication steps: the user
must present a valid username and password, plus a one-time password (OTP, or an authentication token).
Web server
2
The road warrior user should be able to contact the Apache web server with HTTPS through the VPN tunnel. The
following configuration requirements should be considered:
Apache should enforce two-factor authentication in order to authorize accesses from clients: the client (browser) should
present a valid X.509 certificate (issued with the private CA of the scenario) and the user should also present a valid onetime password (or authentication token).
As in the VPN, the validity of the X.509 certificate presented by the client should be checked in the CA using OCSP.
Two-factor user authentication
As previously discussed, VPN establishment and HTTPS accesses to Apache make use of one-time passwords
(authentication tokens), which may be generated by an appropriate application. One-time passwords may be generated using
the TOTP (Time-based One-time Password Algorithm). This algorithm employs a secret key shared between the user
(client) and the remote service, plus a timestamp (obtained from the current system time), to obtain a one-time password.
In order to generate a one-time password, the user may use an application such as Google Authenticator, illustrated in
Figure 3. This application periodically generates a new one-time password that can be used to authenticate the user with the
remote service. This application is available for iOS and Android 1.
Certification authority
As already discussed, the goal is to use OpenSSL to configure a private Certification Authority, as well as to issue and revoke
X.509 digital certificates for the VPN gateways and remote users. The following configuration requirements should be
considered:
The Certification Authority is used to issue certificates for the VPN gateway, VPN client and Apache web server.
The Certification Authority allows the revocation of certificates previously issued.
The Certification Authority also supports a OCSP responder.
For Android: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en and
for Apple iOS: https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8
1
3
Figure 3 Google Authenticator app, to generate a one-time password to access services enabled with two-factor authentication
4. Delivery of the Practical Assignment
With the assignment, please deliver also a report, containing the following information:
Descriptions of the configurations for the implementation of the previous requirements.
A description of how the private Certification Authority was created using OpenSSL.
A description of how X.509 certificates were issued and revoked using the private Certification Authority.
A description of the tests performed to validate the functionalities implemented.
Remaining information considered relevant.
For the delivery of the assignment, put your report, as well as the relevant configuration files, in a single archive. This archive
should be signed using your PGP key and encrypted using the PGP key of your PL teacher.
Note: Assignments without PGP will be accepted, although with a discount of 5% in the final grade.
Delivery deadline:
The deadline for the delivery of the assignment (configuration files and report) is May 3rd 2026.
Submission via Inforestudante.
4

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,27 @@
\relax
\providecommand \babel@aux [2]{\global \let \babel@toc \@gobbletwo }
\@nameuse{bbl@beforestart}
\catcode `"\active
\providecommand\hyper@newdestlabel[2]{}
\providecommand\HyField@AuxAddToFields[1]{}
\providecommand\HyField@AuxAddToCoFields[2]{}
\babel@aux{portuguese}{}
\@writefile{toc}{\contentsline {section}{\numberline {1}Introdução}{3}{section.1}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {2}Preparação Inicial}{3}{section.2}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Criação de Certificados}{3}{subsection.2.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Configuração geral}{4}{subsection.2.2}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {3}VPN Gateway}{5}{section.3}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Configuração da Máquina}{5}{subsection.3.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Configuração do Serviço OpenVPN}{6}{subsection.3.2}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Erros}{7}{subsection.3.3}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.4}Configurar o utilizador com TOTP}{7}{subsection.3.4}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {4}VPN Client (Road Warrior)}{8}{section.4}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Configuração da Máquina}{8}{subsection.4.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Configuração do Cliente OpenVPN}{8}{subsection.4.2}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.3}Testes}{9}{subsection.4.3}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {5}Servidor Apache e OCSP}{9}{section.5}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {5.1}Configuração da Máquina}{10}{subsection.5.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.1}Testes}{12}{subsubsection.5.1.1}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {6}Teste Integrado}{13}{section.6}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {7}Conclusão}{13}{section.7}\protected@file@percent }
\gdef \@abspage@last{13}

View File

@@ -0,0 +1 @@
openssl ca -revoke user.crt -config cheese.cfg -keyfile ca.key -cert ca.crt

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
\BOOKMARK [1][-]{section.1}{\376\377\000I\000n\000t\000r\000o\000d\000u\000\347\000\343\000o}{}% 1
\BOOKMARK [1][-]{section.2}{\376\377\000P\000r\000e\000p\000a\000r\000a\000\347\000\343\000o\000\040\000I\000n\000i\000c\000i\000a\000l}{}% 2
\BOOKMARK [2][-]{subsection.2.1}{\376\377\000C\000r\000i\000a\000\347\000\343\000o\000\040\000d\000e\000\040\000C\000e\000r\000t\000i\000f\000i\000c\000a\000d\000o\000s}{section.2}% 3
\BOOKMARK [2][-]{subsection.2.2}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000\347\000\343\000o\000\040\000g\000e\000r\000a\000l}{section.2}% 4
\BOOKMARK [1][-]{section.3}{\376\377\000V\000P\000N\000\040\000G\000a\000t\000e\000w\000a\000y}{}% 5
\BOOKMARK [2][-]{subsection.3.1}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000\347\000\343\000o\000\040\000d\000a\000\040\000M\000\341\000q\000u\000i\000n\000a}{section.3}% 6
\BOOKMARK [2][-]{subsection.3.2}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000\347\000\343\000o\000\040\000d\000o\000\040\000S\000e\000r\000v\000i\000\347\000o\000\040\000O\000p\000e\000n\000V\000P\000N}{section.3}% 7
\BOOKMARK [2][-]{subsection.3.3}{\376\377\000E\000r\000r\000o\000s}{section.3}% 8
\BOOKMARK [2][-]{subsection.3.4}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000r\000\040\000o\000\040\000u\000t\000i\000l\000i\000z\000a\000d\000o\000r\000\040\000c\000o\000m\000\040\000T\000O\000T\000P}{section.3}% 9
\BOOKMARK [1][-]{section.4}{\376\377\000V\000P\000N\000\040\000C\000l\000i\000e\000n\000t\000\040\000\050\000R\000o\000a\000d\000\040\000W\000a\000r\000r\000i\000o\000r\000\051}{}% 10
\BOOKMARK [2][-]{subsection.4.1}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000\347\000\343\000o\000\040\000d\000a\000\040\000M\000\341\000q\000u\000i\000n\000a}{section.4}% 11
\BOOKMARK [2][-]{subsection.4.2}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000\347\000\343\000o\000\040\000d\000o\000\040\000C\000l\000i\000e\000n\000t\000e\000\040\000O\000p\000e\000n\000V\000P\000N}{section.4}% 12
\BOOKMARK [2][-]{subsection.4.3}{\376\377\000T\000e\000s\000t\000e\000s}{section.4}% 13
\BOOKMARK [1][-]{section.5}{\376\377\000S\000e\000r\000v\000i\000d\000o\000r\000\040\000A\000p\000a\000c\000h\000e\000\040\000e\000\040\000O\000C\000S\000P}{}% 14
\BOOKMARK [2][-]{subsection.5.1}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000\347\000\343\000o\000\040\000d\000a\000\040\000M\000\341\000q\000u\000i\000n\000a}{section.5}% 15
\BOOKMARK [3][-]{subsubsection.5.1.1}{\376\377\000T\000e\000s\000t\000e\000s}{subsection.5.1}% 16
\BOOKMARK [1][-]{section.6}{\376\377\000T\000e\000s\000t\000e\000\040\000I\000n\000t\000e\000g\000r\000a\000d\000o}{}% 17
\BOOKMARK [1][-]{section.7}{\376\377\000C\000o\000n\000c\000l\000u\000s\000\343\000o}{}% 18

Binary file not shown.

View File

@@ -0,0 +1,575 @@
\documentclass[11pt,a4paper]{article}
\usepackage[portuguese]{babel}
\usepackage[lining]{ebgaramond}
\usepackage{style}
\setlength{\parindent}{0em}
\setlength{\parskip}{2ex}
\title{Practical Assignment \#2}
\author{
João Neto -- 2023234004\\[1em]
Vasco Alves -- 2022228207
}
\begin{document}
\maketitle
\newpage
\tableofcontents
\newpage
\section{Introdução}
Este projeto tem como âmbito implementar, uma rede virtual privada (VPN) num cenário
de road-warrior, configurar \textit{two-factor authentication} (2FA) com os serviços
OpenVPN e Apache, e gerir certificados X.509 utilizando OCSP.
% NOTE(vasco): Eu acho que basta explicar o cenario e explicar como decidimos
% implementar <- yeah agree, also esta introdução acho que é boa fala sobre o objetivo
% e o cenario, e porque é que o nosso cenario é como é. Não sei se a parte das razões de
%segurança devia estar nesta parte ou na conclusão como perpetiva futura e reflexão, mas aqui
%também não está mal.
% Para tal, foi implementado um servidor e um cliente OpenVPN, certificados por uma
% autoridade central (CA) que em si é \textit{self-signed}. Para além disto, foi implementado
% um sistema de autenticação de dois factores através do plugin
% \textit{google-authenticator} para o OpenVPN e para o servidor de Apache.
Decidimos utilizar apenas três máquinas virtuais: o cliente (ou \textit{road warrior}),
a \textit{gateway} que utiliza OpenVPN e um servidor interno com OpenSSL e Apache.
Isto simplifica a elaboração do projecto, mas por razões de segurança poderia querer
separar a máquina de OpenSSL de outras máquinas destinadas a serviços da rede interna,
pois esta contém o \textit{certificate authority} (CA).
% Ambos o OpenVPN eo servidor Apache utilizam 2FA,
% recebendo o utilizador, e uma password que é uma concatenação da palavra-passe do utilizador
% e de uma password temporária (TOTP) de 6 dígitos. O servidor de Apache implementa a mesma autenticação.
\begin{tabular}{l l l}
{\bf Nome} & {\bf Script} & {\bf Rede} \\\toprule
Road Warrior & VM\_ROAD\_WARRIOR.sh & Rede Externa 193.168.0.0/24 \\
VPN Gateway & VM\_OPENVPN\_GATEWAY.sh & Router \\
OpenSSL / Apache & VM\_OPENSSL\_APACHE.sh & Rede Interna 10.60.0.0/24 \\
\end{tabular}
\section{Preparação Inicial}
\subsection{Criação de Certificados}
Os certificados utilizados foram auto-certificados por uma autoridade central que ``pertence''
à máquina de OpenSSL. Esta mesma faz a gestão da lista de revogação.
Todas as chaves foram criadas no mesmo computador, com as variáveis que estão
neste código. Aspetos importantes para mais tarde serão os parâmetros de Comon Name (CN)
pois servem para a validação do certificado ambos pelo OpenSSL e pelo browser.
Nós optamos por assumir que num cenário real, teríamos acesso físico às máquinas, por isso em vez
de utilizar, por exemplo SCP ou FTP, escolhemos partilhar os ficheiros a partir da máquina host. No entanto, outra abordagem também estaria correta.
\begin{codeblock}[bash]{create\_all\_keys.sh}
cert_ca="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=CoimbraVPN"
cert_vpn="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=gateway"
cert_user="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=warrior"
cert_apache="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=apache.coimbra"
openssl genrsa -out "ca.key" 2048
openssl req -x509 -nodes -days 365 -key "ca.key" -out "ca.crt" -subj "$cert_ca"
openssl genrsa -out "vpn.key" 2048
openssl req -new -key "vpn.key" -out "vpn.csr" -subj "$cert_vpn"
openssl ca -batch -in "vpn.csr" -cert "ca.crt" -keyfile "ca.key" -out "vpn.crt" -config cheese.cfg
openssl dhparam -out "dh2048.pem" 2048
openvpn --genkey secret "ta.key"
openssl genrsa -out user.key
openssl req -new -key user.key -out user.csr -subj "$cert_user"
openssl ca -batch -in "user.csr" -cert "ca.crt" -keyfile "ca.key" -out "user.crt" -config cheese.cfg
openssl genrsa -out apache.key
openssl req -new -key apache.key -out apache.csr -subj "$cert_apache" -addext "subjectAltName = IP:10.60.0.1,DNS:apache"
openssl ca -batch -in "apache.csr" -cert "ca.crt" -keyfile "ca.key" -out "apache.crt" -config cheese.cfg
openssl --genkey secret ta.key
\end{codeblock}
Como o CA foi criado ``\textit{in place}'', e não na sua pasta prédefinida, foi necessário utilizar
um configuração própria para definir os ficheiros \textit{index.txt} e \textit{serial}.
\begin{codeblock}[bash]{cheese.cfg}
[ ca ]
default_ca = CA_default
[ CA_default ]
default_days = 365
database = index.txt
serial = serial
copy_extensions = copy
new_certs_dir = .
default_md = sha256
policy = policy_any
[ policy_any ]
commonName = supplied
\end{codeblock}
\subsection{Configuração geral}
Para evitar repetição e redundancia; e para garantir consistencia na elaboração do projeto criamos varios shell scripts, um destinado a cada maquina virtual.
Para configurar as VMs era preciso introduzir os mesmos comandos várias vezes, o que levava muitas vezes a erros de escrita,
ou a correr o mesmo comando várias vezes, por isso criamos vários ficheiros .sh para conseguir facilitar o processo.
A utilização de ficheiros .sh também vem com outros positivos pois facilita a testagem, e a recriação do cenário rapidamente.
No entanto para os serviços que configuramos, instalar, desativar e dar flush às iptables não foi suficiente, tivemos que criar
pastas e sincronizar os relógios de todas as VMs visto que elas estarem ligeiramente atrasadas nunca conseguíamos acertar na
password do google-authenticator visto que utiliza o tempo local para calcular a sua chave.
\begin{codeblock}[bash]{VM\_CONFIG.sh}
yum install -y epel-release
yum install -y openvpn iptables-services dhcp-client
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
systemctl enable iptables
iptables -F
CA_DIR="/etc/pki/CA"
mkdir -p "${CA_DIR}/newcerts"
mkdir -p "${CA_DIR}/private"
touch "${CA_DIR}/index.txt"
cp ca/serial "${CA_DIR}/serial"
mkdir -p /etc/openvpn/server
mkdir -p /etc/openvpn/client
# NOTE(vasco): tive problemas com a sincronizacao de tempo
# se nao tiver sincronizado, o TOTP nao funciona
systemctl stop chronyd
ntpdate pool.ntp.org
systemctl start chronyd
\end{codeblock}
\section{VPN Gateway}
\subsection{Configuração da Máquina}
Como já foi dito anteriormente, cada máquina vem com um \textit{script}
que instala toda a configuração necessária.
Para que a gateway funcione como router entre a rede externa e a rede interna,
foi necessário ativar o \textit{IP forwarding} no kernel e configurar as regras
de \textit{iptables} para permitir o tráfego da VPN e realizar o mascaramento
de IP (NAT).
% NOTA(vasco): Não temos regras de DROP a packets
% talvez deviamos mudar isso nao sei <- não diz nada no enunciado ¯\_(ツ)_/¯
% também o trabalho não é sobre ip tables por isso it does make sense não fazer drop
%e utilizar as regras apenas para encaminhar corretamente.
% Colocar isso na conclusão tho
\begin{codeblock}[bash]{VM\_VPN\_GATEWAY.sh}
#!/bin/bash
# --- configuracao --- #
source VM_CONFIG.sh
yum install -y google-authenticator qrencode ntpsec
# --- forwarding --- #
if_fora="enp0s8"
ip_fora="193.136.212.1"
if_dentro="enp0s9"
ip_dentro="10.60.0.3"
mega_tunel="tun0"
ip_mega_tunel="10.8.0.0/24"
ifconfig $if_fora $ip_fora netmask 255.255.255.0
ifconfig $if_dentro $ip_dentro netmask 255.255.255.0
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT
iptables -I FORWARD 1 -i $mega_tunel -o $if_dentro -j ACCEPT
iptables -I FORWARD 1 -i $if_dentro -o $mega_tunel -j ACCEPT
iptables -I FORWARD 1 -i $mega_tunel -o $if_fora -j ACCEPT
iptables -I FORWARD 1 -i $if_fora -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $ip_mega_tunel -o $if_fora -j MASQUERADE
iptables-save > /etc/sysconfig/iptables
# --- vpn server --- #
vpn_dir="/etc/openvpn/server"
cp ca/ta.key $vpn_dir
cp ca/ca.crt $vpn_dir
cp ca/vpn.key $vpn_dir
cp ca/vpn.crt $vpn_dir
cp ca/dh2048.pem $vpn_dir
cp conf/vpn.conf $vpn_dir
cp conf/ocsp-verify.sh $vpn_dir
cp conf/totp /etc/pam.d/
# --- utilizador --- #
id -u john &>/dev/null || useradd john
echo "password" | passwd --stdin john
openvpn --config /etc/openvpn/server/vpn.conf
\end{codeblock}
\subsection{Configuração do Serviço OpenVPN}
O servidor OpenVPN utiliza um certificado X.509 assinado pelo nosso \textit{Certificate Authority} (CA).
E faz uso de um script \texttt{oscp-verify.sh} para validar ou revogar os certificados através do servidor OCSP.
\begin{codeblock}{vpn.conf}
local 193.136.212.1
port 1194
proto udp
dev tun
verb 4
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/vpn.crt
key /etc/openvpn/server/vpn.key
dh /etc/openvpn/server/dh2048.pem
topology subnet
server 10.8.0.0 255.255.255.0
push "route 10.60.0.0 255.255.255.0"
# ocsp and revocation
script-security 2
tls-verify /etc/openvpn/server/ocsp-verify.sh
# auth
cipher AES-256-GCM
auth SHA256
plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so totp
tls-auth /etc/openvpn/server/ta.key 0
\end{codeblock}
Foi criado o ficheiro \texttt{totp} com a configuração de autenticação a
ser utilizada pelo plugin de PAM para o openvpn.
\begin{codeblock}{totp}
auth required pam_google_authenticator.so forward_pass
auth required pam_unix.so use_first_pass
account required pam_unix.so
\end{codeblock}
Este script simplesmente comunica com o servidor OpenSSl
e verifica o resultado.
\begin{codeblock}{ocsp\_verify.sh}
#!/bin/bash
depth=$1
if [ "$depth" -eq 0 ]; then
if [ -n "$tls_serial_0" ]; then
# e preciso converter o serial para hexadecimal porque o openssl espera em hex
hex_serial=$(printf '%x' "$tls_serial_0")
status=$(openssl ocsp -issuer /etc/openvpn/server/ca.crt -serial "0x$hex_serial" -url http://10.60.0.1:8888 -CAfile /etc/openvpn/server/ca.crt 2>/dev/null)
if echo "$status" | grep -q "good"; then
exit 0 # sucesso
fi
exit 1 # revogado ou nao encontrado
fi
exit 1
fi
\end{codeblock}
\subsection{Erros}
Um dos erros que encontramos pelo caminho foi que o OpenSSL OCSP espera que o
\textit{serial} esteja num formato diferente do que o esperado. Foi necessário
converter para hexadecimal primeiro.
Adicionalmente, devido às restrições de segurança do \textit{systemd},
tentamos desativar o \texttt{ProtectHome} no serviço do OpenVPN
para que o plugin PAM consiga ler os ficheiros de segredo do Google Authenticator
localizados nas diretorias \textit{home} dos utilizadores. Mas isto não
foi suficiente, por isso acabamos por correr os serviços pela linha
de comandoos.
\subsection{Configurar o utilizador com TOTP}
Primeiro, na gateway, entramos como o utilizador desejado e obtemos a chave
do gerador de palavras passes temporárias. Ao inserir a chave no
\texttt{google authenticator} podemos obter um código QR, a nossa primeira
chave de 6 dígitos.
\begin{figure}[h]
\centering
\includegraphics[width=8em]{google-authenticator}
\end{figure}
\begin{codeblock}[bash]{}
su john
google-authenticator
\end{codeblock}
\section{VPN Client (Road Warrior)}
\subsection{Configuração da Máquina}
Para a configuração da Máquina, configuramos o edereço, o default gateway e adicionamos apache aos Hosts:
\begin{codeblock}{VM\_ROAD\_WARRIOR.sh}
#!/bin/bash
# --- configuracao --- #
source VM_CONFIG.sh
ifconfig enp0s8 193.136.212.10 netmask 255.255.255.0
route add default gw 193.136.212.1
if ! grep -q "apache" /etc/hosts; then
echo "10.60.0.1 apache" >> /etc/hosts
fi
# --- vpn client --- #
vpn_dir="/etc/openvpn/client/"
cp ca/ta.key $vpn_dir
cp ca/ca.crt $vpn_dir
cp ca/user.key $vpn_dir
cp ca/user.crt $vpn_dir
cp conf/client.conf $vpn_dir
openvpn --config "${vpn_dir}/client.conf"
\end{codeblock}
% Esta configuração foi necessaria, porque sem edereço a VM não conseguia-se identificar na rede. Sem o default gateway
% os edereços desconhecidos seriam enviados para a porta da internet, e adicionamos apache aos Hosts para que fosse igual
% ao domain para não haver erros.
%(I dunno about this Apache part??) Also sinto que ainda precisa de mais um bocado.
Também foram movidos os certificados e chaves necessarias para as pastas do serviço openvpn, para que o Road Warrior
consiga comunicar e ser validado pela gateway.
\subsection{Configuração do Cliente OpenVPN}
O cliente encontra-se na rede externa (\texttt{193.136.212.10}) e liga-se à VPN
gateway na porta 1194. Para garantir a segurança, utilizamos autenticação mútua (os certificados X.509)
e um \textit{two factor authentication} (2FA) como palavras-passe temporárias, geradas através do
\textit{Google Authenticator}.
\begin{codeblock}{client.conf}
client
dev tun
proto udp
remote 193.136.212.1 1194
ca ca.crt
cert user.crt
key user.key
auth-user-pass
cipher AES-256-GCM
auth SHA256
\end{codeblock}
\subsection{Testes}
Para verificar que a autenticação foi corretamente implementada, inserimos a password de um utilizador sem os digitos do TOTP, e identificamos que utilizar somente a password não é suficiente para autenticar. Igualmente ao utilizar ambos a autenticação é bem sucedida.
Para verificar que o tunel foi estabelecido, primeiro corremos na linha de comandos \texttt{ip a}. Observamos a existencia de uma nova interface tun0, ou seja o tunel foi corretamente establecido. Depois demos ping ao route e depois ao servidor interno, que resultou em pacotes devolvidos para ambos.
% TODO: screenshots? dizer que erros exatos nos obtemos a cada etapa
% TODO: erros ortograficos lol
Para verificar que o OCSP funciona correctamente, o cliente conectou ao servidor OpenVPN:
primeiro, sem o servidor OCSP a correr, uma segunda vez com ele a correr e com o certificado correcto
e uma terceira vez com um certificado revogado. Fizemos estes testes sabendo que o
cliente e o servidor já estavam correctamente configurados.
Verificamos que, como é suposto: sem OCSP não é possivel autenticar; com OCSP e com certificado válido,
podemos autenticar; e com OCSP mas com certificado revogado, a autenticação falha.
\section{Servidor Apache e OCSP}
Para a configuração da ultima maquina, temos o OpenSSL e Apache no mesmo servidor, por isso temos de configurar
as pastas necessarias, os utilizadores do serviço, configurar os edereços e uma route:
\begin{codeblock}{VM\_OPENSSL\_APACHE.sh}
#!/bin/bash
# configuracao
source VM_CONFIG.sh
sudo yum install -y epel-release
sudo yum install -y openssl httpd mod_ssl mod_authnz_pam google-authenticator
sudo yum install -y mod_session
# utilizador
id -u john &>/dev/null || useradd john
echo "password" | passwd --stdin john
if_dentro="enp0s8"
ip_dentro="10.60.0.1"
ifconfig $if_dentro $ip_dentro netmask 255.255.255.0
# route de volta para comunicar com o warrior
route add -net 10.8.0.0 netmask 255.255.255.0 gw 10.60.0.3
cp conf/openssl.cnf /etc/pki/tls/
# copiar ca para esta VM
cp ca/index.txt $CA_DIR
cp ca/ca.crt $CA_DIR
cp ca/ca.key $CA_DIR
cp ca/serial $CA_DIR
cp ca/dh2048.pem $CA_DIR
# correr oscp
killall openssl 2>/dev/null
openssl ocsp -index $CA_DIR/index.txt -port 8888 -rsigner $CA_DIR/ca.crt -rkey $CA_DIR/ca.key -CA $CA_DIR/ca.crt -text &
# apache
mkdir -p /etc/httpd/ssl
cp ca/ca.crt /etc/httpd/ssl/
cp ca/apache.crt /etc/httpd/ssl/
cp ca/apache.key /etc/httpd/ssl/
cp conf/ssl.conf /etc/httpd/conf.d/ssl.conf
cp conf/httpd.conf /etc/httpd/conf/httpd.conf
cp conf/httpd-totp /etc/pam.d/httpd-totp
echo "LoadModule session_module modules/mod_session.so" > /etc/httpd/conf.modules.d/01-session.conf
echo "LoadModule session_cookie_module modules/mod_session_cookie.so" >> /etc/httpd/conf.modules.d/01-session.conf
echo "LoadModule auth_form_module modules/mod_auth_form.so" > /etc/httpd/conf.modules.d/01-auth_form.conf
cp -r www/* /var/www/html/
chown -R apache:apache /var/www/html/
httpd -X
\end{codeblock}
\subsection{Configuração da Máquina}
Como já referimos a Máquina tem ambos o serviço OpenSSL e Apache, por isso vai precisar de dois .conf files para
configurar-los. O httpd.conf tem as portas e modulos enquanto o ssl.conf tem a configuração da autenticação mútua, e o OCSP:
\begin{codeblock}{httpd.conf}
ServerRoot "/etc/httpd"
Include conf.modules.d/*.conf
LoadModule authnz_pam_module modules/mod_authnz_pam.so
LoadModule mpm_event_module modules/mod_mpm_event.so
User apache
Group apache
Listen 80
Listen 443
Include conf.d/*.conf
DocumentRoot "/var/www/html"
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
\end{codeblock}
\begin{codeblock}{ssl.conf}
<VirtualHost *:443>
ServerName 10.60.0.1
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/apache.crt
SSLCertificateKeyFile /etc/httpd/ssl/apache.key
SSLCACertificateFile /etc/httpd/ssl/ca.crt
# mutual authentication
SSLVerifyClient require
SSLVerifyDepth 1
# ocsp validation
SSLOCSPEnable on
SSLOCSPDefaultResponder "http://10.60.0.1:8888"
SSLOCSPOverrideResponder on
SSLOCSPUseRequestNonce off
# session management
Session On
SessionCookieName session path=/;HttpOnly;Secure
# proteger
<Location "/">
AuthType Form
AuthName "Coimbra VPN"
AuthFormProvider PAM
AuthPAMService httpd-totp
AuthFormLoginRequiredLocation "/login.html"
Require valid-user
</Location>
# public login page
<Location "/login.html">
AuthType None
Require all granted
</Location>
# login handler
<Location "/dologin">
SetHandler form-login-handler
AuthType Form
AuthName "Coimbra VPN"
AuthFormProvider PAM
AuthPAMService httpd-totp
Require all granted
AuthFormLoginSuccessLocation "/index.html"
AuthFormLoginRequiredLocation "/login.html?error=1"
</Location>
# logout handler
<Location "/logout">
SetHandler form-logout-handler
AuthFormLogoutLocation "/login.html?loggedout=1"
</Location>
</VirtualHost>
# redirect para https
<VirtualHost *:80>
ServerName 10.60.0.1
Redirect permanent / https://10.60.0.1/
</VirtualHost>
\end{codeblock}
\subsubsection{Testes}
\begin{itemize}
\item \textbf{Domínio:} Verificou-se que o acesso só é permitido utilizando o endereço correto, pois se for inserido outro dominio, não é direcionado para o site do Apache.
\item \textbf{Redirecionamento HTTPS:} Ao testar quando colocamos http, e o dominio certo, era redirecionado para https.
\item \textbf{Autenticação com o Certificado:} O acesso foi negado ao apresentar certificados inválidos ou ausentes no browser, devolvendo um erro com sobre não conseguir establecer connexão porque falta de certificado.
\end{itemize}
Para testar o OCSP, fizemos os seguintes paços:
\begin{enumerate}
\item Estabelecer a ligação VPN e verificar a conectividade à rede interna.
\item No diretório da autoridade de certificação (máquina \textit{host}), revogar o certificado do utilizador:
\begin{codeblock}[bash]{revoke.sh}
openssl ca -revoke user.crt -config cheese.cfg -keyfile ca.key -cert ca.crt
\end{codeblock}
\item Atualizar o ficheiro \texttt{index.txt} no servidor OCSP e reiniciar o serviço para carregar o novo estado de revogação.
\item Tentar estabelecer uma nova ligação VPN e verificar que a autenticação falha devido à resposta \texttt{revoked} do responder OCSP.
\end{enumerate}
\section{Teste Integrado}
Para validar, efetuámos um teste integrado englobando todos os requisitos:
\begin{enumerate}
\item Começamos por iniciar todas as máquinas com os devidos \textit{scripts}.
\item Na máquina \textit{Road Warrior}, iniciámos a ligação OpenVPN com o utilizador, a sua password e o \textit{token} TOTP.
\item O \textit{Gateway} OpenVPN verifica as credenciais e verifica o certificado cliente contra o servidor OCSP.
\item Antes de acedermos ao firefox, temos que verificar que já adicionámos a nossa a nossa CA e o certificado \texttt{p12}.
\item Através do túnel VPN, acedemos agora ao endereço \texttt{https://apache.coimbra} no browser.
\item O servidor Apache solicitou o certificado X.509 do utilizador e validou a sua autenticidade e estado de revogação no OCSP.
\item Finalmente, o Apache apresentou a página de login, onde inserimos as credenciais e o código TOTP.
\end{enumerate}
\section{Conclusão}
Atingimos o objetivo deste trabalho: conseguimos configurar o túnel VPN,
o \textit{two-factor authentication} em múltiplos serviços, e conseguimos gerir o ciclo de vida dos
certificados emitidos através de uma CA própria e OCSP. Utilizar mais máquinas para simular um cenário
maior seria redundante e apenas exigiria a emissão de mais certificados, não acrescentando muito ao nível de aprendizagem.
Aplicando conhecimentos de trabalhos anteriores,
poderíamos aplicar políticas mais restritas nas \textit{iptables} (ex: regras de DROP aos pacotes indesejados),
e implementar ferramentas como o Suricata para identificar possíveis anomalias e ataques aos serviços.
\end{document}

View File

@@ -0,0 +1,19 @@
\babel@toc {portuguese}{}\relax
\contentsline {section}{\numberline {1}Introdução}{3}{section.1}%
\contentsline {section}{\numberline {2}Preparação Inicial}{3}{section.2}%
\contentsline {subsection}{\numberline {2.1}Criação de Certificados}{3}{subsection.2.1}%
\contentsline {subsection}{\numberline {2.2}Configuração geral}{4}{subsection.2.2}%
\contentsline {section}{\numberline {3}VPN Gateway}{5}{section.3}%
\contentsline {subsection}{\numberline {3.1}Configuração da Máquina}{5}{subsection.3.1}%
\contentsline {subsection}{\numberline {3.2}Configuração do Serviço OpenVPN}{6}{subsection.3.2}%
\contentsline {subsection}{\numberline {3.3}Erros}{7}{subsection.3.3}%
\contentsline {subsection}{\numberline {3.4}Configurar o utilizador com TOTP}{7}{subsection.3.4}%
\contentsline {section}{\numberline {4}VPN Client (Road Warrior)}{8}{section.4}%
\contentsline {subsection}{\numberline {4.1}Configuração da Máquina}{8}{subsection.4.1}%
\contentsline {subsection}{\numberline {4.2}Configuração do Cliente OpenVPN}{8}{subsection.4.2}%
\contentsline {subsection}{\numberline {4.3}Testes}{9}{subsection.4.3}%
\contentsline {section}{\numberline {5}Servidor Apache e OCSP}{9}{section.5}%
\contentsline {subsection}{\numberline {5.1}Configuração da Máquina}{10}{subsection.5.1}%
\contentsline {subsubsection}{\numberline {5.1.1}Testes}{12}{subsubsection.5.1.1}%
\contentsline {section}{\numberline {6}Teste Integrado}{13}{section.6}%
\contentsline {section}{\numberline {7}Conclusão}{13}{section.7}%

View File

@@ -0,0 +1,64 @@
\usepackage[margin=1in]{geometry}
\usepackage{raleway}
\renewcommand{\familydefault}{\sfdefault}
\usepackage{ulem}
\usepackage{wrapfig}
\usepackage{graphicx,tabularx,booktabs}
\usepackage{paracol}
\usepackage[dvipsnames]{xcolor}
\usepackage{enumitem,amssymb}
\usepackage[colorlinks=true,urlcolor=blue,linkcolor=MidnightBlue]{hyperref}
\graphicspath{{./img/}}
\usepackage{enumitem,amssymb}
\newlist{todolist}{itemize}{2}
\setlist[todolist]{noitemsep, topsep=0pt,label=$\square$}
\usepackage{pifont}
\usepackage{amssymb}
\usepackage[most]{tcolorbox}
\tcbuselibrary{listings, skins, breakable}
\lstdefinestyle{mystyle}{
basicstyle=\ttfamily\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2,
commentstyle=\color{gray},
keywordstyle=\color{MidnightBlue}\bfseries,
stringstyle=\color{ForestGreen}
}
\newtcblisting{codeblock}[2][]{
enhanced,
breakable,
colback=gray!2!white,
colframe=gray!20!black,
attach boxed title to top left={yshift*=-\tcboxedtitleheight/2, xshift=4mm},
boxed title style={
colback=gray!20!black,
outer arc=0pt,
arc=0pt,
top=1pt,
bottom=1pt,
},
fonttitle=\bfseries\ttfamily\footnotesize,
title={#2},
listing only,
listing options={
style=mystyle,
language=#1,
}
}
\setlength{\parskip}{1em}%
\setlength{\parindent}{0em}%

View File

@@ -0,0 +1,13 @@
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Coimbra VPN</title>
</head>
<body>
<h1>Coimbra VPN</h1>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.
Minima porro unde praesentium sint itaque optio, deserunt eum est voluptatum, natus nihil repellat amet impedit? Fugiat fugit ex quis molestiae sit.</p>
</body>
</html>

View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Coimbra VPN</title>
</head>
<body>
<h1>Two-Factor Auth</h1>
<p>Enter your UNIX credentials and TOTP code</p>
<form action="/dologin" method="POST">
<label for="username">Username</label>
<input type="text" id="username" name="httpd_username" placeholder="username">
<br>
<label for="password">UNIX Password (password + 6 digit TOTP)</label>
<input type="password" id="password" name="httpd_password" placeholder="password + TOTP" required>
<button type="submit">Login</button>
</form>
</body>
</html>

View File

@@ -1 +1,90 @@
# LoadModule authnz_pam_module modules/mod_authnz_pam.so
ServerRoot "/etc/httpd"
ServerName "10.60.0.1"
Listen 80
User apache
Group apache
Include conf.modules.d/*.conf
Include conf/modsecurity.conf
<Directory />
AllowOverride none
Require all denied
</Directory>
DocumentRoot "/var/www/html"
<Directory "/var/www">
AllowOverride None
Require all granted
</Directory>
# Further relax access to the default document root:
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
<Files ".ht*">
Require all denied
</Files>
ErrorLog "logs/error_log"
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog "logs/access_log" combined
</IfModule>
<IfModule mime_module>
TypesConfig /etc/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</IfModule>
AddDefaultCharset UTF-8
<IfModule mime_magic_module>
MIMEMagicFile conf/magic
</IfModule>
# reverse proxy for juice shop
ProxyRequests Off
ProxyPreserveHost On
<VirtualHost 10.60.0.1:80>
<IfModule mod_headers.c>
RequestHeader unset Accept-Encoding
</IfModule>
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>
# EnableMMAP off
# EnableSendfile on
IncludeOptional conf.d/*.conf
ServerAdmin jeevacation@gmail.com
# ServerName www.coimbravpn.com:80

38
conf/modsecurity.conf Normal file
View File

@@ -0,0 +1,38 @@
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecDebugLog /var/log/modsecurity/debug.log
SecDebugLogLevel 0
SecAuditLogParts ABIJ
SecAuditLogType Serial
SecAuditLog /var/log/modsecurity/audit.log
SecRequestBodyJsonParser On
# sql injection
SecRule REQUEST_BODY "['\"].*--" \
"id:950001,phase:2,deny,status:403,msg:'SQL Injection: quote and comment',log"
# 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"

View File

@@ -1,32 +0,0 @@
#!/bin/bash
depth=$1
env >> /etc/openvpn/server/ocsp_env.log
if [ "$depth" -eq 0 ]; then
echo "Checking OCSP for serial=$tls_serial_0" >> /etc/openvpn/server/ocsp.log
if [ -n "$tls_serial_0" ]; then
# é preciso converter o serial para hexadecimal porque o openssl espera em hex
hex_serial=$(printf '%x' "$tls_serial_0")
status=$(openssl ocsp -issuer /etc/openvpn/server/ca.crt -serial "0x$hex_serial" -url http://10.60.0.1:8888 -CAfile /etc/openvpn/server/ca.crt 2>>/etc/openvpn/server/ocsp.log)
echo "OCSP Status: $status" >> /etc/openvpn/server/ocsp.log
if echo "$status" | grep -q "revoked"; then
echo "Result: REVOKED" >> /etc/openvpn/server/ocsp.log
exit 1
fi
if echo "$status" | grep -q "good"; then
echo "Result: GOOD" >> /etc/openvpn/server/ocsp.log
exit 0
fi
echo "Result: UNKNOWN/ERROR" >> /etc/openvpn/server/ocsp.log
exit 1
else
echo "tls_serial_0 is empty!" >> /etc/openvpn/server/ocsp.log
exit 1
fi
fi
echo "ERROR: depth > 0" >> /etc/openvpn/server/ocsp.log
exit 0

View File

View File

@@ -1,29 +0,0 @@
Listen 443 https
<VirtualHost *:443>
ServerName 10.60.0.1
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/apache.crt
SSLCertificateKeyFile /etc/httpd/ssl/apache.key
SSLCACertificateFile /etc/httpd/ssl/ca.crt
# Mutual Authentication (Client Cert)
SSLVerifyClient require
SSLVerifyDepth 1
# OCSP Validation against CA
SSLOCSPEnable on
SSLOCSPDefaultResponder "http://10.60.0.1:8888"
SSLOCSPOverrideResponder on
SSLOCSPUseRequestNonce off
# PAM + TOTP Authentication
<Location "/">
AuthType Basic
AuthName "Enter UNIX Password + Google Authenticator Code"
AuthBasicProvider PAM
AuthPAMService httpd-totp
Require valid-user
</Location>
</VirtualHost>

BIN
entrega.zip Normal file

Binary file not shown.

3680
entrega.zip.asc Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,142 +1,152 @@
FSI 2025/2026
Practical Assignment #2
Practical Assignment #3
1. Goals
Configure a VPN tunnel in the “road warrior” scenario.
Explore the WSTG (Web Security Testing Guide)1 web security testing guidelines.
Enable two-factor user authentication with OpenVPN and Apache services.
Manage PKI: certification authorities, X.509 certificates, revocation and OCSP.
Configure and explore the usage of ModSecurity reverse proxy as a WAF (Web Application Firewall)
2. General description
Figure 1 illustrates the scenario considered for our practical assignment. As illustrated, secure communications are
supported by a VPN tunnel established between a remote client (road warrior) and the VPN gateway, with the purpose of
enabling accesses to services in the Internal Network, particularly a web server running Apache. To enable the VPN tunnel,
we will use OpenVPN (https://openvpn.net).
The main goals of this assignment are to explore web application security and to implement a web application firewall to
secure a web application against application-layer attacks. The web application to be used in this assignment is the OWASP
JuiceShop2 3. This assignment is split in two phases: the first phase is dedicated to exploring the security of the JuiceShop
web application, and the second phase aims at monitor, filter, and block HTTP traffic to the JuiceShop, through the
implementation of a WAF using ModSecurity, with the aim to address the security issues identified in the first phase. Figure
1 illustrates the two phases of the assignment, depicting the JuiceShop web server, the penetration testing client and the
WAF.
Figure 1 Scenario for the Practical Assignment #1
Figure 1 Security testing and WAF phases of the Assignment
Regarding authentication, the two communication entities participating in the VPN tunnel (road warrior and the VPN
gateway) should possess valid X.509 certificates, which are created with a private Certification Authority (CA). Users
establishing remote connections to the VPN gateway (road warriors), as well as users connecting to the Apache server, will
also use two-factor authentication, as described below. Apache must also implement client authentication via X.509
certificates. Figure 2 provides an illustration of the interactions between all the entities involved in this setup.
1
Figure 2 X.509 mutual authentication and OCSP
WSTG with v42 is available at: https://owasp.org/www-project-web-security-testing-guide/
As we can observe in Figure 2, the VPN gateway and the Apache web server must verify the status of validity of certificates
using OCSP (Online Certificate Status Protocol) and revocation information from the CA. OCSP verification in not
required for the road warrior. Next, we describe the configuration requirements for the various components of the
assignment.
3. Configuration requirements
VPN tunnel for remote access (road warriors)
As illustrated in Figure 1, remote clients (road warriors) are able to connect to the Coimbra VPN gateway, and using the
tunnel remotely access hosts in the Internal network. The following configuration requirements should be considered:
In order to establish a VPN tunnel with the Coimbra gateway, the road warrior must be in the possession of a valid
X.509 certificate, issued by the private CA of the scenario.
The road warrior and the Coimbra VPN gateway must perform mutual authentication using X.509 digital certificates.
The Coimbra VPN gateway should verify the validity of the X.509 certificate presented by the road warrior using OCSP
and, in case the certificate is revoked, the gateway should refuse the connection.
In order to authorize the remote user, the Coimbra gateway should also enforce two other authentication steps: the user
must present a valid username and password, plus a one-time password (OTP, or an authentication token).
Web server
2
The road warrior user should be able to contact the Apache web server with HTTPS through the VPN tunnel. The
following configuration requirements should be considered:
Apache should enforce two-factor authentication in order to authorize accesses from clients: the client (browser) should
present a valid X.509 certificate (issued with the private CA of the scenario) and the user should also present a valid onetime password (or authentication token).
As in the VPN, the validity of the X.509 certificate presented by the client should be checked in the CA using OCSP.
Two-factor user authentication
As previously discussed, VPN establishment and HTTPS accesses to Apache make use of one-time passwords
(authentication tokens), which may be generated by an appropriate application. One-time passwords may be generated using
the TOTP (Time-based One-time Password Algorithm). This algorithm employs a secret key shared between the user
(client) and the remote service, plus a timestamp (obtained from the current system time), to obtain a one-time password.
In order to generate a one-time password, the user may use an application such as Google Authenticator, illustrated in
Figure 3. This application periodically generates a new one-time password that can be used to authenticate the user with the
remote service. This application is available for iOS and Android 1.
Certification authority
As already discussed, the goal is to use OpenSSL to configure a private Certification Authority, as well as to issue and revoke
X.509 digital certificates for the VPN gateways and remote users. The following configuration requirements should be
considered:
The Certification Authority is used to issue certificates for the VPN gateway, VPN client and Apache web server.
The Certification Authority allows the revocation of certificates previously issued.
The Certification Authority also supports a OCSP responder.
For Android: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en and
for Apple iOS: https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8
1
OWASP JuiceShop: https://owasp.org/www-project-juice-shop/
For this assignment, it is recommended to use the most recent version of the JuiceShop. At the time of writing this document it is v17.2.0
3
Figure 3 Google Authenticator app, to generate a one-time password to access services enabled with two-factor authentication
3. Phase 1 - Web application security testing
In this phase the goal is to explore web application security using the JuiceShop website following the relevant and applicable
WSTG web security testing guidelines, and for this purpose any security tools can be used. In this context, OWASP ZAP
and security tools already available in Kali Linux are particularly relevant. This web security testing phase is described in
Figure 1, where the client has direct communications to the web server. As part of your tests, the OWASP ZAP penetration
tests must, at least:
a. Perform an automated scan to the website.
b. Perform an active scan to the website (explore the most effective policies).
c. Manage add-on required to improve the test and maximize threats identification.
d. Perform a Fuzz attack to the login form.
e. Perform a manual penetration test to explore logged in threats.
f.
4. Delivery of the Practical Assignment
With the assignment, please deliver also a report, containing the following information:
Configure OWASP ZAP active scan to explore authenticated area.
The JuiceShop application can be installed via source code or using docker, as follows:
Descriptions of the configurations for the implementation of the previous requirements.
Installation through source code in one of the virtual machines
A description of how the private Certification Authority was created using OpenSSL.
Using a docker approach (requires Docker Desktop)
As a result of your tests, you should prepare a web application security report, structured along the WSTG guidelines. The
report must document the identified vulnerabilities and on how these can be exploited (e.g., weak passwords, insecure
configurations).
4. Phase 2 Setup and testing of a WAF (web application firewall)
Based on the web application security report produced in the first phase of the assignment, deploy an WAF between the
client and the web server, as depicted in Figure 1. The goals of this WAF are to monitor, filter, and block HTTP traffic to
the Juice Shop. This WAF server should be composed of an Apache 2 service with ModSecurity, and the WAF
configuration should be optimized to prevent all possible attacks.
As a result of this phase of the Assignment, you should repeat all penetration tests performed in the previous task and assess
the performance of the WAF in detecting and blocking the attacks. You should update the web application security report
accordingly, by including the configurations, description of the tests and performance results in a separate section.
5. Delivery of the Practical Assignment
2
The deadline for the delivery of the assignment (configuration files and report, via Inforestudante) is 31/5/2026.
A description of how X.509 certificates were issued and revoked using the private Certification Authority.
Notes:
o
Assignments without PGP will be accepted, although with a discount of 5% in the final grade.
A description of the tests performed to validate the functionalities implemented.
o
Submissions via Inforestudante.
Remaining information considered relevant.
The delivery of the practical assignment can document aspects regarding the methodology of testing, the analysis of results
and can be structured as follows:
For the delivery of the assignment, put your report, as well as the relevant configuration files, in a single archive. This archive
should be signed using your PGP key and encrypted using the PGP key of your PL teacher.
Note: Assignments without PGP will be accepted, although with a discount of 5% in the final grade.
Delivery deadline:
1) Introduction
2) Arquitecture considered for the PA#3 (for both scenarios 1 and 2)
- Network structure
- Servers
- Services
3) Web application security testing
1 Information Gathering
2 Configuration and Deployment Management Testing
3 Identity Management Testing
4 Authentication Testing
5 Authorization Testing
6 Session Management Testing
7 Input Validation Testing
8 Testing for Error Handling
9 Testing for Weak Cryptography
10 Business Logic Testing
11 Client Side Testing
4) Web application security firewall
1 Information Gathering
2 Configuration and Deployment Management Testing
3 Identity Management Testing
4 Authentication Testing
5 Authorization Testing
6 Session Management Testing
7 Input Validation Testing
8 Testing for Error Handling
9 Testing for Weak Cryptography
10 Business Logic Testing
11 Client Side Testing
5) Conclusions
The deadline for the delivery of the assignment (configuration files and report) is May 3rd 2026.
3
Submission via Inforestudante.
6. Important/relevant aspects
The Web Application Security Testing document includes several sections, providing guidelines for testing. The guideline
applicable to this assignment is mainly in Section 4, which must be analysed carefully, since testing tools may be suggested in
each section.
The practical assignment targets black-box testing, which is according to OWASP in WSTG “the art of testing a system or
application remotely to find security vulnerabilities, without knowing the inner workings of the target itself”. Thus, in this
type of testing strategy we focus on tools such as web application security scanners, vulnerability scanners and penetration
testing software.
The following aspects are relevant in what respects the WSTG guidelines and structure:
1. Section 4.7 should be considered as a whole, which can be tested with OWASP ZAP or a similar tool. There are
some subsections, that do not apply in this assignment. For instance, the Juice Shop does not include any support
for LDAP, so subsection 4.7.6 “Testing for LDAP injection” does not require any action/testing.
2. Section 4.11 should be considered as a whole, which can be tested with OWASP ZAP or a similar tool.
3. Section 4.9 should not be considered since communications with Juice Shop are not over HTTPS.
4. Section 4.10 should not be considered as well, as it is out of scope of this assignment.
5. Other subsections are out of scope of this assignment, and students should identify these in the report (and explain
why). For instance. subsection 4.2.9, 4.2.10 and 4.2.11 are not applicable in this assignment.
Regarding the second phase of the work, with the Web Application Firewall, the following aspects should be considered:
1. The main goal of the project in the second phase is to enable detection and prevention of the issues identified in the
first phase. Nonetheless, all the detection and prevention actions must be possible using Apache and ModSecurity
(with OWASP CRS), no other tools should be considered for this purpose.
2. The issues identified Section 4.3 of WSTG cannot be detected and solved with ModSecurity (with OWASP CRS),
so no action is required. ModSecurity is a WAF that operates at the HTTP level — it analyzes HTTP requests and
responses and blocks traffic based on patterns (malicious payloads, suspicious headers, etc.). Identity Management
issues are application logic flaws, not attacks with detectable patterns in HTTP traffic.
4

BIN
relatorio.pdf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
relatorio/imgs/ftp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
relatorio/imgs/metrics.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

BIN
relatorio/imgs/sqlmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
relatorio/imgs/swagger.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@@ -6,19 +6,47 @@
\providecommand\HyField@AuxAddToFields[1]{}
\providecommand\HyField@AuxAddToCoFields[2]{}
\babel@aux{portuguese}{}
\def\@LN@column{1}
\@writefile{toc}{\contentsline {section}{\numberline {1}Introdução}{2}{section.1}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {2}Criação de certificados}{2}{section.2}\protected@file@percent }
\def\@LN@column{1}
\@writefile{toc}{\contentsline {section}{\numberline {3}Configuração geral}{3}{section.3}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {4}Configuração da \textit {Gateway} VPN}{3}{section.4}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Configurar TOTP}{3}{subsection.4.1}\protected@file@percent }
\def\@LN@column{1}
\@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Encaminhamento e Firewall}{4}{subsection.4.2}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {5}Configuração do Cliente (Road Warrior)}{4}{section.5}\protected@file@percent }
\def\@LN@column{1}
\@writefile{toc}{\contentsline {section}{\numberline {6}Servidor Apache e OCSP}{5}{section.6}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {6.1}Revocation e OCSP}{5}{subsection.6.1}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {7}Conclusão}{5}{section.7}\protected@file@percent }
\xdef \mintedoldcachechecksum{\detokenize{\minted@cachechecksum }}
\gdef \@abspage@last{5}
\@writefile{toc}{\contentsline {section}{\numberline {1}Introduction}{3}{section.1}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {2}Architecture Considered for Both Stages}{3}{section.2}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Network structure}{3}{subsection.2.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Servers}{3}{subsection.2.2}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Services}{3}{subsection.2.3}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {3}Web application security testing}{4}{section.3}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Information Gathering}{4}{subsection.3.1}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces ftp}}{4}{figure.1}\protected@file@percent }
\newlabel{fig:ftp}{{1}{4}{ftp}{figure.1}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Configuration and Deployment Management Testing}{4}{subsection.3.2}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces metrics}}{5}{figure.2}\protected@file@percent }
\newlabel{fig:metrics}{{2}{5}{metrics}{figure.2}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces swagger}}{5}{figure.3}\protected@file@percent }
\newlabel{fig:swagger}{{3}{5}{swagger}{figure.3}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Identity Management Testing}{6}{subsection.3.3}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces email-unique}}{7}{figure.4}\protected@file@percent }
\newlabel{fig:email-unique}{{4}{7}{email-unique}{figure.4}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.4}Authentication Testing}{7}{subsection.3.4}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.5}Authorization Testing}{7}{subsection.3.5}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {5}{\ignorespaces email-invalido}}{8}{figure.5}\protected@file@percent }
\newlabel{fig:email-invalido}{{5}{8}{email-invalido}{figure.5}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {6}{\ignorespaces suspiciouserrors}}{8}{figure.6}\protected@file@percent }
\newlabel{fig:suspiciouserrors}{{6}{8}{suspiciouserrors}{figure.6}{}}
\@writefile{lof}{\contentsline {figure}{\numberline {7}{\ignorespaces suspiciouserrors2}}{9}{figure.7}\protected@file@percent }
\newlabel{fig:suspiciouserrors2}{{7}{9}{suspiciouserrors2}{figure.7}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.6}Session Management Testing}{9}{subsection.3.6}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.7}Input Validation Testing}{9}{subsection.3.7}\protected@file@percent }
\@writefile{toc}{\contentsline {subsubsection}{\numberline {3.7.1}Testing for SQL Injection}{10}{subsubsection.3.7.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {3.8}Testing for Error Handling}{10}{subsection.3.8}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {8}{\ignorespaces stack-trace}}{11}{figure.8}\protected@file@percent }
\newlabel{fig:stack-trace}{{8}{11}{stack-trace}{figure.8}{}}
\@writefile{toc}{\contentsline {subsection}{\numberline {3.9}Client Side Testing}{11}{subsection.3.9}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {4}Web Application Security Firewall}{11}{section.4}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Information Gathering}{12}{subsection.4.1}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Configuration and Deployment Management Testing}{12}{subsection.4.2}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.3}Identity Management Testing}{13}{subsection.4.3}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.4}Authentication Testing}{13}{subsection.4.4}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.5}Authorization Testing}{13}{subsection.4.5}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6}Session Management Testing}{13}{subsection.4.6}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.7}Input Validation Testing}{13}{subsection.4.7}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.8}Testing for Error Handling}{14}{subsection.4.8}\protected@file@percent }
\@writefile{toc}{\contentsline {subsection}{\numberline {4.9}Client Side Testing}{14}{subsection.4.9}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {5}Conclusions}{14}{section.5}\protected@file@percent }
\gdef \@abspage@last{14}

View File

@@ -0,0 +1,38 @@
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"

File diff suppressed because it is too large Load Diff

27
relatorio/relatorio.out Normal file
View File

@@ -0,0 +1,27 @@
\BOOKMARK [1][-]{section.1}{\376\377\000I\000n\000t\000r\000o\000d\000u\000c\000t\000i\000o\000n}{}% 1
\BOOKMARK [1][-]{section.2}{\376\377\000A\000r\000c\000h\000i\000t\000e\000c\000t\000u\000r\000e\000\040\000C\000o\000n\000s\000i\000d\000e\000r\000e\000d\000\040\000f\000o\000r\000\040\000B\000o\000t\000h\000\040\000S\000t\000a\000g\000e\000s}{}% 2
\BOOKMARK [2][-]{subsection.2.1}{\376\377\000N\000e\000t\000w\000o\000r\000k\000\040\000s\000t\000r\000u\000c\000t\000u\000r\000e}{section.2}% 3
\BOOKMARK [2][-]{subsection.2.2}{\376\377\000S\000e\000r\000v\000e\000r\000s}{section.2}% 4
\BOOKMARK [2][-]{subsection.2.3}{\376\377\000S\000e\000r\000v\000i\000c\000e\000s}{section.2}% 5
\BOOKMARK [1][-]{section.3}{\376\377\000W\000e\000b\000\040\000a\000p\000p\000l\000i\000c\000a\000t\000i\000o\000n\000\040\000s\000e\000c\000u\000r\000i\000t\000y\000\040\000t\000e\000s\000t\000i\000n\000g}{}% 6
\BOOKMARK [2][-]{subsection.3.1}{\376\377\000I\000n\000f\000o\000r\000m\000a\000t\000i\000o\000n\000\040\000G\000a\000t\000h\000e\000r\000i\000n\000g}{section.3}% 7
\BOOKMARK [2][-]{subsection.3.2}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000t\000i\000o\000n\000\040\000a\000n\000d\000\040\000D\000e\000p\000l\000o\000y\000m\000e\000n\000t\000\040\000M\000a\000n\000a\000g\000e\000m\000e\000n\000t\000\040\000T\000e\000s\000t\000i\000n\000g}{section.3}% 8
\BOOKMARK [2][-]{subsection.3.3}{\376\377\000I\000d\000e\000n\000t\000i\000t\000y\000\040\000M\000a\000n\000a\000g\000e\000m\000e\000n\000t\000\040\000T\000e\000s\000t\000i\000n\000g}{section.3}% 9
\BOOKMARK [2][-]{subsection.3.4}{\376\377\000A\000u\000t\000h\000e\000n\000t\000i\000c\000a\000t\000i\000o\000n\000\040\000T\000e\000s\000t\000i\000n\000g}{section.3}% 10
\BOOKMARK [2][-]{subsection.3.5}{\376\377\000A\000u\000t\000h\000o\000r\000i\000z\000a\000t\000i\000o\000n\000\040\000T\000e\000s\000t\000i\000n\000g}{section.3}% 11
\BOOKMARK [2][-]{subsection.3.6}{\376\377\000S\000e\000s\000s\000i\000o\000n\000\040\000M\000a\000n\000a\000g\000e\000m\000e\000n\000t\000\040\000T\000e\000s\000t\000i\000n\000g}{section.3}% 12
\BOOKMARK [2][-]{subsection.3.7}{\376\377\000I\000n\000p\000u\000t\000\040\000V\000a\000l\000i\000d\000a\000t\000i\000o\000n\000\040\000T\000e\000s\000t\000i\000n\000g}{section.3}% 13
\BOOKMARK [3][-]{subsubsection.3.7.1}{\376\377\000T\000e\000s\000t\000i\000n\000g\000\040\000f\000o\000r\000\040\000S\000Q\000L\000\040\000I\000n\000j\000e\000c\000t\000i\000o\000n}{subsection.3.7}% 14
\BOOKMARK [2][-]{subsection.3.8}{\376\377\000T\000e\000s\000t\000i\000n\000g\000\040\000f\000o\000r\000\040\000E\000r\000r\000o\000r\000\040\000H\000a\000n\000d\000l\000i\000n\000g}{section.3}% 15
\BOOKMARK [2][-]{subsection.3.9}{\376\377\000C\000l\000i\000e\000n\000t\000\040\000S\000i\000d\000e\000\040\000T\000e\000s\000t\000i\000n\000g}{section.3}% 16
\BOOKMARK [1][-]{section.4}{\376\377\000W\000e\000b\000\040\000A\000p\000p\000l\000i\000c\000a\000t\000i\000o\000n\000\040\000S\000e\000c\000u\000r\000i\000t\000y\000\040\000F\000i\000r\000e\000w\000a\000l\000l}{}% 17
\BOOKMARK [2][-]{subsection.4.1}{\376\377\000I\000n\000f\000o\000r\000m\000a\000t\000i\000o\000n\000\040\000G\000a\000t\000h\000e\000r\000i\000n\000g}{section.4}% 18
\BOOKMARK [2][-]{subsection.4.2}{\376\377\000C\000o\000n\000f\000i\000g\000u\000r\000a\000t\000i\000o\000n\000\040\000a\000n\000d\000\040\000D\000e\000p\000l\000o\000y\000m\000e\000n\000t\000\040\000M\000a\000n\000a\000g\000e\000m\000e\000n\000t\000\040\000T\000e\000s\000t\000i\000n\000g}{section.4}% 19
\BOOKMARK [2][-]{subsection.4.3}{\376\377\000I\000d\000e\000n\000t\000i\000t\000y\000\040\000M\000a\000n\000a\000g\000e\000m\000e\000n\000t\000\040\000T\000e\000s\000t\000i\000n\000g}{section.4}% 20
\BOOKMARK [2][-]{subsection.4.4}{\376\377\000A\000u\000t\000h\000e\000n\000t\000i\000c\000a\000t\000i\000o\000n\000\040\000T\000e\000s\000t\000i\000n\000g}{section.4}% 21
\BOOKMARK [2][-]{subsection.4.5}{\376\377\000A\000u\000t\000h\000o\000r\000i\000z\000a\000t\000i\000o\000n\000\040\000T\000e\000s\000t\000i\000n\000g}{section.4}% 22
\BOOKMARK [2][-]{subsection.4.6}{\376\377\000S\000e\000s\000s\000i\000o\000n\000\040\000M\000a\000n\000a\000g\000e\000m\000e\000n\000t\000\040\000T\000e\000s\000t\000i\000n\000g}{section.4}% 23
\BOOKMARK [2][-]{subsection.4.7}{\376\377\000I\000n\000p\000u\000t\000\040\000V\000a\000l\000i\000d\000a\000t\000i\000o\000n\000\040\000T\000e\000s\000t\000i\000n\000g}{section.4}% 24
\BOOKMARK [2][-]{subsection.4.8}{\376\377\000T\000e\000s\000t\000i\000n\000g\000\040\000f\000o\000r\000\040\000E\000r\000r\000o\000r\000\040\000H\000a\000n\000d\000l\000i\000n\000g}{section.4}% 25
\BOOKMARK [2][-]{subsection.4.9}{\376\377\000C\000l\000i\000e\000n\000t\000\040\000S\000i\000d\000e\000\040\000T\000e\000s\000t\000i\000n\000g}{section.4}% 26
\BOOKMARK [1][-]{section.5}{\376\377\000C\000o\000n\000c\000l\000u\000s\000i\000o\000n\000s}{}% 27

Binary file not shown.

View File

@@ -1,31 +1,12 @@
\documentclass[11pt,a4paper]{article}
\usepackage[portuguese]{babel}
\usepackage[lining]{ebgaramond}
\usepackage{listings}
\usepackage{booktabs}
\usepackage{style}
\lstdefinestyle{mystyle}{
basicstyle=\ttfamily\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2
}
\lstset{style=mystyle}
\setlength{\parindent}{0em}
\setlength{\parskip}{2ex}
\title{Practical Assignment \#2}
\title{Practical Assignment \#3}
\author{
João Neto -- 2023234004\\[1em]
Vasco Alves -- 2022228207
@@ -33,216 +14,514 @@
\begin{document}
\maketitle
\newpage
\tableofcontents
\newpage
\section{Introdução}
\section{Introduction}
Este projeto tem como âmbito implementar, uma rede virtual privada (VPN) num cenário
de road-warrior, configurar \textit{two-factor authentication} (2FA) com os serviços
OpenVPN e Apache, e gerir certificados X.509 utilizando OCSP.
% FAZER EM ENGLISH??? O prof é BR temos que fazer em Brazileiro
% NOTE(vasco): Eu acho que basta explicar o cenario e explicar como decidimos
% implementar
Este trabalho tem como objetivo realizar testes de penetração numa aplicação
cobaia (o \textit{Juicebox}) desenhada para aprendizagem.
% Para tal, foi implementado um servidor e um cliente OpenVPN, certificados por uma
% autoridade central (CA) que em si é \textit{self-signed}. Para além disto, foi implementado
% um sistema de autenticação de dois factores através do plugin
% \textit{google-authenticator} para o OpenVPN e para o servidor de Apache.
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}).
Decidimos utilizar apenas três máquinas virtuais: o cliente (ou \textit{road warrior}),
a \textit{gateway} que utiliza OpenVPN e um servidor interno com OpenSSL e Apache.
Isto simplifica a elaboração do projecto, mas por razões de segurança poderia querer
separar a máquina de OpenSSL de outras máquinas destinadas a serviços da rede intera,
pois esta contém o \textit{certificate authority} CA.
\section{Architecture Considered for Both Stages}
% Ambos o OpenVPN eo servidor Apache utilizam 2FA,
% recebendo o utilizador, e uma password que é uma concatenação da palavra-passe do utilizador
% e de uma password temporária (TOTP) de 6 dígitos. O servidor de Apache implementa a mesma autenticação.
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}).
\begin{tabular}{l l l}
% 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.
{\bf Nome} & {\bf Script} & {\bf Rede} \\\toprule
Road Warrior & VM\_ROAD\_WARRIOR.sh & Rede Externa 193.168.0.0/24 \\
VPN Gateway & VM\_OPENVPN\_GATEWAY.sh & Router \\
OpenSSL / Apache & VM\_OPENSSL\_APACHE.sh & Rede Interna 10.60.0.0/24 \\
% 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}
\section{Criação de certificados}
\subsection{Information Gathering}
Os certificados utilizados foram auto-certificados por uma autoridade central que "pertence"
à máquina de OpenSSL. Esta mesma faz a gestão da lista de revogação.
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.
Todas as chaves foram criadas no mesmo computador, com as variáveis que estão
neste código, aspetos importantes para mais tarde serão os parâmetros de CN
que precisam de ser passados mais tarde para aceder ao Apache e ao gateway.
Numa situação normal teríamos uma autoridade de certificação para enviar e
no fundo gerir todos, mas para este cenário podemos inicializar as máquinas
com as chaves, requests e certificados necessários.
% 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.
O código para gerar os certificados X.509:
Adicionalmente, realizámos testes de infraestrutura utilizando ferramentas especializadas:
\begin{lstlisting}[language=bash]
cert_ca="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=CoimbraVPN"
cert_vpn="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=gateway"
cert_user="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=warrior"
cert_apache="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=apache.coimbra"
\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}
openssl genrsa -out "ca.key" 2048
openssl req -x509 -nodes -days 365 -key "ca.key" -out "ca.crt" -subj "$cert_ca"
openssl genrsa -out "vpn.key" 2048
openssl req -new -key "vpn.key" -out "vpn.csr" -subj "$cert_vpn"
openssl ca -batch -in "vpn.csr" -cert "ca.crt" -keyfile "ca.key" -out "vpn.crt" -config cheese.cfg
openssl dhparam -out "dh2048.pem" 2048
openvpn --genkey secret "ta.key"
openssl genrsa -out user.key
openssl req -new -key user.key -out user.csr -subj "$cert_user"
openssl ca -batch -in "user.csr" -cert "ca.crt" -keyfile "ca.key" -out "user.crt" -config cheese.cfg
openssl genrsa -out apache.key
openssl req -new -key apache.key -out apache.csr -subj "$cert_apache" -addext "subjectAltName = IP:10.60.0.1,DNS:apache"
openssl ca -batch -in "apache.csr" -cert "ca.crt" -keyfile "ca.key" -out "apache.crt" -config cheese.cfg
\end{lstlisting}
Ao executar o \textit{sqlmap}, descobrimos que o sistema de gestão de
base de dados subjacente é o \textit{SQLite}.
% Porque é que precisamos de uma chave secreta?
% Criar chave secreta.
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{lstlisting}[language=bash]
openssl --genkey secret ta.key
\end{lstlisting}
\section{Configuração geral}
Para configurar as VMs era preciso introduzir os mesmos comandos várias vezes, o que levava muitas vezes a erros de escrita, ou a correr o mesmo comando várias vezes, por isso criamos vários ficheiros .sh para conseguir facilitar o processo. A utilização de ficheiros .sh também vem com outros positivos pois facilita a testagem, e a recriação do cenário rapidamente.
\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}
No entanto para os serviços que configuramos, instalar, desativar e dar flush às iptables não foi suficiente, tivemos que criar pastas e sincronizar os relógios de todas as VMs visto que elas estarem ligeiramente atrasadas nunca conseguíamos acertar na password do google-authenticator que utiliza o tempo local para calcular a sua chave.
\begin{lstlisting}[language=bash]
yum install -y epel-release
yum install -y openvpn iptables-services dhcp-client
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
systemctl enable iptables
iptables -F
CA_DIR="/etc/pki/CA"
mkdir -p "${CA_DIR}/newcerts"
mkdir -p "${CA_DIR}/private"
touch "${CA_DIR}/index.txt"
cp ca/serial "${CA_DIR}/serial"
mkdir -p /etc/openvpn/server
mkdir -p /etc/openvpn/client
# NOTE(vasco): tive problemas com a sincronizacao de tempo
# se nao tiver sincronizado, o TOTP nao funciona
systemctl stop chronyd
ntpdate pool.ntp.org
systemctl start chronyd
\end{lstlisting}
\section{Configuração da \textit{Gateway} VPN}
\subsection{Configurar TOTP}
Foi criado o ficheiro \texttt{totp} com a configuração de autenticação a
ser utilizada pelo plugin de PAM para o openvpn.
\begin{lstlisting}[language=bash]
plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so totp
\end{lstlisting}
Adicionalmente, devido às restrições de segurança do \textit{systemd},
foi necessário desativar o \texttt{ProtectHome} no serviço do OpenVPN
para que o plugin PAM consiga ler os ficheiros de segredo do Google Authenticator
localizados nas diretorias \textit{home} dos utilizadores.
\begin{lstlisting}[language=bash]
[Service]
ProtectHome=false
\end{lstlisting}
Primeiro, na gateway, entramos como o utilizador desejado e obtemos a chave
do gerador de palavras passes temporárias. Ao inserir a chave no
\texttt{google authenticator} podemos obter um código QR, a nossa primeira
chave de 6 dígitos.
\begin{figure}[h]
\begin{figure}[h!]
\centering
\includegraphics[width=8em]{google-authenticator}
\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}
\begin{lstlisting}[language=bash]
su john
google-authenticator
\end{lstlisting}
\subsection{Encaminhamento e Firewall}
Para que a gateway funcione como router entre a rede externa e a rede interna,
foi necessário ativar o \textit{IP forwarding} no kernel e configurar as regras
de \textit{iptables} para permitir o tráfego da VPN e realizar o mascaramento
de IP (NAT).
\subsection{Configuration and Deployment Management Testing}
% NOTA(vasco): Não temos regras de DROP a packets
% talvez deviamos mudar isso nao sei
\subsubsection*{Enumerate Infrastructure and Application Admin Interfaces}
\begin{lstlisting}[language=bash]
# Ativar encaminhamento
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
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.
# Regras de Firewall
iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT
iptables -I FORWARD 1 -i tun0 -o enp0s9 -j ACCEPT
iptables -I FORWARD 1 -i enp0s9 -o tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp0s8 -j MASQUERADE
\end{lstlisting}
\subsubsection*{Test HTTP Methods}
\section{Configuração do Cliente (Road Warrior)}
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.
O cliente encontra-se na rede externa (\texttt{193.136.212.10}) e liga-se à VPN
gateway na porta 1194. Para garantir a segurança, utilizamos autenticação mútua (os certificados X.509)
e um \textit{two factor authentication} (2FA) como palavras-passe temporárias, geradas através do
\textit{Google Authenticator}.
\subsubsection*{Test File Permission}
\begin{lstlisting}[language=bash]
client
dev tun
proto udp
remote 193.136.212.1 1194
ca ca.crt
cert user.crt
key user.key
auth-user-pass
cipher AES-256-GCM
auth SHA256
\end{lstlisting}
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.
\section{Servidor Apache e OCSP}
O servidor interno (\texttt{10.60.0.1}) alberga o serviço Apache e o responder OCSP
da autoridade de certificação.
\subsection{Revocation e OCSP}
\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{<h1>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 Estabelecer a ligação VPN e verificar a conectividade à rede interna.
\item No diretório da autoridade de certificação (máquina \textit{host}), revogar o certificado do utilizador:
\begin{lstlisting}[language=bash]
openssl ca -revoke user.crt -config cheese.cfg -keyfile ca.key -cert ca.crt
\end{lstlisting}
\item Atualizar o ficheiro \texttt{index.txt} no servidor OCSP e reiniciar o serviço para carregar o novo estado de revogação.
\item Tentar estabelecer uma nova ligação VPN e verificar que a autenticação falha devido à resposta \texttt{revoked} do responder OCSP.
\item \textbf{Injeção HTML:} Introduzimos o valor \texttt{<h1>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{<script>alert("someones gotta do it")</script>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}
<img src="x" onerror="alert('someones gotta do it')">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:
\section{Conclusão}
\begin{codeblock}{bash}
sqlmap -u "http://10.60.0.1:3000/rest/products/search?q=apple" -p q --dbms=sqlite --prefix="'%" --suffix="%'--" --tables --batch
% Conclusão!!!
Atingimos o objetivo deste trabalho, conseguimos configurar o VPN tunnel,
o two-factor authentication e conseguimos criar e retirar acesso aos
certificados que emitimos. Utilizar mais maquinas para simular um cenario
maior seria redundante, teriamos que emitir mais certificados mas não iamos
aprender muito mais.
[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}
<img src="x" onerror="alert(localStorage.getItem('token'))">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{<h1>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{<img src="x" onerror="...">} e \texttt{<h1>}, 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{<img src="x" onerror="alert(localStorage.getItem('token'))">})
é 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.
% Para aprofundar (???)
\end{document}

View File

@@ -1,11 +1,28 @@
\babel@toc {portuguese}{}\relax
\contentsline {section}{\numberline {1}Introdução}{2}{section.1}%
\contentsline {section}{\numberline {2}Criação de certificados}{2}{section.2}%
\contentsline {section}{\numberline {3}Configuração geral}{3}{section.3}%
\contentsline {section}{\numberline {4}Configuração da \textit {Gateway} VPN}{3}{section.4}%
\contentsline {subsection}{\numberline {4.1}Configurar TOTP}{3}{subsection.4.1}%
\contentsline {subsection}{\numberline {4.2}Encaminhamento e Firewall}{4}{subsection.4.2}%
\contentsline {section}{\numberline {5}Configuração do Cliente (Road Warrior)}{4}{section.5}%
\contentsline {section}{\numberline {6}Servidor Apache e OCSP}{5}{section.6}%
\contentsline {subsection}{\numberline {6.1}Revocation e OCSP}{5}{subsection.6.1}%
\contentsline {section}{\numberline {7}Conclusão}{5}{section.7}%
\contentsline {section}{\numberline {1}Introduction}{3}{section.1}%
\contentsline {section}{\numberline {2}Architecture Considered for Both Stages}{3}{section.2}%
\contentsline {subsection}{\numberline {2.1}Network structure}{3}{subsection.2.1}%
\contentsline {subsection}{\numberline {2.2}Servers}{3}{subsection.2.2}%
\contentsline {subsection}{\numberline {2.3}Services}{3}{subsection.2.3}%
\contentsline {section}{\numberline {3}Web application security testing}{4}{section.3}%
\contentsline {subsection}{\numberline {3.1}Information Gathering}{4}{subsection.3.1}%
\contentsline {subsection}{\numberline {3.2}Configuration and Deployment Management Testing}{4}{subsection.3.2}%
\contentsline {subsection}{\numberline {3.3}Identity Management Testing}{6}{subsection.3.3}%
\contentsline {subsection}{\numberline {3.4}Authentication Testing}{7}{subsection.3.4}%
\contentsline {subsection}{\numberline {3.5}Authorization Testing}{7}{subsection.3.5}%
\contentsline {subsection}{\numberline {3.6}Session Management Testing}{9}{subsection.3.6}%
\contentsline {subsection}{\numberline {3.7}Input Validation Testing}{9}{subsection.3.7}%
\contentsline {subsubsection}{\numberline {3.7.1}Testing for SQL Injection}{10}{subsubsection.3.7.1}%
\contentsline {subsection}{\numberline {3.8}Testing for Error Handling}{10}{subsection.3.8}%
\contentsline {subsection}{\numberline {3.9}Client Side Testing}{11}{subsection.3.9}%
\contentsline {section}{\numberline {4}Web Application Security Firewall}{11}{section.4}%
\contentsline {subsection}{\numberline {4.1}Information Gathering}{12}{subsection.4.1}%
\contentsline {subsection}{\numberline {4.2}Configuration and Deployment Management Testing}{12}{subsection.4.2}%
\contentsline {subsection}{\numberline {4.3}Identity Management Testing}{13}{subsection.4.3}%
\contentsline {subsection}{\numberline {4.4}Authentication Testing}{13}{subsection.4.4}%
\contentsline {subsection}{\numberline {4.5}Authorization Testing}{13}{subsection.4.5}%
\contentsline {subsection}{\numberline {4.6}Session Management Testing}{13}{subsection.4.6}%
\contentsline {subsection}{\numberline {4.7}Input Validation Testing}{13}{subsection.4.7}%
\contentsline {subsection}{\numberline {4.8}Testing for Error Handling}{14}{subsection.4.8}%
\contentsline {subsection}{\numberline {4.9}Client Side Testing}{14}{subsection.4.9}%
\contentsline {section}{\numberline {5}Conclusions}{14}{section.5}%

View File

@@ -8,7 +8,7 @@
\usepackage[dvipsnames]{xcolor}
\usepackage{enumitem,amssymb}
\usepackage[colorlinks=true,urlcolor=blue,linkcolor=MidnightBlue]{hyperref}
\graphicspath{{./img/}}
\graphicspath{{./imgs/}}
\usepackage{enumitem,amssymb}
\newlist{todolist}{itemize}{2}
@@ -17,7 +17,47 @@
\usepackage{pifont}
\usepackage{amssymb}
\usepackage{minted}
\usepackage[most]{tcolorbox}
\tcbuselibrary{listings, skins, breakable}
\lstdefinestyle{mystyle}{
basicstyle=\ttfamily\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2,
commentstyle=\color{gray},
keywordstyle=\color{MidnightBlue}\bfseries,
stringstyle=\color{ForestGreen}
}
\newtcblisting{codeblock}[2][]{
enhanced,
breakable,
colback=gray!2!white,
colframe=gray!20!black,
attach boxed title to top left={yshift*=-\tcboxedtitleheight/2, xshift=4mm},
boxed title style={
colback=gray!20!black,
outer arc=0pt,
arc=0pt,
top=1pt,
bottom=1pt,
},
fonttitle=\bfseries\ttfamily\footnotesize,
title={#2},
listing only,
listing options={
style=mystyle,
language=#1,
}
}
\setlength{\parskip}{1em}%
\setlength{\parindent}{0em}%

21
relatorio/texput.log Normal file
View File

@@ -0,0 +1,21 @@
This is pdfTeX, Version 3.141592653-2.6-1.40.29 (TeX Live 2026/Arch Linux) (preloaded format=pdflatex 2026.5.3) 29 MAY 2026 20:43
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
**
! Emergency stop.
<*>
End of file on the terminal!
Here is how much of TeX's memory you used:
4 strings out of 469495
118 string characters out of 5470099
433756 words of memory out of 5000000
28764 multiletter control sequences out of 15000+600000
627721 words of font info for 40 fonts, out of 8000000 for 9000
16 hyphenation exceptions out of 8191
0i,0n,0p,1b,6s stack positions out of 10000i,1000n,20000p,200000b,200000s
! ==> Fatal error occurred, no output PDF file produced!

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More