最近在一個帖子中看到一道題:
問:下面是一個簡單的密碼保護功能,你能在不知道密碼的情況下將其破解嗎?
#include<stdio.h>
#include<string.h> int main(int argc, char *argv[]) { int flag = 0; char passwd[10]; memset(passwd,0,sizeof(passwd)); strcpy(passwd, argv[1]); if(0 == strcmp("apple", passwd)) { flag = 1; } if(flag) printf("\n Password cracked \n"); else printf("\n Incorrect passwd \n"); return 0; }
我個人感覺這道題對於我這種C語言半瓶子水的人來說還是挺有意思的,(╯▔皿▔)╯
其實答案也不難,就是利用了strcpy()函數的漏洞:
簡單來說就是用戶在向passwd數組傳值時沒有考慮會溢出的情況。如果用戶輸入的passwd足夠長,導致不僅溢出了passwd的空間而且還“侵犯”了flag變量的空間,造成flag的值不為0。最終也就導致了判斷的失效:passwd不匹配,但是flag不為0。
在程序設計中如何避免出現此情況
——
可能有同學發現,在運行上面的程序時,如果輸入的長度過長有可能會終止並報錯。
這其實是有的IDE在編譯時已經為你加入了一種檢測堆棧溢出的機制——stack protector機制。
gcc(4.9)中提供了關於stack protector機制的多個編譯選項:
-fstack-protector 啟用堆棧保護,不過只為局部變量中含有 char 數組的函數插入保護代碼。 -fstack-protector-all 啟用堆棧保護,為所有函數插入保護代碼。 stack-protector-strong 在stack-protector基礎上,增加本地數組、指向本地幀棧地址空間保護。
stack-protector-explicit 在stack-protector基礎上,增加程序中顯式屬性"stack_protect"空間。 -fno-stack-protector 禁用堆棧保護。
所以如果你的編譯器默認加入了此保護機制,你需要在gcc編譯時加入-fno-stack-protector,才能看到破解密碼的效果(●'◡'●)
進而可以很明顯的得到,要避免此種情況:
1 可以使用-fstack-protector或其它適合你的保護選項來避免堆棧的溢出。
2 從代碼編寫方面來看,可以更多的使用strncpy()結合strlen()的判斷。