# 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。