當涉及到威脅檢測,有多少次你聽到有人說: 「答案就在我的頭腦中,如果你有任何問題,只問我就夠了! 」 或者「只有 TA 或者他們知道怎麼做! 」 ,像這樣的情況有很多次,不是嗎?沒有對如何分析數據以檢測網絡中潛在的入侵的過程作記錄、標準化或與人分享的問題要比你想像的更常見,特別是從技術和專業知識的角度來看當團隊變得非常多樣化的時候。它不僅會影響你的檢測策略,還會影響你的團隊的動態。
現在,有多少次你想過用一種更有效、更直觀或更有創造性的方法來分析你的組織收集的安全事件,但是你會因為只能使用一個語言相關的搜索欄而感到有局限性?
這篇文章是本系列文章的一部分,這個系列文章將介紹如何利用 Jupyter Notebook 以一種更加動態、靈活和不涉及語言的方式來分析安全事件,同時幫助你的團隊記錄、標準化和分享用於檢測威脅的Jupyter Notebook 文件。你可以將其與 ThreatHunter-Playbook 之類的項目集成在一起,然後免費進行部署,並且可以不限時間的使用 HELK 之類的開源項目。
在本系列文章的第一篇博文中,我將介紹 Jupyter Notebook 的基本工作原理,如何創建你的第一個notebook ,以及如何在 Python 中運行一些初始的基本命令。
其餘四部分可在以下連結找到:
· 用Jupyter Notebook 進行威脅狩獵——第二部分: Pandas 數據分析基礎
· 用Jupyter Notebook 進行威脅狩獵——第三部分: 利用 Apache Spark 查詢 Elasticsearch
· 用Jupyter Notebook 進行威脅狩獵——第四部分: 通過 Apache SparkSQL 實現 SQL JOIN
· 用Jupyter Notebook 進行威脅狩獵——第五部分: 記錄、分享和運行威脅狩獵
什麼是 Notebook?
你可以把 notebook 想像成一個文檔,你可以通過 Web 界面訪問這個文檔,這個 Web 界面允許你保存交互式會話的輸入(即實時代碼)和輸出(即代碼執行結果 / 評估代碼輸出) ,以及解釋執行特定任務(即數據分析)的方法和步驟所需的重要說明。
什麼是 Jupyter Notebook?
Jupyter Notebook 是一個開源的 Web 應用程式,允許你創建和分享包含實時代碼、方程式、可視化和敘述文本的文檔。用途包括: 數據清理和轉換,數值模擬,統計建模,數據可視化,機器學習,等等。
Jupyter Notebook 項目是 IPython Notebook 庫的演變,開發這個庫的主要目的是為了通過可共享的 Web 文檔實現科學操作和高級數據分析功能,從而增強默認的 python 交互控制臺。
如今,Jupyter Notebook 項目不僅支持 Python,還支持40多種程式語言,如 R、 Julia、 Scala 和 PySpark。事實上,它的名字最初來源於三種程式語言: Julia、 Python 和 R,這使它成為第一個與語言無關的 notebook 應用程式,現在被認為是社區中數據科學家和工程師探索和分析數據最喜歡的環境之一。
「Jupyter Notebook」是如何工作的?
Jupyter Notebook 使用基於內核-客戶端基礎結構的所謂雙進程模型。這個模型將一個類似的概念應用於 Read-Evaluate-Print Loop (REPL) 編程環境,該環境接受單個用戶的輸入,然後計算輸入,並將結果返回給用戶。
基於雙進程模式的概念,我們可以從以下方面解釋 Jupyter 的主要組成部分:
Jupyter 客戶端
· 它允許用戶將代碼以Qt 控制臺 或者通過瀏覽器的 notebook文件的形式將代碼發送到內核。
· 從 REPL 的角度來看,客戶端執行read 和 print 操作。
· 由一個 Jupyter Web 伺服器託管,該伺服器使用Tornado 處理 HTTP 請求。
Jupyter 內核
· 內核接收客戶端發送的代碼並執行代碼以及將結果返回給客戶端顯示。 一個內核進程可以有多個客戶端與其通信,這就是為什麼該模型也被稱為解耦的雙進程模型。
· 從 REPL 的角度來看,內核執行evaluate 操作。
· 內核和客戶端通過基於 ZeroMQ (底層傳輸層)和 WebSocket(基於 TCP)的異步消息處理庫的交互式計算協議進行通信。
Jupyter Notebook 文件
· Notebook 可以自動保存和存儲在磁碟上,採用開放源碼的 JavaScript Object Notation文件(JSON)格式保存,文件的後綴名稱是 .ipynb。
Jupyter Lab
· 這是下一代基於 Web 用戶界面的 Jupyter 項目。
· JupyterLab 最終將取代經典的 Jupyter Notebook。
· 我們將在整個系列文章中使用 Jupyter Lab 擴展。
安裝 Jupyter
我敢肯定此刻你一定想急於安裝 Jupyter 並開始探索它的功能,但首先你必須決定你是想直接在你的系統上安裝 Jupyter Notebook 伺服器,還是在虛擬機或 docker 容器上託管它。
我相信給你這些選項是很重要的,這樣你就可以隨心所欲地運行這個工具。如果你希望直接在系統上進行經典式的安裝,請參閱官方的 Jupyter 安裝文檔。
通過 Docker 運行 Jupyter
對於本系列文章,我們將使用 HELK 項目。我更喜歡通過 docker 鏡像共享一個標準化的工作環境,以便更多地關注應用程式的功能,而不是花時間對伺服器安裝進行故障排除。
安裝要求
· HELK 項目
初始化步驟
· 克隆最新版本的 HELK 代碼倉庫,將你的工作目錄改為 HELK/docker 然後運行通過sudo 執行 helk_install.sh 腳本
git clone https://github.com/Cyb3rWard0g/HELK.git
cd HELK/docker
sudo ./helk_install.sh
· 對於本系列文章,我們將使用帶有基礎許可證的選項3 進行安裝。
· 一旦腳本運行完成(大約5-10分鐘) ,你將看到類似的輸出:
· 打開上面的 HELK JUPYTER SERVER URL
· 你可能會得到一個Privacy Error 頁面。忽略掉它,點擊 Advanced 然後點擊 Proceed。
· 複製顯示在你的控制臺中的JUPYTER CURRENT TOKEN 的值然後將這個 token 粘貼到頁面的密碼框中然後點擊Log in。
· 你可以進入 Jupyter Lab 的主菜單。
· 正如你可以在上面的圖片中看到的,有一個名為datasets的目錄。裡面默認包含了一個Mordor 數據集 ,這個數據集我們將會在下一篇文章中用到。我們將在下一篇文章中使用的數據集。此外,還有一些 notebook 可供你使用。我製作所有這些 notebook 的目的是為了讓你們熟悉我將要分享的概念。
探索 Jupyter 的主界面
文件瀏覽器部分
· 這一部分顯示的是可用的對象,例如可供你使用的文件夾或文件。你可以通過右鍵單擊對象 重命名 , 移動 , 下載, 或刪除 任何文件夾或文件。
· 你還可以上傳本地系統中存在的文件,方法是單擊Upload 圖標,如下圖所示。
· 此外,還可以創建新對象,如Notebooks,文本文件,甚至運行 bash 終端。
· 你也可以從啟動器部分(Launcher)完成,如下圖所示:
· 如上圖所示,我們的Jupyter 伺服器有四個內核可用: Python 3, PySpark, R, and Syplon。
· 默認情況下,Jupyter 使用的是Python 3 (IPython) 內核。Jupyter 團隊維護了IPython 內核 ,因為 Jupyter notebook 伺服器依賴於 IPython 內核功能。除了 Python 之外,notebook 中還可以使用許多其他語言。這就是我所說的與語言無關的方法。如果你想了解更多關於其他內核的信息,你可以點擊這裡閱讀。
運行終端和內核部分
· 這一部分提供有關當前運行的 Jupyter 進程的信息。當你創建一個notebook 或啟動一個終端會話時,你將能夠在這裡跟蹤這些進程。
命令部分
· 這一部分提供有關可用於與文件、新控制臺交互的幾個命令的信息。如:內核等。
你的第一個 Notebook
現在,讓我們創建我們的第一個notebook ,並熟悉其他選項。
· 返回到 啟動器(Launcher) 部分,單擊要用來初始化新notebook 的特定內核。這裡我們選擇 Python 3。
· 你會看到一個基本的 notebook Web 界面和命名為Untitled 的最初的 notebook以及 一個input(In) 單元格,你可以添加代碼到 Python 3 內核中,然後執行代碼。
· 你還將看到一個後綴為ipynb名稱為untitled 的文件。notebook 會自動進行保存。
· 你可以通過點擊文件瀏覽器的圖標來最小化文件瀏覽器部分。
· 你可以通過右鍵點擊 notebook 的標題然後點擊 Rename Notebook重命名你的notebook。
· 如果你檢查 Jupyter 內核會話,你將看到你的 notebook 正在運行,並帶有關閉內核的選項。
探索 Notebook 界面
在notebook 界面中有幾個可用的選項,其中大多數選項的含義都非常簡單明了,工作方式類似於你在常規文檔工具欄中獲得的工具,你可以保存、打開或關閉文件。然而,有一些選擇和概念非常有必要重點理解:
Cell 環境
· Cell 環境的一個主要部分是input cell container ,你可以在其中輸入代碼(即 Python)或文本(即 Markdown) ,以供內核計算和執行。
· 在input cell 左邊有一個input label。這個是通過一系列數字來跟蹤代碼的執行,默認從[1]開始計數。如果還沒有運行任何程序,它將顯示空括號[ ]。如果內核正在運行代碼,這裡的空括號[]裡面會顯示一個星號*也就是[*]。
· 你可以通過頁面中的工具欄保存 notebook 的內容,添加新單元格(➕) ,剪切 / 刪除單元格(✂) ,複製單元格和粘貼單元格。
· 你可以通過選擇input cell container 然後點擊run cell button 運行代碼。你也可以選中一個單元格通過SHIFT +回車鍵運行代碼。
· 你可以通過code 下拉按鈕選擇你要是有的輸入類型。目前有三種單元格輸入類型,code 輸入類型允許用戶在內核中定義的特定程式語言中運行代碼。在這種情況下,程式語言是 Python 3。
你也可以通過 Run 選項卡訪問更多選項,如下圖所示:
內核環境
· 你可以通過Kernel 標籤訪問內核選項。
我想運行一些代碼
現在我們了解了如何與 Jupyter notebook 接口交互,接下來讓我們在input cell container 中運行一些基本的 python 代碼。
輸入一個基本的 python PRINT 語句,然後按下SHIFT + 回車鍵運行單元格代碼。
· 現在嘗試運行一個FOR 循環 ,這個循環通過RANGE生成 5 個數字的序列。
for x in range(5):
print(x)
· 將 cell type 切換為一個新的輸入類型 ——Markdown ,輸入一些 Markdown 文本。
· 複製,粘貼,並運行下面的Markdown 文本:
# Threat Detection
## Data Analysis
### Data Sources
#### Process Monitoring
PowerShell Execution
· 使用 SHIFT + UP 鍵選擇所有當前單元格然後刪除它們。
· 通過在某個單元格上創建一個變量,在從另一個單元格調用變量之前需要先運行該變量,使變量在多個輸入單元格之間可用。
dog_name = 'Pedro'
print(dog_name + " is my best friend!")
標準 python shell 中的一個有用特性是 tab 補全。
· 你可以鍵入變量的第一個字母dog_name 然後在你的鍵盤上按下tab 鍵。這將在命名空間中搜索與你輸入的字母相匹配的任何變量。
· 你還可以將對象中可用的方法或屬性進行tab補全。
· 讓我們定義一個包含關於我的狗的元素列表,並將它保存在一個變量中。
dog_list = ['pedro, 4, 2015]
· 然後你可以在輸入dog_list 後,再輸入一個句點符號然後按下 tab 鍵看看你可以使用哪些方法來處理這個列表。例如,你可以選擇 append 在列表中附加新的元素。
· 你也可以對模塊執行相同的操作。現在我們導入 random 模塊然後通過 tab 補全查看模塊內部可用的方法或函數。
· tab 補全功能也適用於補全文件路徑。我們可以在datasets文件夾中測試這個功能。
另一個很酷的特性是 Introspection,可以用於獲取關於對象的信息(例如列表、函數等)。你可以在對象之前或之後簡單地輸入一個問號(?)即可。
· 讓我們用它來處理變量 dog_list。
· 那麼函數呢? 讓我們用print 函數做個測試。輸入一個問號(?)來列印這個函數的docstring 。
這很簡單,不是嗎?如果這是你第一次使用「Jupyter notebook 」 ,我希望這能幫助你熟悉一些基本的概念,加快你的第一個「Jupyter notebook 」環境的部署!
如果你想再次獲得 Jupyter 令牌,你可以使用以下方法:
sudo docker exec -ti helk-jupyter jupyter notebook list | grep "token" | sed 's/.*token=\([^ ]*\).*/\1/'
在下一篇文章中,我們將使用 HELK jupyter 容器中的一些可用的 notebook ,通過一個名為 Pandas 的 python 庫學習更多關於安全事件日誌的數據分析。
Pandas 基礎數據分析
在上文中,我介紹了 Jupyter Notebook 的基本概念,並向你展示了如何部署一個基本的notebook環境。現在,我們準備開始運行更多的 Python 代碼,並開始向你展示如何靈活和動態地使用notebook來分析安全事件。
在下文中,我將向你展示如何在一個名為 Pandas 的 python 庫的幫助下,以 JSON 格式讀取和分析安全日誌文件。
要求
· 本文假設你已經閱讀了前一篇文章,並按照特定的指示部署了 HELK 項目。
· 基本的 Python 編程技能和對 Python Numpy 數組的基本理解。如果你是 python 數據結構、控制流、循環、函數、模塊和 NumPy 數組方面的新手,或者是你想刷新一下你對這些知識的記憶,我為你準備了兩個簡短的 notebook,作為對這些知識的介紹。打開01-intro-to-python.ipynb 和 02-intro-to-numpy-arrays.ipynb就可以開始學習了。
儘管如此,我還是想直接跳到事件日誌的分析部分,我相信理解 Pandas 背後的基本概念是很重要的。
什麼是 Pandas?
Pandas 是一個 Python 包,提供了快速、靈活和富於表達能力的數據結構,旨在使處理「關係型」或「標記型」數據變得既簡單又直觀。它旨在成為用 Python 進行實際的、現實世界的數據分析的基本高級構建塊。
Pandas 數據對象嚴重依賴高性能 NumPy 數組,並提供典型的電子表格和關係型資料庫(如 SQL)的靈活的數據操作能力。
什麼是 Numpy?
· Numpy 是「Numerical Python」的縮寫,它是用於科學計算的基本 Python 包
· 它使用一種高性能的數據結構,稱為 n維數組或 ndarray,這是一種多維數組對象,用於高效地計算數組和矩陣。
什麼是數組?
· Python 數組是類似於列表存儲數據的數據結構,只是其中存儲的對象類型受到了限制。數組的元素都具有相同的類型,並由一組正整數進行索引。
· Python 的 array 模塊 允許你在創建對象時通過使用類型代碼(單個字符)指定數組的類型。
NumPy N維數組(ndarray)
· Numpy 數組是一個高效的多維數組,提供快速的面向數組的算術運算。
· 與任何其他 Python 數組一樣,它是相同類型元素的容器。
· 與 Python 中的其他容器對象一樣,你可以通過索引或切片操作訪問和修改 ndarray 的內容。
· Numpy 數組處理向量化操作,存儲效率比其他 Python 內置的數據結構更高。
· 如果我們嘗試向列表中的每個元素添加一個數字,你必須執行一個循環,以便對每個元素應用基本的加法。
· 如果對 NumPy 數組執行相同的操作,則只需要向數組對象添加一個數字,並將其應用於數組的每個元素。
Pandas 和 NumPy 數組
Pandas 利用並擴展了 NumPy 中的幾個基於數組的功能,並提供了一種更具表現力的表示數據和操作數據的方法。Pandas 中的兩個主要數據結構是:
· Series(序列)
· DataFrames
Pandas 的 Series
· Pandas 的 Series 是一個一維的帶標籤的索引數組,可以存儲任何數據類型,如整數、浮點數和字符串。
· 可以通過傳遞 NumPy 的 ndarray 來創建和初始化 Series。
· 正如你在上面看到的,索引在左邊,值在右邊。我們沒有為數據指定索引; 因此, Pandas默認從0開始創建索引。
Pandas 的 DataFrames
· Datatrame 是一個二維表,用於以表格格式表示數據。
· 可以將 DataFrame 看作是一個包含列標題和行的表格。
· Dataframe 同時具有行索引和列索引。
· Pandas 依賴 NumPy 數據類型來輸入 DataFrames 中的數值。例如,我們可以使用以下命令列印單個條目的數據類型,例如,我們可以使用 iloc 查看 age 列上的第一個值的數據類型,我們可以看到它是 NumPy 類型。
現在我們已經了解了 Pandas 的基礎知識及其數據結構,我們可以開始使用 DataFrames 以表格格式處理安全事件日誌。
基本的事件日誌分析
讓我們創建一個新的notebook,探索魔多數據集,不斷豐富、可視化這個數據集並篩選出有趣的事件。這個notebook的解決方案被命名為basic_event_log_analysis_pandas ,對你是可用的。我建議你重新創建它,並按照下面的步驟進行操作,這樣你就可以得到一些親自的實踐體驗。
創建一個新的notebook
導入庫
import pandas as pd
from pandas.io.json import json_normalize
import json
import matplotlib.pyplot as plt
讀取魔多數據集
· 我們接下來要讀取的是魔多的小數據集——empire_invoke_wmi
· 我們可以用 read_json 這個方法read_json 將 Mordor JSON 文件轉換為 DataFrame。lines 參數設置為了 True ,目的是將文件作為 json 對象進行每行讀取。
invoke_wmi_df = pd.read_json('datasets/empire_invoke_wmi_2019-05-18214442.json', lines=True)
探索數據
· 接下來,我們可以使用shape 以返回表示 DataFrame 維度的元組。數據包含 5271 行和23 列。
· 此外,我們可以使用iloc 選擇 DataFrame 中的第一條記錄。在這一步中,我們了解了 DataFrame 中的模式。請記住,我們的數據集包含不同的數據源。因此,我希望模式對每個記錄或審計類別進行大量更改。
嵌套列處理
· 在前面的圖片中,我們可以看到數據集中的一些嵌套欄位。因此,我們可以使用json_normalize 幫我們壓平那些列。
· 首先,我使用to_json方法將DataFrame轉換為 JSON。
· 接下來,將結果作為 json 結構加載,然後通過json_normalize 函數獲得一個 DataFrame 。
json_struct = json.loads(invoke_wmi_df.to_json(orient="records"))
invoke_wmi_flat = json_normalize(json_struct)
識別可用的數據源
· 你可以用pandas的groupby 方法使用source_name 欄位對 DataFrame 進行分組。我這樣做是為了了解更多關於可用數據源的信息。
invoke_wmi_flat.groupby(['source_name']).size()
篩選 Sysmon 事件
· 現在,我們可以開始通過特定的數據源篩選我們的 DataFrame。
· 我決定只篩選 Microsoft-Windows-Sysmon 事件。
· 正如你在下面看到的,還有一些欄位的值是NaN 。這是因為 Sysmon 的每個事件的數據模式並不是相同的。
sysmon_filter = invoke_wmi_flat['source_name'] == "Microsoft-Windows-Sysmon"
sysmon_df = invoke_wmi_flat[sysmon_filter]
篩選 Sysmon 進程創建事件(EID 1)
· 現在我們有了一個 Sysmon DataFrame,我們可以根據特定的事件 id 篩選這些事件。讓我們通過傳遞event_id == 1 篩選一下。
sysmon_filter2 = sysmon_df['event_id'] == 1
sysmon_proc_create = sysmon_df[sysmon_filter2]
在 ProcessCreate Dataframe 上刪除空欄位
· 在對一個特定事件篩選 Sysmon DataFrame 之後,我們需要刪除值為 NaN 的空欄位。屬於相同事件類型(事件 id)的所有記錄都應該具有相同的模式,這樣就可以很容易地篩選出不屬於ProcessCreate 模式的數據。
· 你可以通過以下方法了解關於模式的更多信息OSSEM Sysmon Event Id 1
sysmon_proc_create = sysmon_proc_create.dropna(axis = 1, how = 'all')
按特定欄位分組事件
· 讓我們一起探索我們的ProcessCreate 事件,並將這個事件的數據按照ParentImage分組。
· 根據數據集的含義,該文件包含的是攻擊者利用 WMI 進行橫向移動,以便在目標機器上產生一個新代理的行為數據。因此,我決定分析ParentImage 列的數據值,目的是為了了解在端點上執行的父進程的更多信息。
sysmon_proc_create.groupby(['event_data.ParentImage']).size()
豐富數據
· 我們可以採取的一個基本步驟是豐富當前的事件
· 我們可以向我們的 DataFrame 添加一個新欄位,並將該欄位的值設置為每條記錄的字符總數的結果,然後我們可以使用這個新欄位來尋找潛在的異常值
sysmon_proc_create['command_count'] = sysmon_proc_create['event_data.CommandLine'].str.len()
可視化數據
· 我們可以從每條記錄中提取新欄位的值,並用一個基本的柱狀圖將數據可視化。
· 我們可以看到與網絡流量中的其他進程相比 C:\Windows\System32\Wbem\WmiPrvSE.exe 的CommandLine 參數執行了大量字符的操作。
sysmon_proc_create.plot(kind='bar',x='event_data.ParentImage',y='command_count')
篩選有趣的事件
· 我們可以更深入地了解在 CommandLine 參數中執行的子進程的信息。
· 接下來,我們可以選取子進程的 ProcessGuid 進行分析。
sysmon_filter3 = sysmon_proc_create['event_data.ParentImage'] == "C:\Windows\System32\wbem\WmiPrvSE.exe"
sysmon_proc_create[sysmon_filter3]['event_data.ProcessGuid']
顯示結果
· 我們可以用 Pandas 的 option_context 管理器來增加我們的結果列的寬度,以便看到較長的CommandLine 參數。
· 通過分析,我們可能已經找到了我們的對手。
with pd.option_context('display.max_colwidth', 2000):
print(sysmon_proc_create[sysmon_filter4]['event_data.CommandLine'])
我希望這篇文章對那些剛剛開始使用 Jupyter notebook的人有所幫助。另外,我希望這能激發你使用 DataFrames 來表示和分析安全事件日誌的興趣。
如果你想深入研究 Pandas 提供的一些附加功能,可以運行可用的03-intro-to-Pandas notebook。如果你想運行在這篇文章中提出的每一個步驟,並比較你的結果,你也可以運行basic_event_log_analysis_pandas notebook。
在下一篇文章中,我們將繼續以表格格式分析安全事件日誌,但是我們會直接從資料庫中讀取,而不是從離線的 JSON 文件中讀取。我們仍然會使用相同的魔多數據集,但我會對數據進行實時分析,然後進行規範化處理並存儲在一個 Elasticsearch 資料庫。然後,我將向你展示如何通過 Apache Spark 連接到 Elasticsearch 資料庫,進行可擴展的並行數據處理。
參考資料
https://jupyter.org/
https://jupyter4edu.github.io/jupyter-edu-book/
https://jupyter.readthedocs.io/en/latest/architecture/how_jupyter_ipython_work.html
https://ipython-books.github.io/chapter-3-mastering-the-jupyter-notebook/
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop
https://en.wikipedia.org/wiki/read%e2%80%93eval%e2
https://jupyterlab.readthedocs.io/en/stable/getting_started/overview.html#overview
https://github.com/pandas-dev/pandas
https://medium.com/@ericvanrees/pandas-series-objects-and-numpy-arrays-15dfe05919d7
https://github.com/Cyb3rWard0g/OSSEM
https://github.com/Cyb3rWard0g/mordor
https://pandas.pydata.org/pandas-docs/stable/index.html
參考來源:https://posts.specterops.io/threat-hunting-with-jupyter-notebooks-part-1-your-first-notebook-9a99a781fde7