Chrome 浏览器 Cookies 提取和解密

互联网开发
回复
头像
paktc
出类拔萃
出类拔萃
帖子: 65
注册时间: 2016年07月21日 20:34
联系:

Chrome 浏览器 Cookies 提取和解密

帖子 paktc »

StackOverflow - Chrome 80 how to decode cookies

以下内容翻译自 Topaco 的答案,

从 Local State 文件获取钥匙并解密钥匙,得到decrypted_key。

代码: 全选

import os
import json
import base64 
import win32crypt
from Crypto.Cipher import AES

path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
    encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = base64.b64decode(encrypted_key)                                       # Base64 decoding
encrypted_key = encrypted_key[5:]                                                     # Remove DPAPI
decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]  # Decrypt key
加密过的 cookie 值通常以 "v10" 开头(字面值为\x76\x31\x30),剩下部分是二进制密文。

代码: 全选

data = bytes.fromhex('763130...') # the encrypted cookie
nonce = data[3:3+12]
ciphertext = data[3+12:-16]
tag = data[-16:]
使用 AES-256 GCM 模式加解密

代码: 全选

cipher = AES.new(decrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag) # the decrypted cookie
相关工具:
Cookies查看工具(转明文)NirSoft - ChromeCookiesView
DB Browser for SQLite
头像
paktc
出类拔萃
出类拔萃
帖子: 65
注册时间: 2016年07月21日 20:34
联系:

完整代码 Re: Chrome 浏览器 Cookies 提取和解密

帖子 paktc »

上面只对提取的加密 cookie 值做解密,结合另一个旧的文章获取谷歌浏览器cookie的两种方法,从cookies文件中提取加密的value,拼出完整代码

代码: 全选

import os
import json
import base64
import sqlite3
import win32crypt
from Crypto.Cipher import AES

def get_decrypt_key():
    path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
    path = os.path.expandvars(path)
    with open(path, 'r') as file:
        encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
    encrypted_key = base64.b64decode(encrypted_key)                                       # Base64 decoding
    encrypted_key = encrypted_key[5:]                                                     # Remove DPAPI
    decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]  # Decrypt key
    return(decrypted_key)

# 读取数据库相应键值
username = os.environ.get('USERNAME')
cookie_file = 'C:/Users/{UserName}/AppData/Local/Google/Chrome/User Data/Default/Cookies'.format(UserName=username)
con = sqlite3.connect(cookie_file)
cursor = con.cursor()
sql = 'SELECT host_key, name, value, encrypted_value FROM cookies WHERE name = "channel" and host_key=".baike.baidu.com";'

try:
    if cursor.execute(sql):
        for en_value in cursor:
            data = en_value[3]
            if data:
                nonce = data[3:3+12]
                ciphertext = data[3+12:-16]
                tag = data[-16:]
                
                # 解密
                cipher = AES.new(get_decrypt_key(), AES.MODE_GCM, nonce=nonce)
                plaintext = cipher.decrypt_and_verify(ciphertext, tag) # the decrypted cookie
                print(plaintext)
except Exception as e:
    print(e)

显示结果

代码: 全选

b'baidusearch'
头像
paktc
出类拔萃
出类拔萃
帖子: 65
注册时间: 2016年07月21日 20:34
联系:

Perl 版本 Re: Chrome 浏览器 Cookies 提取和解密

帖子 paktc »

代码: 全选

use utf8;
use Encode;
use Modern::Perl;
use File::Slurp;
use Mojo::UserAgent;
use MIME::Base64;

# metacpan 搜索 GCM 找到该模块
use Crypt::AuthEnc::GCM qw(gcm_encrypt_authenticate gcm_decrypt_verify);

use Win32::API;
use File::Copy;
use DBI;
use JSON qw/from_json to_json/;
STDOUT->autoflush(1);

my $f1 = "C:\\Users\\". $ENV{"USERNAME"} ."\\AppData\\Local\\Google\\Chrome\\User Data\\Local State";
my $data = from_json( scalar(read_file($f1)) );
# encrypt_key 前5位是 "DPAPI"
my $enc_key = decode_base64( $data->{'os_crypt'}{'encrypted_key'} );
$enc_key = substr($enc_key, 5);
my $dec_key = decryptData( $enc_key );
print_hex($dec_key);

unless ( -e "Cookies" ) {
    my $chrome_cookie_file = 'C:/Users/'.$ENV{"USERNAME"}.'/AppData/Local/Google/Chrome/User Data/Default/Cookies';
    copy($chrome_cookie_file, 'Cookies') || die "Failed to move files: $!";;
}

my $dbc = DBI->connect("dbi:SQLite:dbname=Cookies", '', '', { RaiseError => 1, AutoCommit => 0});

my @rows = @{$dbc->selectall_arrayref("SELECT host_key, name, value, encrypted_value FROM cookies")};
for my $row (@rows)
{
    my ($host_key, $name, $value, $encrypted_value) = @{$row};

    next unless ( $host_key eq ".baidu.com" );

    printf "%s\n",   $name;
    # 加密数据以 v10 的 ASCII 编码(即 0x763130)开始,然后是 12 字节的随机数、实际密文,最后是 16 字节的认证标签。 可以按如下方式分离各个组件:
    my $nonce = substr($encrypted_value, 3, 12);
    my $ciphertext = substr($encrypted_value, 3+12, -16);
    my $tag = substr($encrypted_value, -16);

    # print_hex($nonce);
    # print_hex($ciphertext);
    # print_hex($tag);

    # decrypt and verify
    my $plaintext = gcm_decrypt_verify('AES', $dec_key, $nonce, undef, $ciphertext, $tag);
    printf "%s\n", $plaintext;
}

$dbc->commit(); #SQLite is slow at excuting one row at a time. SEE: http://stackoverflow.com/a/8882184
$dbc->disconnect();

sub decryptData
{
    #Cleaned up version of http://www.perlmonks.org/?node_id=776481
    my $encryptedData = shift;
    if($encryptedData eq ''){ return undef; } #avoid errors...
    my $pDataIn = pack('LL', length($encryptedData)+1, unpack('L!', pack('P', $encryptedData)));

    my $DataOut;
    my $pDataOut = pack('LL', 0, 0);

    my $CryptUnprotectData = Win32::API->new('Crypt32', 'CryptUnprotectData', ['P', 'P', 'P', 'P', 'P', 'N', 'P'], 'N');
    if($CryptUnprotectData->Call($pDataIn, pack('L', 0), 0, pack('L', 0), pack('L4', 16, 0, 0, unpack('L!', pack('P', 0))), 0, $pDataOut)){
        my($len, $ptr) = unpack('LL', $pDataOut);
        $DataOut = unpack('P'.$len, pack('L!', $ptr));
        return $DataOut;
    }else{
        return undef;
    }
}

sub print_hex
{
    my $s = shift;
    $s=~s/(.)/sprintf "%02X ", ord($1)/ge;
    printf "%s\n", $s;
}

sub gbk { encode('gbk', $_[0]) }
sub utf8 { encode('utf8', $_[0]) }
sub u2gbk { encode('gbk', decode('utf8', $_[0])) }
sub uni { decode('utf8', $_[0]) }



回复

在线用户

正浏览此版面之用户: 没有注册用户 和 0 访客