如何使用BPF將SSH會話轉換為結構化事件

  • 2020 年 3 月 31 日
  • 筆記

寫在前面的話

Teleport 4.2引入了一個名叫增強型會話記錄(Enhanced Session Recording)的新功能,該功能可以接收一個非結構化的SSH會話,並輸出結構化事件的數據流。這是Teleport的一次進步,因為它使用了新技術(eBPF,或現在可以簡稱為BPF)來彌補Teleport審計能力的一些不足。接下來,我們將給大家介紹這個新功能,並討論其中的一些技術細節。

背景介紹

Teleport在最早的版本中就引入了會話記錄功能,會話記錄可以捕捉用戶在終端中的列印資訊,並可在之後的安全審計過程中以影片的方式提供回放記錄。這個功能的優勢就在於,這些記錄很容易查看和理解,並且可以提供用戶在會話建立期間的相關活動以及上下文,這對於安全審計活動來說是非常有價值的。

當然,它的不足之處就在於,用戶可以通過多種方式來繞過會話記錄。

1、混淆處理-比如說下列命令:

echo Y3VybCBodHRwOi8vd3d3LmV4YW1wbGUuY29tCg== | base64 –decode | sh

當該命令解碼後即為「curl http://www.example.com」,但是SSH會話記錄中並不會包含curl命令。

2、Shell腳本-如果用戶上傳並執行了一個腳本,那麼腳本中的命令將無法被會話記錄捕捉到,而是直接將腳本文件輸出。

3、終端控制-終端支援各種控制命令,最常用的應該是sudo了,禁用終端的echo將允許我們在運行命令的同時不會被SSH會話記錄捕捉到。

技術實現

為了解決這個問題,Teleport需要一種方法來在會話持續的過程中將非結構化的SSH會話轉換為結構化的事件流。那麼這種結構化事件流中應該包含什麼呢?

我們對多種方法進行了研究,我們研究的內容從諸如regex模式匹配之類的特殊方法到更複雜的嘗試,比如自己解析原始SSH會話。我們還研究了Linux提供的各種API和系統,如Audit、fanotify和BPF。

在選擇使用哪種技術來構建時,我們有以下幾個關鍵的標準:

1、減小誤報,理想情況下為0。如果你的系統誤報率非常高,那麼你對警報的關注度可能會因此而減少,這將導致關鍵問題被忽略。 2、減少由監控所引起的任何性能影響,理想情況下為0,這也能減輕向用戶添加額外資源的負擔。

這些特定的方法都會存在誤報的問題。我們在解析和解釋組成SSH會話的位元組流時,無法在不引起錯誤警告的情況下保證數據的準確率。而且由於性能方面的原因,我們排除了Linux Audit。

BPF是什麼?

Brendan Gregg,是BPF程式的開發人員,他經常將BPF描述為一種「新型軟體」。BPF允許用戶空間程式以安全和高效的方式在內核的某些位置設置鉤子並發出事件。

安全和性能意味著什麼?在這種情況下,「安全」意味著BPF程式不能陷入無限循環中,導致系統崩潰。BPF程式不太可能像內核模組那樣使整個作業系統崩潰。BPF程式也有性能,如果不能足夠快地使用事件,則會刪除事件,而不是拖累整個系統的性能。

Teleport如何使用BPF

Teleport當前使用了三個BPF程式:execsnoop用於捕捉程式執行,opensnoop用來捕捉程式所打開的文件,tcpconnect用來捕捉程式建立的TCP鏈接。

為了更好地了解這三個BPF程式的功能,大家看看我們在運行「man ls」命令時,execsnoop捕捉到的內容:

# ./execsnoop    Tracing exec()s. Ctrl-C to end.       PID   PPID ARGS     20139  20135 mawk -W interactive -v o=1 -v opt_name=0 -v name= [...]     20140  20138 cat -v trace_pipe     20171  16743 man ls     20178  20171 preconv -e UTF-8     20181  20171 pager -s     20180  20171 nroff -mandoc -rLL=173n -rLT=173n -Tutf8     20179  20171 tbl     20184  20183 locale charmap     20185  20180 groff -mtty-char -Tutf8 -mandoc -rLL=173n -rLT=173n     20186  20185 troff -mtty-char -mandoc -rLL=173n -rLT=173n -Tutf8     20187  20185 grotty

