Behind the news: Authentication gone wrong

Personal - and in some cases sensitive - information about 63,000 students could be accessed. Here are the details that the newspaper article did not give.

Published: Mon, September 10, 2018, 06:55
Information leak
Social Security numbers
Behind the news
OWASP 2013 A2
OWASP 2013 A3
OWASP 2013 A5

Background 🔗

I got in contact with a parent concerned about the security in a new messaging app used for communication between pupils, teachers and parents (Norwegian link) in the schools of Oslo. The app - which is called Skolemelding - was released this summer and is developed by CGI Norge. Unfortunately the concerns turned out to be justified. Please note that I was not the one to discover any of these issues.

The Norwegian newspaper Aftenposten broke the news about the vulnerabilities September 6th (follow-up article) and the system was temporarily shut down.

Security issues 🔗

The security vulnerabilities were really bad. The system is designed for sending messages between school and home, including messages related to student absence. According to Norwegian law health information is regarded as sensitive personal information, and therefore I would assume that the system should be designed with the appropriate security level to prevent unauthorized access.

Anyone with either a valid login or anyone who got hold of a guardian's Social Security number could access any and all messages across all 63,000 pupils + guardians and teachers. This includes not only communication between guardians and school, but also communication between teachers was accessible through these vulnerabilities.

Anyone who got hold of a guardian's Social Security number could access details about a pupil's family (full names, Social Security Numbers, usernames, e-mail addresses, phone numbers) (in addition to the guardian's messages). I have published a couple of cases where one easily could get a specific person's Social Security number.

Technical details 🔗

The apps 🔗

There are two apps - one for parents and one for teachers + students. Looking at the Android apps they are pretty much the same app with just different build variant (flavors). Parents use a different login than the teachers and students.

The apps are built using React Native with all the functionality bundled in a JavaScript file. Seemingly you get the same functionality by logging in on the web as in the apps.

Reading anyone's messages 🔗

To fetch a message the app calls /api/message/GetMessageWithId?messageId=[ID1]&threadId=[ID2]&isReplyAllowed=[true|false]&onBehalfOf=[pupil's username].

This is where we find the first failure. The server did not do an authorization check on the messageId and therefore let one read any other message in the system. And to make this a huge problem; the IDs were a sequential number that let one go through all messages available.

Log in as someone else 🔗

The parent/guardian version of the app uses a common log-in solution by the Agency for Public Management and eGovernment (Difi) called ID-porten. The teacher + student version of the app uses a log-in solution called Feide - a pretty common solution among schools. It's important to emphasize that there were no weaknesses in these two solutions in this case. However, the usage and implementation in the apps was horrible.

In the parent version of the app, when pressing the Log in button, the user is taken through the log-in flow of ID-porten as expected. However, there was a big flaw in the logic of the authentication server (called midporten) used by this system. The "token" returned from that server was just the user ID - the parent's Social Security number. One could intercept the call at this stage and replace the user ID/SSN with another one and get full access.

Log in by just skipping the authentication system 🔗

Reading the last sentence you might ask what the client really did with the user ID. Well, the client sent the user's SSN to the school portal (the app's API) to generate an access token. This means that it was possible to just skip the whole flow of midporten and ID-porten and just ask the app's backend to get an access token for any valid user ID. Wow.

So the flow was like this (with optional faking of user ID in either step 5 or 6):

  1. Tell midporten you want to log in
  2. Tell ID-porten which electronic id you want to use
  3. Do the log-in process with ID-porten
  4. Get authentication response from ID-porten and forward to midporten
  5. Tell midporten which user ID/SSN just logged in
  6. Tell app's API which user ID/SSN you want to log in as and get an access token for it
LDAP to the people 🔗

While not a direct flaw, it is interesting to look at the structure of the data from the server. There's a call going to /api/settings which returns information about the logged in user and the belonging student(s). The JSON returned is actually LDAP data. And it contains full names, usernames, e-mails, Social Security numbers, possibly phone numbers of guardians and belonging student(s). It looks like a dump of the LDAP. Why would one need this information in the app? And why are Social Security numbers stored in a way like this in a directory where an app has access? We're talking about hundreds - maybe thousands - of lines of LDAP data.

Is that a good fix? 🔗

The fix for the login vulnerability was - instead of sending the user ID to generate the access token - to send a JSON Web Token (JWT). The JWT does not contain any user information, meaning that it has be checked on the server side to see which user is asking for an access token.

What is surprising is that the JWT does not contain some internal user ID (like a UUID), but rather a timestamp. And the JWT cannot actually be verified on the backend (other than string comparison) as it is sent back as lower-case.

What happens if two users log in at the exact same time? Is it possible that the timestamps (and therefore JWT) can end up being the same? Would one user get access to the other?

Could there be more? 🔗

With these vulnerabilities you can start to wonder if there are other problems here. I have not tested any of these things, but it is something for the vendor to look into.

It looks like the messages in the app support HTML markup. Does the server and clients handle data escaping properly?
File storage
It's interesting to take a look at the file names and directory structure of the server. It really makes you wonder if there could be weaknesses and vulnerabilities related to naming of files.
Logs with SSN?
Some of the requests contained Social Security numbers in the query parameters. This means that there probably are logs with many SSN. Is this okay?

Responsible disclosure?

I understand how Aftenposten wanted to get out the news about this as fast as they could. And they did indeed warn the City of Oslo before publishing it to give them a heads-up and chance to shut down the system. They only right thing to do here was to shut down the system immediately as someone might soon find the issues or maybe already was abusing them. So this wasn't too bad, but I would have liked to see CGI Norge and the City of Oslo get some more time to look at the issues and confirm that they had fixed them before publishing the article.

Conclusion 🔗

It's easy to make mistakes when programming, and not all programmers will have a good enough understanding of security (though I think we should try to improve this!). What really sticks out here is how both CGI Norge and the City of Oslo could release a product like this without testing the security. I do not believe this is a case where a pen tester overlooked something. This must be a case where there has been no external testing of the system. And that's a shame.

Get notified when there are new posts! :-)