脚本带交互式菜单,运行前会显示当前权限状态,执行前需确认,防止误操作。
新建一个suid_sgid_manager.sh文件,将下面的代码完整写入保存后上传到服务器并赋予执行权限,以root权限运行:
chmod +x suid_sgid_manager.sh2. 运行(root权限)
sudo ./suid_sgid_manager.sh完整代码
#!/bin/bash
# ======== suid_sgid_manager.sh ============================
# =============== by laitai.top ============================
# SUID / SGID 权限一键管理脚本
# 作用:批量去除 / 恢复系统指定文件的 SUID / SGID 特殊权限
# 目标文件清单:
# /usr/bin/gpasswd (SUID root)
# /usr/bin/chfn (SUID root)
# /usr/bin/chsh (SUID root)
# /usr/bin/newgrp (SUID root)
# /bin/mount (SUID root)
# /bin/umount (SUID root)
# /usr/bin/chage (SGID shadow)
# ============================================================
# ---------- 目标文件与默认权限定义 ----------
# SUID 文件列表(u+s)
SUID_FILES=(
"/usr/bin/gpasswd"
"/usr/bin/chfn"
"/usr/bin/chsh"
"/usr/bin/newgrp"
"/bin/mount"
"/bin/umount"
)
# SGID 文件列表(g+s)
SGID_FILES=(
"/usr/bin/chage"
)
# ---------- 颜色定义 ----------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# ---------- 函数:打印分隔线 ----------
print_line() {
echo "------------------------------------------------------------"
}
# ---------- 函数:检查 root 权限 ----------
check_root() {
if [ "$(id -u)" -ne 0 ]; then
echo -e "${RED}[错误] 请使用 root 用户或 sudo 运行此脚本!${NC}"
exit 1
fi
}
# ---------- 函数:显示当前权限状态 ----------
show_status() {
echo -e "${BLUE}【当前权限状态】${NC}"
print_line
echo -e "文件路径 | 当前权限 | 特殊位"
print_line
for f in "${SUID_FILES[@]}" "${SGID_FILES[@]}"; do
if [ -e "$f" ]; then
perms=$(stat -c "%a" "$f")
special=$(ls -l "$f" | awk '{print $1}' | cut -c4)
if [ "$special" = "s" ]; then
special_tag="${YELLOW}s${NC}"
else
special_tag="-"
fi
printf "%-26s | %-8s | %s\n" "$f" "$perms" "$special_tag"
else
echo -e "${RED}$f 不存在!${NC}"
fi
done
print_line
}
# ---------- 函数:选项1 - 去除 SUID/SGID ----------
remove_special() {
echo -e "${YELLOW}【即将执行:批量去除 SUID / SGID 权限】${NC}"
echo "影响文件:"
for f in "${SUID_FILES[@]}" "${SGID_FILES[@]}"; do
echo " - $f"
done
echo ""
read -p "确认执行?(y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo -e "${RED}已取消操作。${NC}"
return
fi
echo ""
echo -e "${GREEN}>>> 开始去除 SUID ...${NC}"
for f in "${SUID_FILES[@]}"; do
if [ -e "$f" ]; then
chmod u-s "$f" && echo -e " ${GREEN}[OK]${NC} $f 已去除 SUID"
else
echo -e " ${RED}[跳过]${NC} $f 不存在"
fi
done
echo ""
echo -e "${GREEN}>>> 开始去除 SGID ...${NC}"
for f in "${SGID_FILES[@]}"; do
if [ -e "$f" ]; then
chmod g-s "$f" && echo -e " ${GREEN}[OK]${NC} $f 已去除 SGID"
else
echo -e " ${RED}[跳过]${NC} $f 不存在"
fi
done
echo ""
echo -e "${GREEN}=====================================${NC}"
echo -e "${GREEN} 去除操作完成!${NC}"
echo -e "${GREEN}=====================================${NC}"
}
# ---------- 函数:选项2 - 回滚恢复默认权限 ----------
restore_default() {
echo -e "${YELLOW}【即将执行:恢复 SUID / SGID 默认权限】${NC}"
echo "影响文件:"
for f in "${SUID_FILES[@]}"; do
echo " - $f (恢复 u+s)"
done
for f in "${SGID_FILES[@]}"; do
echo " - $f (恢复 g+s)"
done
echo ""
read -p "确认执行?(y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo -e "${RED}已取消操作。${NC}"
return
fi
echo ""
echo -e "${GREEN}>>> 恢复 SUID ...${NC}"
for f in "${SUID_FILES[@]}"; do
if [ -e "$f" ]; then
chmod u+s "$f" && echo -e " ${GREEN}[OK]${NC} $f 已恢复 SUID"
else
echo -e " ${RED}[跳过]${NC} $f 不存在"
fi
done
echo ""
echo -e "${GREEN}>>> 恢复 SGID ...${NC}"
for f in "${SGID_FILES[@]}"; do
if [ -e "$f" ]; then
chmod g+s "$f" && echo -e " ${GREEN}[OK]${NC} $f 已恢复 SGID"
else
echo -e " ${RED}[跳过]${NC} $f 不存在"
fi
done
echo ""
echo -e "${GREEN}=====================================${NC}"
echo -e "${GREEN} 回滚恢复完成!${NC}"
echo -e "${GREEN}=====================================${NC}"
}
# ---------- 主菜单 ----------
main_menu() {
clear
echo -e "${BLUE}╔═══════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ SUID / SGID 权限一键管理工具 by Laitai.top ║${NC}"
echo -e "${BLUE}╚═══════════════════════════════════════════════════╝${NC}"
echo ""
show_status
echo ""
echo -e "${YELLOW}请选择操作:${NC}"
echo " 1. 一键去除 SUID / SGID 权限"
echo " 2. 一键回滚恢复默认权限"
echo " 3. 刷新查看当前状态"
echo " 0. 退出"
echo ""
read -p "请输入选项 [0-3]: " choice
case $choice in
1)
echo ""
remove_special
echo ""
read -p "按回车键返回主菜单..."
main_menu
;;
2)
echo ""
restore_default
echo ""
read -p "按回车键返回主菜单..."
main_menu
;;
3)
echo ""
read -p "按回车键返回主菜单..."
main_menu
;;
0)
echo -e "${GREEN}再见!${NC}"
exit 0
;;
*)
echo -e "${RED}无效选项,请重新输入!${NC}"
sleep 1
main_menu
;;
esac
}
# ---------- 脚本入口 ----------
check_root
main_menu3. 菜单说明
| 选项 | 功能 |
|---|---|
| 1 | 一键去除:对 6 个 SUID 文件执行 chmod u-s,对 1 个 SGID 文件执行 chmod g-s |
| 2 | 一键回滚:恢复所有文件的默认 SUID/SGID 权限 |
| 3 | 刷新查看当前各文件权限状态 |
| 0 | 退出 |
安全设计
- 运行前先检查 root 权限,非 root 直接退出
- 每次执行操作前列出影响文件并要求输入
y确认 - 顶部实时显示每个文件当前权限和特殊位状态
- 文件不存在时自动跳过,不报错中断
包含的文件清单
SUID 去除 / 恢复(u+s):
/usr/bin/gpasswd/usr/bin/chfn/usr/bin/chsh/usr/bin/newgrp/bin/mount/bin/umount
SGID 去除 / 恢复(g+s):
/usr/bin/chage
说明
| 命令 | 原本权限 | 作用 | 去掉特殊位之后的后果 |
|---|---|---|---|
| /usr/bin/gpasswd | SUID root | 普通用户可以修改组密码、管理用户附属组 | 普通用户无法再修改组密码,无法管理附属组;root 本身不受影响 |
| /usr/bin/chfn | SUID root | 普通用户修改自己的 finger 信息(个人备注) | 普通用户不能修改自己的 GECOS 信息,root 仍可操作 |
| /usr/bin/chsh | SUID root | 普通用户修改自己的登录 shell | 普通用户无法更换自己的 shell,root 不受影响 |
| /usr/bin/newgrp | SUID root | 普通用户临时切换有效用户组 | 普通用户不能执行 newgrp 切换组 |
| /bin/mount | SUID root | /etc/fstab里标记user选项的分区,允许普通用户挂载 | 普通用户再也不能挂载 fstab 中 user 标记的分区,root 依旧可以 mount |
| /bin/umount | SUID root | /etc/fstab中user挂载的分区,普通用户卸载 | 普通用户无法卸载自己挂载的分区,root 不受影响 |
| /usr/bin/chage | SGID shadow | chage 需要读取/etc/shadow(shadow 组权限) | 普通用户无法查看密码过期信息;root 执行 chage 不受影响 |
