193 - ImageMagick, Cracking SmartLocks, and Broken OAuth
Relatively straight forward oauth hijack/account takeover flow with one interesting aspect in actually performing the login with the hijacked OAuth code.
The straight forward part is leaking the code from Facebook. Facebook’s side of the system only validates that teh
redirect_uri belongs to the appropriate domain. This isn’t terribly unexpected, but combined with an open-redirect somewhere within the Booking.com domain one can have the victim redirected to an attacker controlled location with the code in the URL.
Which is the first issue documented, an open redirect. I’m not exactly sure what Booking.com was thinking here but under the Dashboard there is an option to ‘Add a Display Name’ and clicking that takes you to a domain like the following:
It looks like an OAuth flow page, though according to the author it just redirects off to the
/mysettings/personal endpoint. And that redirection happens based off of a Base64 encoded JSON content that is encoded into the
state parameter. The
mysettings_path from that JSON content is used to craft the redirect URL, and one can encoded their own URL pointing to another domain and have it redirect. So its an odd endpoint, but still an open redirect.
Now with the ability to steal codes used the open redirect, the challenge is logging in. Which did have a bit of an extra difficulty. Usually one could take the stolen code, and then during a legitimate OAuth flow tamper with their request, replacing the code returned by Facebook with the stolen code. The application iwll take that code and do its usual flow with it. The problem is that you send the
redirect_uri with the
code during the exchange process. The Booking server doesn’t know an abnormal
redirect_uri was used, so it sends along the normal one, and when Facebook sees that it throws back an error because the
redirect_uri doesn’t match the one used.
Fortunately for the authors here, the Booking mobile application had a bit of a weird process going on, where it would receive the code send it to booking.com backend, which would redirect it back to the back (using a deep link as its redirect), which would then send the code again to the server. When the code is passed to the backend for the second time, it sends a
resultUri parameter, this parameter is used as the
redirect_uri when exchanging the code. So by passing in the malicious
redirect_uri value in that request, the flow will complete as expected, granting an account takeover.
A long, fairly beginner friendly post about attacking a Bluetooth lock, there is a lot of process information here as it was an intern’s research project. What the vulnerability comes down to though is a lack of any real authoization checking instead only validating the integrity (poorly!) of the request and trusting the app did all the heavy lifting.
What they found was that the lock would communicate with the mobile application over bluetooth and the app would communicate over HTTP (not even HTTPS) with the backend API that actually performed most of the actions. tampering with the request resulted in an warning about illegal access to resources. This was because of a custom
SecSignDest header containing what appeared to be a MD5 hash. After some digging about how this header was crafted it was a MD5 of the request data (date, data, and path) along with a fixed “OKLOK” string.
Being able to craft their own
SecSignDest header was all that was necessary as there was not authorization or authentication checking. So they could go ahead and unbind a lock from the victim’s account and bind it to their own.
Several fun issues found in DataHub by GitHub Security Lab, we won’t summarize all of them here but a few of our favorites:
Missing JWT signature check - Basically the backend was not verifying the signature of JWTs. This was likely because of a confusion around using the JWT libary as the
parsePlaintextJws methods both validate the signature, but the
parse method they used does not.
System account impersonation - All comes down to a case-sensitive string comparison. The application used a
X-DataHub-Actorheader when proxying requests to indicate who the request was made on behalf of. Naturally you don’t want attackers to be able to provide that header themselves so they have code in-place to remove it if found. The problem being that the code removing the header was case-sensitive, but the backend service looked for the header in a case-insensitive way.
JSON Injection - The
AuthServiceClient which, as the name implies, handles authentication would build up JSON strings using format strings without checking for any context breaking characters. So if one provided a string that would be reflected in the output JSON containing a
" character, they could break out of the string and start adding new key/value pairs to the JSON. They abused this to create an account with the email
__datahub_system which is a special value used to indicate a system account is making the request.
Login fail open on JAAS misconfiguration - The
authenticateJaasUser method wraps the login service access in a try/catch block. Normally when a login fails, it’ll raise a
LoginException which is explicitly caught, but any other exception is simply ignored, with a comment saying this should never happen. Of course, it can happen if the JAAS configuration has an error, in which case it’ll fail-open. The liklihood of an invalid JAAS configuration is relative low, but still failing open is a poor choice.
In resizing a PNG, in a textual chunk you have keywords and a text string as a value, if the keyword
profile is used, imagemagick will try to read the associated filename (the text value for the keyword) and will load the content of the file (if it exists) into the resultant image. So in cases where a user uploaded image is resized or processed in some way by imagemagick, it may be possible to leak file content in the resulting image.