void foo(char *data){
char name[10];
printf("%p\n%p\n%p\n%p\n");//打印当前程序栈内存
strcpy(name, data);//覆盖返回地址
}
void hack(void){
puts("another place");
}
int main(){
char buf[10];
char buf2[10];
scanf("%s", buf);
foo(buf);
return 0;
}
以上是经典的缓冲区溢出攻击,当buf中输入超过10(16)字节,将会覆盖buf2中的内容;如果写入更多字节数,可以改变寄存器中保存的地址,使得被调用函数执行完成后返回到另一个函数的入口地址。
问题:
当前保护机制下,只能覆盖buf2中内容,但是即便跳过很长的内存保护的区域依然找不到记录被调函数返回地址的位置。1.在linux下不采用任何内存保护方法编译源代码的方法?2.关于现在内存保护机制下缓冲区溢出攻击的可能形式。
PHP中文网2017-04-17 11:18:58
Stack protector 的實作是在堆疊上放一個canary隨機值,在函數呼叫完成後,檢查這個值是否原樣,如果不是原樣則證明棧被破壞了。
你的原程式碼是有問題的。如果你輸入的東西溢出了緩衝區,那麼它就會覆蓋scanf的回傳位址,那麼就無法正確回傳,也就不能呼叫foo了。
我猜你想要的是這樣:
void foo(char *data){
scanf("%s", data);
printf("%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n");
}
int main(){
char buf[10];
char buf2[10];
foo(buf);
return 0;
}
有些常識需要知道,不是你輸入超出20個字元長度就一定能將回傳地址覆蓋。局部變數在堆疊上的分配,並不是緊湊的,通常情況下都會進行align,並且按16位元組對齊。
所以,如果你輸入很多字元(超過64?),你是能得到segment fault的。
但你沒有辦法改正確回地址,一個是因為ALSR,Address space layout randomization,另一個是因為canary本身是隨機值,你也無法覆蓋正確,最終逃不過檢查。
所以,你只能搞出segmentfault的效果,卻並不能覆寫回傳位址還能讓程式碼繼續正常運作。
1.在linux下不採用任何記憶體保護方法編譯原始碼的方法?
GCC有一個-fno-stack-protector參數。預設情況下stack-protector是啟用的,GCC偵測到函數參數類型為char *,且沒有限定長度時,它就會在函數呼叫前,在堆疊上放一個canary。
問題2目前我不想多去思考。