quiz11 Q2

contributed by <nashi556, ga6394870>

測驗 2

考慮以下程式碼:

#include <inttypes.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { char *p, *q; uintptr_t pv, qv; { char a = 3; p = &a; pv = (uintptr_t) p; } { char b = 4; q = &b; qv = (uintptr_t) q; } if (p != q) { printf("%p is different from %p\n", (void *) p, (void *) q); printf("%" PRIxPTR " is not the same as %" PRIxPTR "\n", pv, qv); } else { printf("Surprise!\n"); } return 0; }

這段程式碼在 macOS 和 GNU/Linux 有著不同的執行輸出:

  • macOS 17.5.0 / x86_64 平台上用 clang-902.0.39.1 編譯,得到以下執行輸出
    ​​​​0x7ffee37fbabf is different from 0x7ffee37fbabe
    ​​​​7ffee37fbabf is not the same as 7ffee37fbabe
    
  • Ubuntu Linux 17.10 / x86-64 平台用 gcc-7.2.0 編譯得到以下執行輸出
    ​​​​Surprise!
    

從以下選項中挑出最接近的描述

作答區

B = ?

  • (a) 純粹只是 C 編譯器行為的落差,實務上不需特別留意;
  • (b) char achar b 這兩個物件的生命週期僅分別在第 11 行和第 16 行有效,一旦超出 scope (作用範圍),C 語言編譯器就會主動釋放物件,而透過 & (value-of) 運算子得到的地址自然就不再有效;
  • (c) char achar b 這兩個物件的生命週期僅分別在第 11 行和第 16 行有效,一旦超出 scope (作用範圍) 仍操作物件的話,會導致 undefined behaviour;
  • (d) gcc 的實作不符合 C99/C11 規格描述;

提示:

  1. 在資訊安全的漏洞回報中,CWE-416: Use After Free 提及 dangling pointer 的影響
  2. 在 C11 規格書中 6.2.4:2 節提及物件的生命週期:

The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

延伸問題:

  1. 從 C99/C11 規格和編譯器行為,解釋上述程式的運作,並找到真實世界中類似的案例,最好是 Linux 核心程式碼相關
  2. 上方程式的 PRIxPTR 為何?在哪裡定義?

Dangling Pointer

Dangling Pointer 指的是當一個程式中的指標不被使用的時候,例如某個記憶體區段被 free() 之後,程式並不會自動將指標設為 NULL,而是指在原來的記憶體區段,但有可能該記憶體區段已經在程式中挪為他用,而這個有指的指標就稱為 dangling pointer 。

故在使用指標時,安全起見應該要記得將不用的指標在 free() 後設為 NULL。

而一個 dangling pointer 出現時,會產生兩種情況:

  • 比較好的情況是,該區段還沒被使用,所以使用這個已經不被使用的指標時,是看到原來在該區段的舊資料
  • 比較糟的情況是,該區段已經被挪為他用,用舊的指標存取新資料,如果新資料放的是可以執行的位址,eip 會到這個位址去執行。 -> 這個會觸發 UAF

UAF (Used-after Free)

例子:CVE-2016-0728

UAF 的步驟是:

  1. 產生一個 dangling pointer
  2. 設計一段資料覆蓋在原來的位址上
  3. 用 dangling pointer 存取該資料,讓 eip 執行

這是在 Linux kernel 中的 keyring 中 find_keyring_by_name 程式碼:

long join_session_keyring(const char *name) { ... new = prepare_creds(); ... keyring = find_keyring_by_name(name, false); //find_keyring_by_name increments keyring->usage if a keyring was found if (PTR_ERR(keyring) == -ENOKEY) { /* not found - try and create a new one */ keyring = keyring_alloc( name, old->uid, old->gid, old, KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, KEY_ALLOC_IN_QUOTA, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; } } else if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; } else if (keyring == new->session_keyring) { ret = 0; goto error2; //<-- The bug is here, skips key_put. } /* we've got a keyring - now install it */ ret = install_session_keyring_to_cred(new, keyring); if (ret < 0) goto error2; commit_creds(new); mutex_unlock(&key_session_mutex); ret = keyring->serial; key_put(keyring); okay: return ret; error2: mutex_unlock(&key_session_mutex); error: abort_creds(new); return ret; }

keyring 是一個物件,我們可以用 name 作為搜尋的參考,或者不輸入傳入 NULL,而這個物件可以被 processes 之間共用,當一個 keyring 產生時,內部的 refcount 存在一個叫做 usage 的 field 會增加。但是這裡有個問題是當現在這個 process 已經有正在使用

Acyclic-Graph Directories

image alt

  • Tree-structured directories

image alt

  • Acyclic-Graph Directories

根據 Operating System Concepts 書中第十章 File System 提到,由於 Tree-structured directory 的方式不利於兩位以上共同擁有者協作進行,所以在 UNIX 的系統中採用 Acyclic-Graph Directories ,可能存在同時有兩個的指標指向同一個 directory ,在這個方法下的檔案系統,在刪除時就可能產生 dangling pointer 的情況,例如:其中一方刪除目錄時,其他共有這個目錄的其他使用者,他們的指標就會指向已經不存在的目錄,成為 dangling pointer。

IPFS

IPFS - InterPlanetary File System

Heap Exploit

Heap Exploitation - Modern Binary Exploitation CSCI 4968 - Spring 2015

  • 首先,先討論一個 heap 到底有什麼:

在 malloc() 實作中,分配的記憶體單位為 chunk 。使用者真正的資料是放在 data 的那段,而前面 previous chunk 則會記錄連續記憶體前一個 chunk 是不是在被使用,而 chunk size 裡放的 flag 則是以三個 bits 用來標記 N(non main arena)、 M(mapped,大於 128 kb 是用 mmap() 分配)、 P(prev chunk 有沒有使用)

  • 被 freed 之後:

Heap chunk 會變成這個形式,這個 chunk 會交由 glibc 以 linked list 管理,原先 allocated 的 user data 區段取 16 bytes 作為 fd 、 bk 使用,這兩個指標分別指著 linked list 中前一個 chunk 和後一個 chunk。