目录
[四、案例一:2375 未授权接口如何改变控制链](#四、案例一:2375 未授权接口如何改变控制链)
四、案例一:2375 未授权接口如何改变控制链
课程第一个完整案例围绕 Docker Remote API 的 2375 端口。原稿先检查守护进程配置文件是否存在,再尝试让 Docker daemon 监听 0.0.0.0:2375。配置写入后,服务第一次重启失败,排查方向集中在 JSON 格式和配置项冲突。随后发现问题与 host 配置覆盖有关,于是移除冲突项,改用 containerd 的 override 配置目录重新组织参数。这里的关键不在于"写入一段配置就成功",而在于每一次失败都缩小了原因范围。

图 32:Docker 守护进程配置、端口监听与重启排错

图 33:Docker 守护进程配置、端口监听与重启排错

图 34:Docker 守护进程配置、端口监听与重启排错

图 35:Docker 守护进程配置、端口监听与重启排错

图 36:Docker 守护进程配置、端口监听与重启排错

图 37:Docker 守护进程配置、端口监听与重启排错

图 38:Docker 守护进程配置、端口监听与重启排错

图 39:Docker 守护进程配置、端口监听与重启排错

图 40:Docker 守护进程配置、端口监听与重启排错
配置排查的细节值得单独记录。实验首先确认 Docker 是否已经读取目标配置文件,再确认配置文件是否为空、是否存在同名字段以及 JSON 结构是否闭合。第一次写入之后,docker info 没有得到正常结果,服务重启也没有完成。此时不能直接判断端口配置无效,因为服务还没有进入监听状态。原稿先把问题归到格式,再检查 host 字段是否与新配置重复,最后把变更移动到 systemd 的 override 目录。每一步都对应一个可验证的假设:格式错误会导致解析失败,字段冲突会导致启动阶段拒绝,override 位置错误则会导致配置根本没有被读取。

图 37:Docker 守护进程配置、端口监听与重启排错
当配置再次调整后,服务能够继续启动,但远程请求仍然需要单独验证。实验从本机查看监听端口,再从客户端请求 API,避免把"服务已启动"误当成"接口已对外可用"。监听在 127.0.0.1 与监听在 0.0.0.0 的安全含义不同,课程实际关注的是后者是否把管理面暴露给了不应访问的网络。代理只影响镜像或文档访问,daemon 监听地址决定管理面是否暴露。
写入宿主机任务计划的验证也有层次:先确认挂载目录中出现目标文件,再确认权限,之后才检查任务是否被调度以及 shell 是否能解释脚本。原稿在 644 改为 600 后仍然没有立即看到反弹结果,说明权限只是必要条件之一。Ubuntu 环境可能使用 dash,而脚本按 bash 语法编写时,即使文件存在且权限正确,也可能因为解释器不匹配而失败。
日志排查没有采用"没有回显就等于没有执行"的判断。实验先确认查看的是宿主机日志而非容器日志,再区分登录日志和任务计划相关日志。由于当前日志没有出现预期执行记录,最终只能确认文件已经写入,不能确认任务计划已触发。这个未完成状态揭示了攻击链中的真实断点:挂载能力成立,但触发条件和脚本兼容性尚未完成验证。
配置生效后,实验使用 docker info 和端口检查确认守护进程是否真的监听。原稿还记录了代理和镜像源问题:拉取 Nginx 镜像时,网络访问不稳定,代理端口被调整过,部分尝试因为外部连接失败而暂停。最终通过已有镜像完成容器启动,使用 docker run -itd -p 8080:80 --name nginx-test 创建测试容器,并进入容器再次验证 .dockerenv、进程数量和网络状态。

图 41:2375 接口访问、根目录挂载与任务计划验证

图 42:2375 接口访问、根目录挂载与任务计划验证

图 43:2375 接口访问、根目录挂载与任务计划验证

图 44:2375 接口访问、根目录挂载与任务计划验证
端口暴露后,授权实验从另一端调用 API,先获取容器列表,再核对容器名称、镜像、镜像 ID、映射端口和容器内部端口。第一次查询没有返回预期结果,原因是测试容器已经停止;重新启动后,列表信息恢复。这个现象说明接口本身可达,并不代表目标容器一定处于运行状态,状态信息必须结合 docker ps 的时间点和退出结果判断。

图 45:2375 接口访问、根目录挂载与任务计划验证

图 46:2375 接口访问、根目录挂载与任务计划验证

图 47:2375 接口访问、根目录挂载与任务计划验证
接下来实验利用 Docker 管理接口创建新容器,并把宿主机根目录挂载到新容器的某个目录。挂载完成后,通过 chroot 或切换到挂载目录观察文件,发现目录内容不再包含 .dockerenv,而是宿主机根目录的文件。这个差异构成了验证闭环:请求由远程 daemon 接收,daemon 让运行时创建容器,容器挂载了宿主机根目录,最终在容器内得到宿主机文件视图。

图 48:2375 接口访问、根目录挂载与任务计划验证

图 49:2375 接口访问、根目录挂载与任务计划验证

图 50:2375 接口访问、根目录挂载与任务计划验证

图 51:2375 接口访问、根目录挂载与任务计划验证
原稿随后尝试通过宿主机的任务计划写入反弹命令。第一次写入没有触发,排查依次考虑了写入路径、文件权限和 Ubuntu 使用的 shell。宿主机上的任务计划文件被确认已经出现,但权限为 644,课程认为这可能不符合任务计划的读取要求,于是改为 600。权限调整仍不能保证执行,因为当前系统的 shell 可能是 dash,而脚本按 bash 语法调用时会出现找不到解释器或语法不兼容。

图 52:2375 接口访问、根目录挂载与任务计划验证

图 53:2375 接口访问、根目录挂载与任务计划验证

图 54:2375 接口访问、根目录挂载与任务计划验证

图 55:2375 接口访问、根目录挂载与任务计划验证

图 56:2375 接口访问、根目录挂载与任务计划验证

图 57:2375 接口访问、根目录挂载与任务计划验证

图 58:2375 接口访问、根目录挂载与任务计划验证
为此,原稿把命令包裹为 sh -c 形式再次验证,并结合宿主机日志观察任务计划是否执行。日志没有立即给出明确结果,说明"文件写入成功"和"任务计划触发成功"是两个独立状态。最终课程把这一案例归纳为:2375 暴露后,远端能够控制 daemon;daemon 能创建带危险挂载的容器;容器中的写入作用于宿主机文件系统;后续是否触发,还受权限、路径和 shell 环境影响。

图 59:2375 接口访问、根目录挂载与任务计划验证
经验判断:
2375未授权访问的危害来自管理接口本身,而不是某条特殊 payload。真正需要优先确认的是监听地址、访问控制、网络隔离和 daemon 的实际权限。