How I stole the identity of every Yahoo user

When looking at bug bounty programs that have existed for a long time it’s often beneficial to assume that every public facing page has already been automatedly scanned to death. In many cases this isn’t valid because of the types of tools people use, different scopes people prefer, or the tendency for these scanners to break or return false positives but approaching something with a realistic mindset can be fruitful.

Vulnerability scanners like BURP professional suite, acunetix, and Nessus are great – but they’re sometimes lazy. One of the most commonly missed services on web applications undergoing a pentest are mailing systems due to their spread area of effect. There aren’t many scanning tools that will check the contents of an email received from the site, so therefore there is room to attack where no-one else has.

If you take a look at Yahoo’s fantasy sports platform for a while you’ll see how much does pertain to email. Starting a fantasy league? Why don’t you invite some friends. Want to run that league better? Invite a co-manager! All of these forms (the image above is an example of an invitation form) will trigger actions on the web service to send an email. The logical process looks something like this:

Logical order of events
  1. The user enters the name and email address of whomever they’d like to invite to the program them submits the form.
  2. <form method="POST" action="inviteUser">
    <input type="text" id="email" value="">
    <input type="text" id="name" value="Sam Curry">
  3. Yahoo processes the name and email and appends them to variables. If they were using PHP, it’d look something like this:
  4. $email = $_POST['email']; //
    $fullname = $_POST['fullname']; //Sam Curry
  5. Yahoo finalizes the string and passes it to a function that will actually do the sending (an example of one of these functions would be PHP’s mail function). An example of this code is below:
  6. <?php
    $to      = $email; //
    $subject = 'Hi '.$fullname; //Hi Sam Curry!
    $message = 'n/a'; //this header is not being addressed currently
    $headers = 'From:' . "\r\n" .
    mail($to, $subject, $message, $headers);
  7. The user will receive an email with the following content somewhere inside of it:
  8. From: <>
    Subject: Hi Sam Curry!

How would I exploit this?

Something tied deeply within most applications and systems are symbols that describe the end of a line. In windows, the symbols “\r\n” are used whenever an author would like to go to the next line. In other systems like <= Mac OS 9, all that is needed to accomplish this is the “\r” symbol. In Unix (or Mac OS X) the “\n” symbol is all that is required.

This entity is somewhat comparable to HTML’s <br> tag as it accomplishes the same task of breaking the line to continue to the next line. In the below example a comparison is made between “break” tags and “carriage return, line feed” symbols. The first example is an HTML document…

Hi! I'm sam! This is my sloppy HTML!<br>
Instead of chunking both of these lines as a paragraph I split them where the "br" tag was!

… while a text file with “carriage return, line feed” would look like this…

Hi! I'm a standard Windows text file! I was created in notepad.\r\n
Woah! The text just split into two lines instead of staying on one because of the symbols \r\n!

By inserting these “carriage return, line feed” symbols within their request, the attacker can add additional HTTP headers that will override headers stated after the injection point. An example scenario is below:

POST /invitation
Host:>\r\nSubject: you have been hacked!\r\nCookie:

In this request we can see that…

  1. The “to” email was supplied so the victim will receive the message (the > tag at the end was used in order to close the formatting for the “to” tag. The result of this can be seen in the response below).
  2. The “Subject” tag was modified to demonstrate our proof of concept.
  3. The “Cookie” header was supplied in order to scrape up the data that would normally be projected after the standard invitation request.

The response would look something like this…

To: <>
Subject: you have been hacked!
Cookie: >

Exhibit one: mailed-by and signed-by

The “mailed-by” and “signed-by” receipts state where exactly the message came from. If you’re ever unsure whether or not something is spam you’d usually check if (1) the message is encrypted, (2) the message is being mailed by a trusted domain, and (3) the contents of the emails sources. Since we’re mailing free-roam inside of Yahoo’s platform we can send whatever content we’d like beyond the header we’re modifying (you can’t delete pre-existing data before the first injection point). This means that if I wanted to, I could write a few breaks then inject “From: admin@[sending domain]” and Gmail would say it was valid to the victim. These messages would seem very authentic and match almost all heuristics used in attempting to verify the integrity of a message.

Exhibit two: attacking multi-part

Content-Type: text/plain; charset=UTF-8;
Content-Transfer-Encoding: 8bit

Some of these mail functions will inject content post-header section and that’s kind of sucky. If this occurs, however, there is still room for exploitation. Let’s re-visit something commonly used in web requests, emails, and general HTTP: multipart forms. If the function is sending content using multipart data forms with a predictable separator it is then very easy to modify additional content.

Let’s say you have a very simple function that sends the content “text/plain” to a specified user with a message held within. The developer doesn’t sanitize the data since there’s no real way the user could modify the email content to be malicious besides “plz go to”… right? Wrong. An attacker could simply break the email by submitting a few native returns then changing the content type to something bad like “text/html”. The attacker could additionally attach files to the email using things like “Content-disposition” mail headers. This is fixed by having unpredictable multipart boundaries — but fundamentally by not allowing CRLF injection.

Sam has sent the following message:
Hello \r\n
Content-Type: text/html; charset=UTF-8;\r\n

<a href=''>Click me!</a>

Exhibit three: pretending to be the admin

Some mail clients that victims use will have automatic checks to see whether or not something is spam. Gmail, for instance, will check to see if there are multiple “From” tags. This check is defeated if the injection point occurs before the from tag is explicitly defined OR the attacker has control of the from tag. The reason being for this is because the “From” header can be cancelled out or modified post-injection/at injection because another one can be stated and included as the valid one.

In order to cancel out a “From” tag one may simply inject it as hidden HTML content, encode it as base64 using “Content-disposition”, or use any other method to push the “From” tag to included as non-header material.

If the attacker would like to pretend to be someone else then these pre-existing conditions must be met. All the attacker do, at this point, is declare theirself as “admin@[sending domain]” and they’ll be validated, signed, and sent as an administrator.

Subject: injectable content.. but I can't pretend to be an admin due to filtering in most mail clients! damn.
The above is an example of a non-exploitable (if you’re trying to get around Gmail, Yahoo, AOL, or any other top 20 mail client filtering) injection for the from tag
Subject: injectable content! woo! \r\n
From: \r\n
[additional headers] \r\n
<style>#hidden{}</style><a href=''>Click me!</a><div id="hidden">
The above example is an example whereas an attacker can pretend to be an administrator (or any other user). Please note – the original “from tag” is appended after the div

Additional ramifications: Yahoo specific

When loading emails using Yahoo’s mail client it will usually ask you whether or not you’d like to load an image within an email. There are certain senders within Yahoo, however, who are white-listed from this property. If a user receives an email they’ll usually have to click “allow images”, but if the email is from an explicitly defined then the images are automatically loaded. By sending emails as anyone from Yahoo, attackers can send HTTP 401 attacks (image authentication injection) to victims browsing with an insecure browser.

Reward: $1,250
CVSS Score: 6.5

2 thoughts on “How I stole the identity of every Yahoo user”

  1. Terrific post however , I was wanting to know if you could write a litte more on this subject? I’d be very thankful if you could elaborate a little bit further. Appreciate it!

    1. Of course! Is there anything you’d like me to expand upon or just write a more technically extensive article?

Leave a Reply

Your email address will not be published. Required fields are marked *