Format String Vulnerability Lab——格式化字符串漏洞

1 實驗概述

格式化字符串漏洞是由像printf(user_input)之類代碼引起的,這裏user_input變量的內容由用戶提供。當這個程序由特權運行(例如Set-UID程序),這個printf會導致以下情況之一:

(1)程序崩潰;
(2)從內存任意位置讀取;
(3)修改任意內存位置的值。

應該注意,這個實驗的輸出依賴於操作系統,我們的描述和討論是基於Fedora Linux (Core 4),如果你使用了不同的操作系統,可能會出現不同的情況和問題。

2 實驗任務

2.1 任務1
在下面的程序中,你將被要求提供一個輸入,它將被存放在一個叫做user_input的緩衝區中。接下來程序用printf打印出此緩衝區。這個程序是一個Set-UID程序(有效執行用戶是root),即它用root權限運行。不幸的是,在用戶輸入調用printf的途徑中有一個格式化字符串漏洞。我們想要攻擊這個漏洞,看看能造成多大的損害。這個程序有兩個secret值存在它的內存裏,你對這兩個值很感興趣。然而,你不知道這兩個值,也不能從二進制代碼中找到它們(爲簡化,我們用常數0x44和0x55將這兩個secret值硬編碼)。儘管你不知道secret值,在實踐中,找到它們的內存地址(範圍或確切地址)並不困難(它們的地址是連續的),因爲對於許多操作系統而言,任何時候運行程序地址都是完全一樣的。本實驗中,我們假設你已經知道了確切地址。爲達到這個目的,程序“故意”爲你打印出地址。有了這些知識,你的目標如下(不需要同時完成):
• (25 分)使程序崩潰
• (25 分)打印出secret[1]的值
• (25 分)修改secret[1]的值
• (25 分)將secret[1]的值修改爲一個預先設定的值
注意到(Set-UID)程序的二進制代碼對你僅僅是可讀/可執行,你無法修改。也就是說,你不能通過修改代碼達到上述目標。然而,你有一份源碼的拷貝幫助你設計攻擊:

/* vul_prog.c */
#define SECRET1 0x44
#define SECRET2 0x55
int main(int argc, char *argv[])
{
char user_input[100];
int *secret;
int int_input;
int a, b, c, d; /* other variables, not used here.*/
/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));
/* getting the secret */
secret[0] = SECRET1; secret[1] = SECRET2;
printf("The variable secret’s address is 0x%8x (on stack)\n", &secret);
printf("The variable secret’s value is 0x%8x (on heap)\n", secret);
printf("secret[0]’s address is 0x%8x (on heap)\n", &secret[0]);
printf("secret[1]’s address is 0x%8x (on heap)\n", &secret[1]);
printf("Please enter a decimal integer\n");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */
/* Vulnerable place */
printf(user_input);
printf("\n");
/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2);
printf("The new secrets: 0x%x -- 0x%x\n", secret[0], secret[1]);
return 0;
}

我們先打開地址隨機化:sysctl -w kernel.randomize_va_space=2
在這裏插入圖片描述
編譯、設置爲setuid程序。

[01/15/2019 19:05] root@ubuntu:/home/seed/lab3# gcc -o vul vul_prog.c
[01/15/2019 19:06] root@ubuntu:/home/seed/lab3# chmod 4755 vul

1 使程序崩潰

我們從代碼中可以看到user_input大小爲100,所以我們輸入的字節數大於100時就會出現段錯誤。

perl -e 'print "12" . "\n" . "A"x1200 . "\n"' | ./vul

這種輸入方式等價於執行該程序然後輸入 12(第一個要求輸入的整數) ->回車換行->輸入1200個A(使程序崩潰)->回車換行
在這裏插入圖片描述

2 從內存任意位置讀取

找出 int_input 在堆棧中的位置。
在這裏插入圖片描述
已經知道了我們輸入的整數對應的位置,我們就可以得到任意地址中存放的值。
得到 Secret[1]的值。
先運行程序,讀取secret[1]的地址爲0x899c00c,將它轉換成十進制,用%s可以將地址中的內容以字符串形式讀出來。

在這裏插入圖片描述
在這裏插入圖片描述
U的ASCII碼爲85,轉換成16進製爲0x55,所以我們讀出的U就是secret1中內容轉化成字符串的結果。

3 修改 secret[1]的值

將%s 換成%n 可輸出當前已經輸出的字節數。
將 secret[1]的值修改成預先設定的值 0xab
此處計算爲:0xab-(0x3a-0x08)
在這裏插入圖片描述
修改成功,想修改成其他值方法類似。

還有關閉地址隨機化的情況,在這種情況下,不用每次都將secret1地址的值轉換成對應的十進制了,因爲地址不會每次都改變了,但是這種情況下可能會遇到特殊字符\x0c等,這種情況怎麼解決呢?由於我的方法不是很提倡,這裏就不放出來了,大家自己探索哦~

(以上是自己實驗課做的步驟,可能會有錯誤,歡迎留言指正)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章