Skip to content

Instantly share code, notes, and snippets.

@mehitabel
Forked from cyrozap/pyCookieCheat.py
Last active August 29, 2015 14:08
Show Gist options
  • Select an option

  • Save mehitabel/cec86856d3d9a35a3dbe to your computer and use it in GitHub Desktop.

Select an option

Save mehitabel/cec86856d3d9a35a3dbe to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""pyCookieCheat.py
2014-10-28 Modified to FUCK ALL COOKIES (quit Google Chrome first) --Jeigh
20140701 v 2.1: Modularized the code, made it compatible with Python 2, and added an encryption function
Use your browser's cookies to make grabbing data from login-protected sites easier.
Intended for use with Python Requests http://python-requests.org
Accepts a URL from which it tries to extract a domain. If you want to force the domain,
just send it the domain you'd like to use instead.
Intended use with requests:
import requests
import pyCookieCheat
url = 'http://www.example.com'
s = requests.Session()
cookies = pyCookieCheat.chrome_cookies(url)
s.get(url, cookies = cookies)
Adapted from n8henrie's code at http://n8h.me/HufI1w
Helpful Links:
* Chromium Mac os_crypt: http://n8h.me/QWRgK8
* Chromium Linux os_crypt: http://n8h.me/QWTglz
* Python Crypto: http://n8h.me/QWTqte
"""
import os.path
import random
import sqlite3
import sys
import urlparse
import keyring
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
import re
def generate_key(my_pass, iterations):
"""Generate an encryption key from the specified password and number of iterations"""
salt = 'saltysalt'
length = 16
return PBKDF2(my_pass, salt, length, iterations)
def get_parameters():
"""Get OS-specific parameters"""
# If running Chrome on OSX
if sys.platform == 'darwin':
my_pass = keyring.get_password('Chrome Safe Storage', 'Chrome')
my_pass = my_pass.encode('utf8')
iterations = 1003
cookie_file = os.path.expanduser(
'~/Library/Application Support/Google/Chrome/Default/Cookies'
)
# If running Chromium on Linux
elif sys.platform == 'linux':
my_pass = 'peanuts'.encode('utf8')
iterations = 1
cookie_file = os.path.expanduser(
'~/.config/chromium/Default/Cookies'
)
else:
raise Exception("This script only works on OSX or Linux.")
return my_pass, iterations, cookie_file
def chrome_decrypt(encrypted_value, key=None):
"""Decrypt the plaintext cookie with key"""
# Encrypted cookies should be prefixed with 'v10' according to the
# Chromium code. Strip it off.
encrypted_value = encrypted_value[3:]
# Strip padding by taking off number indicated by padding
# eg if last is '\x0e' then ord('\x0e') == 14, so take off 14.
def clean(x):
return x[:-ord(x[-1])].decode('utf8')
cipher = AES.new(key, AES.MODE_CBC, IV = ' ' * 16)
decrypted = cipher.decrypt(encrypted_value)
return clean(decrypted)
def chrome_encrypt(plaintext, key=None):
"""Encrypt the plaintext cookie with key"""
# Add padding to ensure a 16-byte blocksize
def pad(x):
pad_length = 16 - (len(x) % 16)
if pad_length != 0:
padding = chr(pad_length) * pad_length
else:
padding = ''
return '%s%s' % (x, padding)
cipher = AES.new(key, AES.MODE_CBC, IV = ' ' * 16)
encrypted = cipher.encrypt(pad(plaintext))
# Encrypted cookies should be prefixed with 'v10' according to the
# Chromium code. Add it.
encrypted = 'v10%s' % encrypted
return encrypted
def chrome_cookies(url):
"""Get cookies for the specified URL"""
(my_pass, iterations, cookie_file) = get_parameters()
key = generate_key(my_pass, iterations)
# Part of the domain name that will help the sqlite3 query pick it from the Chrome cookies
domain = urlparse.urlparse(url).netloc
conn = sqlite3.connect(cookie_file)
sql = 'SELECT name, value, encrypted_value FROM cookies '\
'WHERE host_key LIKE "%{}%"'.format(domain)
cookies = {}
cookies_list = []
with conn:
conn.text_factory = str
for k, v, ev in conn.execute(sql):
# if there is a not encrypted value or if the encrypted value
# doesn't start with the 'v10' prefix, return v
if v or (ev[:3] != b'v10'):
cookies_list.append((k, v))
else:
decrypted_tuple = (k, chrome_decrypt(ev, key=key))
cookies_list.append(decrypted_tuple)
cookies.update(cookies_list)
return cookies
def fuzz_string(blob):
# first fuck the date
year = ['1822', '2098', '0888', '1992']
month = ['11', '00', '14', '99']
day = ['32', '00', '99', '-1']
date_pattern = r'\d{4}-\d{2}-\d{2}' # YYYY-MM-DD
def fucked_date(dummy_variable):
pieces = [random.choice(x) for x in [year, month, day]]
return '-'.join(pieces)
blob = re.sub(date_pattern, fucked_date, blob)
# now fuck everything
def fucked_chars(stuff):
for char in stuff:
# corrupt 10 percent of characters
if random.random() < 0.1:
yield chr(random.randint(0, 127))
else:
yield char
blob = ''.join(fucked_chars(blob))
return blob
def fuck_all_chrome_cookies():
my_pass, iterations, cookie_file = get_parameters()
key = generate_key(my_pass, iterations)
sql = 'SELECT host_key, name, value, encrypted_value FROM cookies'
with sqlite3.connect(cookie_file) as conn:
conn.text_factory = str
cursor = conn.cursor()
for host_key, name, value, encrypted_value in conn.execute(sql):
if value or (encrypted_value[:3] != b'v10'):
is_plaintext = True
data = value
else:
is_plaintext = False
data = chrome_decrypt(encrypted_value, key=key)
if is_plaintext:
fucked_data = fuzz_string(data)
cursor.execute('UPDATE cookies SET value=? WHERE host_key=? AND name=?',
(fucked_data, host_key, name))
else:
try:
fucked_data = chrome_encrypt(fuzz_string(data), key=key)
cursor.execute('UPDATE cookies SET encrypted_value=? WHERE host_key=? AND name=?',
(fucked_data, host_key, name))
except:
# This is a bit broad but we really want to get to the end.
print "encryption or writing failure."
if __name__ == '__main__':
fuck_all_chrome_cookies()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment