---
# System prepended metadata

title: VDSO hijacking
tags: [malware]

---

# VDSO hijacking
###### tags: `malware` 
[mitre T1055.014](https://attack.mitre.org/techniques/T1055/014/)

這是 mitre 上面提到的 linux 獨有的 process injection 方式，不過從 reference 來看好像沒有已知的攻擊是用這種方式(我覺得是太麻煩的緣故 XD)，但他的確是一個可行的攻擊技巧

[作者原文](https://web.archive.org/web/20150711051625/http://vxer.org/lib/vrn00.html#c7)

本質上是透過 `ptrace` 達到加載 shared library 和修改 GOT table 達到劫持的目的

## kernel pwn 的 vdso hijacking 

如果直接 google vdso hijacking ，可能會找到某個 kernel pwn 的題目，雖然都叫 vdso hijacking ，但兩者可以說是天差地遠，一個是在 kernel 層去修改 vdso 的執行流程，另一個則是在 user space 透過 ptrace 去攔截 syscall 並加以利用

其實對 vdso hijacking 這個技術的講解看上面的作者原文就夠了，畢竟根本沒什麼人在討論這個手法，大概也找不到其他比較有價值的文章

## 攻擊流程

這個攻擊很大部分是在繞過一個叫 GRSEC 的 kernel patch ，他的功用影響比較大的有：
* NX protection
* maps file blank
    * 不確定 blank 是 blank 哪些地址還是全部都 blank 
    * 從文中來看 process 載入地址應該是固定的，可能是 2009 年 PIE 技術還不流行

NX 是現在 linux 發行版應該都有的保護， maps file blank 就比較麻煩，不過我沒花時間去弄這個 patch ...

1. 透過讀取 `/proc/<pid>/maps` 拿到 process 地址資訊
    * 如果拿不到地址，我覺得 x86 環境下用 ptrace + egg hunter 技巧慢慢找應該還是找的到
3. 利用地址資訊和 parsing elf 的格式，找到 got 地址
4. 用 `ptrace` attach program
5. 利用 `PTRACE_SYSCALL` 在進入離開 syscall 會被暫停的功能找到位於 vdso 的 sysenter
    * x86 模式下暫停的時候 pc 暫存器位在 vdso sysenter 指令附近
    * x64 應該就直接停在 libc 的 syscall 附近
        * 因為指令不是固定的，定位起來比較麻煩，但用 ptrace 的讀取前面的記憶體加上反組譯應該還是找的到
6. 保存本來要送去 syscall 的暫存器資料
7. 將暫存器改成 open shared library 並且執行 sysenter
8. 將暫存器改成 mmap shared library 並且執行 sysenter ，執行後拿返回的 mmap 地址，這個是 shared library 地址
    * 這步驟要執行兩次，一次是 mmap text segment ，另一次是 data segment ，因為權限不同所以要分開執行
9. 回復之前保存的暫存器並執行 sysenter
10. 在 tracee process 裡面搜尋想要執行的 evil function 地址
    * 感覺可以記偏移直接拿到地址不用再爬一遍
12. 保存 tracee process 中想要攔截的 GOT 地址
14. 將 GOT 地址改成 evil function 
    * Full relro 的話會失敗，不過 process 內應該很多 function pointer 可以 hijack 
16. 將 evil function 結尾修改成步驟 10 保存的 GOT 地址
17. 結束

## 對 code 的修正

作者給的 code 不知道是在哪個環境下實驗的，我用 ubuntu 20.04 或是 9.04 都執行失敗，推測應該是編譯器編譯出來的 machine code 長的不一樣導致，建議自己根據自己的環境編譯出來的 code 做修改，以下提到幾個要改的部分：

* tracee text segment 在 ubuntu 20.04 下 offset 不再是 0x0
    * 我直接修改成 0x1000 
* mmap 第一個地址盡量自己指定
    * 我遇到不指定地址，結果第一個 text segment 被 map 到 libc 和 ld 中間，導致後續 data segment 和 text segment 不連續，這樣會在之後定位 evil function 的步驟出了點問題(不過看起來可以來硬的寫死在裡面)
* evilsig
    * 其實就是 evil function 前幾個 bytes ，因為編譯器關係長的會跟文中的 code 不一樣
* tc
    * 這個 array 是放 evil function 要跳轉回正常 function 的 machine code ，同樣會因為編譯器關係導致偏移不一樣

## 