Instantly share code, notes, and snippets.
Forked from cyrozap/pyCookieCheat.py
Last active
August 29, 2015 14:08
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save mehitabel/cec86856d3d9a35a3dbe to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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