Can’t Even Order a Pizza Safely

Validate input from all sources!

What caught my eye was address information that is not pulled from a backend database:

Papa Johns - Stored Address Info

Where are you stored!?

Values are stored in the “pjCustomer” cookie, not encrypted, right there for you (or another device user) to read:

Papa Johns - Cookie Address Storage

Plaintext

The server does not handle tampered input well–specifically opening and closing script tags:

Papa Johns - Exception

Exception!

Maybe data stored in this cookie is not validated here because it was set by the server in an earlier web page when a visitor first inputs address information. There the server does a lookup to ensure it is a real address. Once the server validates the address, it locates the closest store and proceeds through the workflow. Perhaps at this point it is assumed that pjCustomer data is safe.

Like other input sources, data stored in cookies should be checked for tampering: https://www.owasp.org/index.php/Data_Validation#Prevent_parameter_tampering
CWE-472: External Control of Assumed-Immutable Web Parameter: http://cwe.mitre.org/data/definitions/472.html

Share

Disclosed (Patched): AddThis Email Sharing Button API XSS and Iframe Injection

Four days ago the AddThis Email Sharing Button API was vulnerable to cross-site scripting (XSS) and iframe injection. The PHP backend service endpoint that handles form submissions would reflect back payloads sent to one parameter in particular. The “tofriend” parameter got left behind when protections were applied to all others. Payloads sent to other parameters were effectively blocked from executing.

Because values sent to the “tofriend” parameter were embedded in an element’s attribute in the response page, it was possible to terminate this attribute prematurely with a double quote and then write your payload. A little circumvention was also needed because on the server side AddThis was checking for pairs of script tags to block. Read more about different XSS payload forms by following the link at the end of this post.

AddThis Email Sharing Button

AddThis Email Sharing Button and Form

 

XSS

XSS was possible with payloads of at least two different forms via the following vector when the “Request expired, please try again” page was returned from POST requests to /tellfriend.php.

  • Image tag payload supplied to the “tofriend” parameter sent to the “tellfriend.php” endpoint page via POST request. Example payload: filler”></span><IMG%20SRC%3d/%20onerror%3d”alert(String.fromCharCode(88,83,83))”></img><span%20class%3d”filler
Image Tag XSS Payload Supplied by Burp Proxy

Image Tag XSS Payload Supplied by Burp Proxy

Resulted in …

XSS Payload Executed in Firefox

XSS Payload Executed in Firefox

  • Inline style attribute payload in the “tofriend” parameter sent to the “tellfriend.php” endpoint page via POST request. This is the same form used in the Telerik CVE disclosure. Example payload: filler”></span><div STYLE=”background-image: expression(alert(‘XSS’))”></div><span class=”filler
XSS Div Style Attribute Payload

Div Style Attribute XSS Payload Supplied by Burp Proxy

Resulted in …

Internet Explorer (IE) XSS Execution

Internet Explorer (IE) XSS Execution

 

Iframe Injection

Iframe injection was possible via the following vector when the “Request expired, please try again” page was returned.

  • Iframe payload in the “tofriend” parameter sent to the “tellfriend.php” endpoint page via POST request. Example payload: filler”></span><iframe id=”mainframe” width=”400″ height=”200″ src=”http://example.org/iframeDocument.html”>Iframes not supported.</iframe><span class=”filler
Iframe Injection Payload

Iframe Injection Payload Supplied by Burp Proxy

Resulted in …

Iframe Injection Execution

Iframe Injection Execution

 

Deploying the Payload

Each example posted here contains a payload and additional characters–what are they for? Well, the original HTML response embedded the “tofriend” parameter’s value within the “value” attribute of an input tag. So our submitted payload has extra content whose job was to terminate that value, then its containing element, then create our malicious payload within an element we create (image tag, div tag, iframe tag, etc), then finally create an opening span tag to mesh with the rest of the HTML ensuring everything flowed smoothly and the response page got rendered successfully.

 

Different XSS Payload Formats

Here is information on different XSS payloads that may work in different browsers. For example, the div style attribute payload worked in IE but not Firefox, etc. https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

 

Exploiting XSS Over HTTP POST

And here is information on auto-submitting forms to exploit XSS vulnerabilities over HTTP POST: http://ha.ckers.org/blog/20060814/exploiting-cross-site-scripting-through-post/

 

Thanks to Matt Abrams and the rest of the AddThis engineering team for quickly deploying a fix.

Share

Injecting yourself into email threads without an invitation #partycrashing

You probably trust that emails within a thread belong together, right?

Injecting yourself into Gmail threads is like rudely butting into a conversation at a cocktail party. Here we’ll go over how, with two pieces of data, you can inject yourself into the existing email thread of a target person. While not earth-shattering information, this technique can perhaps be leveraged for social engineering, during a penetration test, or while on a phishing expedition.

You need to know the subject line and Message-ID of an email in the thread that you want to inject yourself into. Armed with these two, you can join in the threaded conversation from the outside, and a rushed or unobservant office worker may not notice that you do not belong in that conversation. The subject line is what you’re accustomed to setting when you write in a subject for an email. As it turns out, you are even able to get away with similar subject lines in Gmail: “test” and “Re: test” will both work in this case. Apparently there is some leeway here and other variants work as well. The Message-ID is a globally unique identifier of the digital message, is part of the email header, is typically not viewable to the user, and is automatically generated for the domain where the email was generated. For Gmail, that would be within the “mail.gmail.com” domain.

Obtain (by whatever your means) the Message-ID of an existing message in the target thread, and place it into both the “In-Reply-To” and “References” fields of the email header of an email that you will craft specially. For more information about the purpose of these two fields, read the full RFC here: http://tools.ietf.org/html/rfc2822.

Now, I do not believe that you can edit email headers through Gmail’s Web interface or through a client such as Thunderbird, but here is a Python script that you can use to send email through a Gmail account you control to your target. This script has been configured for Gmail but can be modified to use other SMTP servers if you wish.

import os
import smtplib
import mimetypes
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEAudio import MIMEAudio
from email.MIMEImage import MIMEImage
from email.Encoders import encode_base64

def sendMail(yourEmail, yourPassword, subjectLine, bodyText,
  targetEmail, messageID, *attachmentFilePaths):
  gmailUser = yourEmail
  gmailPassword = yourPassword
  recipient = targetEmail
  msg = MIMEMultipart()
  msg['From'] = gmailUser
  msg['To'] = recipient
  msg['Subject'] = subjectLine
  msg['In-Reply-To'] = messageID
  msg['References'] = messageID
  msg.attach(MIMEText(bodyText))
  for attachmentFilePath in attachmentFilePaths:
    msg.attach(getAttachment(attachmentFilePath))
  mailServer = smtplib.SMTP('smtp.gmail.com', 587)
  mailServer.ehlo()
  mailServer.starttls()
  mailServer.ehlo()
  mailServer.login(gmailUser, gmailPassword)
  mailServer.sendmail(gmailUser, recipient, msg.as_string())
  mailServer.close()
  print('Sent email to %s' % recipient)

def getAttachment(attachmentFilePath):
  contentType, encoding = mimetypes.guess_type(attachmentFilePath)
  if contentType is None or encoding is not None:
    contentType = 'application/octet-stream'
  mainType, subType = contentType.split('/', 1)
  file = open(attachmentFilePath, 'rb')
  if mainType == 'text':
    attachment = MIMEText(file.read())
  elif mainType == 'message':
    attachment = email.message_from_file(file)
  elif mainType == 'image':
    attachment = MIMEImage(file.read(),_subType=subType)
  elif mainType == 'audio':
    attachment = MIMEAudio(file.read(),_subType=subType)
  else:
    attachment = MIMEBase(mainType, subType)
  attachment.set_payload(file.read())
  encode_base64(attachment)
  file.close()
  attachment.add_header('Content-Disposition', 'attachment',
    filename=os.path.basename(attachmentFilePath))
  return attachment

if __name__ == "__main__":
#Edit the following arguments with your values
  sendMail("yourEmail", "yourPassword", "test",
    "Hello, thread.", "targetEmail",
    "Message-ID")

The important take away from all this is that you can insert your email into a thread that you were not privy to in the first place, and you do not even have to send your message from an email address within the same domain as the recipient(s). Shout out to @baffles for pointing me to the correct parts of the RFC to focus on for this and for testing this out with me.

Caveats and things to note:

  • This has only really been tested briefly with Gmail
  • You can modify this script to supply multiple values to “References” but I do not know the pros and cons of doing so
  • How Message-ID is generated will be the subject of future research
Share