Posted by gavin on April 22, 2015, 6 p.m.
At Fusionbox we are using Harvest for time tracking. To ease the use of Harvest, I recently worked with Harvest platform to add support for time tracking to our internal bug tracker and with Harvest OAuth for a status dashboard. While working on these projects, I discovered several security vulnerabilities.
All the vulnerabilities discussed here were reported to Harvest through their Responsible Security Disclosure program and have since been fixed.
Throughout the examples, ‘Alice’ is a user of Harvest, and ‘Mallory’ is trying to attack her.
Harvest platform is how Harvest supports adding time-tracking buttons to your own applications. This is useful for bug or issue trackers, because Harvest supports attaching the bug title and URL to the time log, and displays a link to the bug in time reports.
Harvest was not validating the protocol of the URL sent by the bug
tracker, so it allowed
payload as a URL, like
payload would be executed when Alice clicks the link. This allows
Mallory to take complete control over Alice’s Harvest account.
CSRF Token fixation
A little-known fact about cookies and HTTPS is that cookies set over HTTP can be read over HTTPS. This can be exploited by a man-in-the middle present a fake HTTP version of your site and setting cookies. The tricky part is that this is not detected by TLS—Mallory is forging the HTTP version of the site, not HTTPS.
Mallory obtains a valid
_harvest_sesssession cookie, which contains a valid CSRF token, by visiting
Mallory presents her version of
http://fusionbox.harvestapp.com/, which sets the session cookie created previously, to Alice. Alice is now using the CSRF token that Mallory knows.
Alice logs in to harvest. Mallory can now mount a CSRF attack because she knows Alice’s token.
It’s important to regenerate the session and CSRF tokens when permission levels change. You can see how this happens in Django’s `login` function.
Secure flag on session cookies
When using HTTPS, it’s important to set the
on session cookies. Otherwise, the browser will send the cookie for
plain HTTP requests, not just HTTPS. An attacker can initiate an HTTP
request trick a browser into revealing the cookie over plain HTTP by
<img> tag (for example, there are other ways to trigger a
cross-domain request) to a page the target loads.
Hijacking the post-login redirect through OAuth handling
Harvest allows third-party applications to authenticate to Harvest using OAuth. When an application wants to use a user’s credentials, the application sends the user to an approval page where the user has an option to approve or decline the application’s request. Once they approve the application, Harvest redirects back to a URL of the application’s choice.
The problem lies in how Harvest was storing the state of the OAuth approval process. Once a user visits the authentication-request page, the application’s success redirect URL is stored in the user’s session. The redirect URL will be used after the user logs in later, even if it’s from the normal harvest login page.
The exploit looks like this:
Mallory, the attacker, wants to send Alice, the target, to some nasty destination when Alice logs in to harvest.
Mallory embeds a Harvest OAuth authentication-request page for her application,
https://fusionbox.harvestapp.com/oauth2/authorize?redirect_uri=https%3A%2F%2Fharvest.firstname.lastname@example.org%2F&response_type=code&client_id=azg3pKHNIj3r247PqbhmgQ, in an invisible iframe on an innocent-looking page that Alice visits. Alice doesn’t see anything related to harvest, but her session has been poisoned to redirect to Mallory’s choice of redirect URL.
Alice leaves Mallory’s page and goes to do something else, unaware that anything has happened.
Later, Alice goes to her normal harvest login page and enters her credentials:
Instead of going to her Harvest account like she should, she sees Mallory’s authentication-request page, which has been disguised to hide its purpose:
Of course ‘Harvest time tracking’ should have access to Alice’s account!
When Alice approves the request (or declines, for that matter, since either way Harvest will redirect back to Mallory), she will be redirect to Mallory’s nasty URL instead of going to Harvest.
This problems stems from overuse of Sessions to store state. Web requests should be stateless, so a Session value should never control the post-login redirect.