接下來的Stack buffer overflow都會利用Ubuntu環境下GCC所產生的程式來實作,這邊寫一個小程式,基本上就是個簡單的輸入輸出然後就結束的一支小程式。
但當我們利用GCC生成時會出現warning,第一個warning通常是說你調用了某個函數,但在標頭沒有設定,而gets這個東東已經被判定成危險的寫法了,程式會覺得你是不是要寫fgets。
第二個是程式直接跟你說gets不要用。
我們看到man是怎麼介紹gets的,直接寫著Never use this function,那我們就來用看看會發生怎樣的事。
正常是打一串字,然後就回一串相同的字給我,但可以發現如果字串太長,會出現Segmentation fault,這種情況就是典型的Stack buffer overflow。
我們放到GDB上來看看,把break point設在gets前。
這邊要提到之前說的Stack,在這支程式我們可以想像到,Stack在這支程式總共的空間是0x10,然後最下面會有Old RBP和結束後轉跳哪裡,要給RIP的值,有了上述的基本概念後,接著來看在call gets前的暫存器和Stack的樣子。
然後我們到gets的地方,輸入Hello看看Stack的狀態,字串的位址是放在RBP-0x1的地方,就直接來看看那個位址的變化。
為了有明顯的比較,我們再輸入一次Hello,只是這次我們在後面多加一個驚嘆號Hello!,來看看程式有什麼變化。
這邊就很清楚的看到驚嘆號的ASCII code是21,如果仔細想想會覺得怪怪的,在之前有說過,程式在做結束動作時,會先把RSP 加回來,讓RSP和RBP相同,再把Old RBP給POP出去,也就是說Old RBP放的位置就是在目前RBP位置的下一個地方,而這個程式的RBP卻是放著我們剛剛打的字串,這就會導致程式在結束時,會將我們的字串當成是Old RBP給POP到RBP上,所以我們來看看這支程式跑完後的RBP值是長什麼樣子。
可以看到程式把我們的Hello!吃進去了,換言之,如果我們輸入一些有意義的RBP值,程式的RBP就會轉跳到那邊去,這就是Stack buffer overflow,下一章就來控制程式走向。