File Descriptor Hijacking - 文章分享
最近又讀了一篇 Phrack 的文章,這次是在說 File Descriptor 的部分,實作部分有碰到一些 Linux kernel module ,感覺蠻有趣的,接下來會找時間好好學這一部份。
簡介
/dev/kmem 這個檔案是 Linux kernel 虛擬記憶體的內容,直接修改他,就等於修改 kernel memory。那這篇文章就是利用這個檔案去交換兩個 Process 的 file descriptor table ,達到 Hijacking 其他使用者的程式輸出或 telnet 。原文章連結
環境
- Ubuntu 16.04 amd64
簡報
整理成一個簡報,是在 UCCU 內部讀書會用的,可以搭配著看。
How the kernel keeps track of open file descriptors
在 Unix-like 的系統裡, Process 存取資源的時候會使用叫做 file descriptors 的東西,可以用一些 system call 拿到這個值,像是 open(), socket(), pipe()。不過有些是預設的,像是 0 代表 stdin ; 1 代表 stdout ; 2 代表 stderr 。若有新的 fd 產生就會依順序累加。
可以用 python 做個小測試
開啟檔案後按下 Ctrl-Z 然後使用 jobs -l
查 pid
接下來利用 /proc/$pid/fd 查看該程序開啟的 fd 有哪些
可以看到 /etc/issue 的 fd 為 3 ,0~2 開啟的檔案是我目前 ssh 拿到的 pts(pseudoterminal slave) ,詳細解說可以看 man pts
。
那麼在 kernel 來看,每個 process 都有一個 file descriptor table ,裡面存著指向 fd 結構的指標。這個結構會存著很多資訊,型態拉、 fd 的資料拉等等。
以 linux 系統來說每個 process 會用一個 task_struct 來儲存,這個結構內又有一個 files_struct 結構,裡面還有一個 fdtable 結構,這個結構裡面有一個 fd array ( 如下圖 ) 。
kernel 版本不同會有些差異,我目前 kernel 版本是 4.4.0-116-generic ,可以用 uname -r
看自己的 kernel 版本,然後可以到這個看 Linux kernel source 的網站了解一下 task_struct 這個結構。
File descriptor hijacking
接下來的範例只會使用把兩個 process 的 fd 交換,不會進行複製 fd 或只拿走一個 process 的 fd ,要注意的是使用的人要有存取 /dev/kmem 的權限(其實就是 root ),不過在 kernel 2.6.26 以後的 /dev/kmem 是預設關閉的,如果要啟用需要重新編譯 kernel ,我有試著編譯過,但還是不能用 Orz ,幸好在 github 上找到了一個類似的 code ,他寫了一個 Linux kernel module 去控制 kernel memory ,於是就自己修了一下,讓他符合這篇文章需要的功能。
編譯 chfd
- fdhijack
- chfd 的主程式,會編譯好 chfd 和 fdhj.ko 。
- peeping_tom
- 我隨手寫的玩具,利用 chfd 去偷窺別人的 process 。
用法
其實跟原文章相反就是了 ╮(╯_╰)╭
懶人版:
裝好之後要先確認 chfd, fdhj.ko, fdhj_load, echo_fd 在同個目錄下。確認好就開始做範例吧!
─=≡Σ((( つ•̀ω•́)つ
First
首先要載入 kernel module
lsmod
可以看目前載入的 kernel module ,確認 fdhj 有出現在裡面就可以開始範例了 ~
Example 1
環境
- 受害者開啟一個程序不斷的 echo 遞增的數字 ( pid = 207 )
- 你開啟一個 terminal 輸入指令 “cat > somefile” ( pid = 1746 )
執行
- ./chfd 207 1 1746 1
結果
- 交換了兩隻程式的 stdout
- 某人的 echo 將會停止
- 對 cat 那隻程式按下 ^C 後檢查 somefile 會出現剛剛消失的數字
Example 2
環境
- 受害者正在使用 bash ( pid = 4022 )
- 你開啟一個 bash ( pid = 4121 )
執行
- 在 bash 上執行 sleep 10000
- 上面那個 bash 睡死了所以開啟另一個 bash 執行:
- ./chfd 4022 0 4121 0
- ./chfd 4022 1 4121 1
- ./chfd 4022 2 4121 2
結果
- 受害者按下任意按鍵後睡死的 bash 就可以控制受害者的 bash
Example 3
環境
- 受害者正在使用 telnet ( pid = 6309 )
- 你也開啟一個 telnet ( pid = 7081 )
- 查看 /proc/6309/fd 可以看到 fd 3 是 telnet 連線用的
執行
- ./chfd 6309 3 7081 3 0 0
結果
- 受害者看到視窗上顯示連線已關閉
- 你成功幹走受害者的 telnet
Example 4
環境
- 受害者正在使用 rlogin ( pid = 4547, 4548 )
- 你也開啟一個 rlogin ( pid = 4852, 4855 )
- 查看 /proc/$pid/fd 可以看到 fd 3 是 rlogin 連線用的
執行
- ./chfd 4547 3 4852 3
- ./chfd 4548 3 4855 3
Example 5
環境
- 受害者正在使用 bash ( pid = 1234 )
- 你使用 echo_fd 程式監控受害者的 bash
執行
- ./echo_fd 1234
結果
- 監控受害者的 bash 可以看到他打的指令和輸出結果
詳細操作可以看 peeping_tom 的 README
結論
這篇打得很像翻譯文(雖然也沒有全部都翻到),還是建議到原文章讀,要實作時再回來。
順便幫我按顆星星我會很感謝你 ♥(´∀` )人
總之,感謝您的閱讀~