# quiz11 Q2 contributed by <`nashi556`, `ga6394870`> ## 測驗 `2` 考慮以下程式碼: ```Clike= #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 a` 和 `char b` 這兩個物件的生命週期僅分別在第 11 行和第 16 行有效,一旦超出 scope (作用範圍),C 語言編譯器就會主動釋放物件,而透過 `&` (value-of) 運算子得到的地址自然就不再有效; * `(c)` `char a` 和 `char b` 這兩個物件的生命週期僅分別在第 11 行和第 16 行有效,一旦超出 scope (作用範圍) 仍操作物件的話,會導致 undefined behaviour; * `(d)` gcc 的實作不符合 C99/C11 規格描述; 提示: 1. 在資訊安全的漏洞回報中,[CWE-416: Use After Free](https://cwe.mitre.org/data/definitions/416.html) 提及 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. :::success 延伸問題: 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](https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2016-0728) UAF 的步驟是: 1. 產生一個 dangling pointer 2. 設計一段資料覆蓋在原來的位址上 3. 用 dangling pointer 存取該資料,讓 eip 執行 這是在 Linux kernel 中的 keyring 中 find_keyring_by_name 程式碼: ```C= 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](https://4.bp.blogspot.com/-HjN3pWFST1w/VLc25AL7GKI/AAAAAAAAlJo/ukm2qUoDs5U/s400/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%2B2014-12-10%2B%E4%B8%8B%E5%8D%881.00.44-22.png) * Tree-structured directories ![image alt](https://2.bp.blogspot.com/-EjTi86eE_Zo/VLc25L2q0mI/AAAAAAAAlJs/rRoCqieWMI4/s400/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%2B2014-12-10%2B%E4%B8%8B%E5%8D%881.09.49-25.png) * 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](https://ipfs.io/) ![](https://cdn-images-1.medium.com/max/2000/1*84YPXEWxIyuH7WGousjsjg.jpeg) ### Heap Exploit [Heap Exploitation - Modern Binary Exploitation CSCI 4968 - Spring 2015](http://security.cs.rpi.edu/courses/binexp-spring2015/lectures/17/10_lecture.pdf) * 首先,先討論一個 heap 到底有什麼: ![](https://i.imgur.com/lrADdAM.png) 在 malloc() 實作中,分配的記憶體單位為 chunk 。使用者真正的資料是放在 data 的那段,而前面 previous chunk 則會記錄連續記憶體前一個 chunk 是不是在被使用,而 chunk size 裡放的 flag 則是以三個 bits 用來標記 N(non main arena)、 M(mapped,大於 128 kb 是用 mmap() 分配)、 P(prev chunk 有沒有使用) * 被 freed 之後: ![](https://i.imgur.com/D5vIKA0.png) Heap chunk 會變成這個形式,這個 chunk 會交由 glibc 以 linked list 管理,原先 allocated 的 user data 區段取 16 bytes 作為 fd 、 bk 使用,這兩個指標分別指著 linked list 中前一個 chunk 和後一個 chunk。