現在你也許已經了解了BPF程式的功能了,簡單的「man」命令,原來後面有這麼多其他的程式在執行。

Teleport已將這三個程式的程式碼嵌入在了自己的庫中,當我們啟用了增強型會話記錄功能之後,它便會執行這些程式。

就其本身而言,這些程式都是用於調試和跟蹤的優秀工具,因為它們可以告訴我們整個系統在執行哪些操作。事實上,這就是我們最開始選擇這些工具的目的:我們使用它們來調試Teleport遇到的一些問題,而這些問題可能會導致它在某些場景中耗盡文件描述符。但是,我們使用Teleport的目的各有不同,我們有時需要將程式執行與SSH會話以及標識符關聯起來。

為了將程式執行與特定的SSH會話關聯起來,我們選擇使用cgroup(cgroupv2)。當Teleport啟動SSH會話時,它首先會重新啟動並將自己放置在cgroup中。這將允許程式對當前進程以及Teleport將要啟動的所有進程進行跟蹤,並分配唯一標識ID。Teleport所運行的BPF程式還可以發出執行它們的程式的cgroup ID,這允許我們將事件與特定的SSH會話和標識關聯起來。

切入主題

了解了關於BPF的相關內容之後,你也可以將增強型會話記錄功能引入你自己的程式之中,腳本程式碼已託管至GitHub:https://gist.github.com/russjones/01fe0e5f0bfbabf73f***b93f4d119ed。

首先啟動Ubuntu 19.04或RHEL/CentOS 8 VM並運行上面鏈接提供的腳本。該腳本只會安裝內核頭和bcc-tools,這些都是增強型會話記錄運行的前提條件。除此之外,它還會安裝jq,這樣更有助於可視化查看結構化事件流。

安裝命令如下:

yum install -y kernel-headers bcc-tools

apt install -y linux-headers-$(uname -r) bpfcc-tools

如需啟用Teleport中的增強型會話記錄功能,請將下列內容添加至配置文件中:

   ssh_service:           enhanced_recording:              enabled: yes

當你以本文說明的方式在終端中執行「curl http://www.gravitational.com」時,你將會看到下列輸出內容:

{      "argv": [        "http://www.gravitational.com"      ],      "cgroup_id": 4294967355,      "code": "T4000I",      "ei": 15,      "event": "session.command",      "login": "root",      "namespace": "default",      "path": "/bin/curl",      "pid": 2315,      "ppid": 2294,      "program": "curl",      "return_code": 0,      "server_id": "e56dc762-0171-4d6e-aa56-24f2ae268c7f",      "sid": "72aabcd8-38c8-11ea-af55-42010a800031",      "time": "2020-01-17T01:27:05.07Z",      "uid": "4b493296-7df2-4ec7-9282-a19c0d98e261",      "user": "test-user"    }    {      "cgroup_id": 4294967355,      "code": "T4002I",      "dst_addr": "104.24.97.116",      "dst_port": 80,      "ei": 0,      "event": "session.network",      "login": "root",      "namespace": "default",      "pid": 2315,      "program": "curl",      "server_id": "e56dc762-0171-4d6e-aa56-24f2ae268c7f",      "sid": "72aabcd8-38c8-11ea-af55-42010a800031",      "src_addr": "10.128.0.49",      "time": "2020-01-17T01:27:05.145Z",      "uid": "42831223-1da2-4b26-a783-08060fd8d7b1",      "user": "test-user",      "version": 4    }

此時,我們可以看到用戶將以兩種方式運行curl程式。第一種就是程式執行本身,第二種方法就是程式的行為,curl將會發送一個網路請求。

當然了,你也可以嘗試運行其他內容,比如說經過混淆處理的命令等等,你同樣可以在日誌中查看到執行結果。

執行演示

下面演示的是增強型會話記錄如何將一個非結構化的SSH會話轉換成了一個結構化事件流:

*參考來源:gravitational,FB小編Alpha_h4ck編譯,轉載請註明來自FreeBuf.COM