进程溯源与sudo代理脚本用户定位技术问询
进程溯源与sudo代理脚本用户定位技术问询
您好,针对您提出的sudo代理脚本sodo无法定位实际执行用户的问题,咱们可以从实操角度一步步解决这个痛点:
先梳理下当前的核心问题
您的sodo脚本已经实现了命令白名单控制(仅允许执行firewall-cmd、ip、systemctl),也做了基础日志记录,但因为用户是通过sudo切换到root身份运行脚本,$USER会返回root,没法直接锁定发起操作的真实用户;更棘手的是如果有人在公共路径(比如/var下)的Python脚本里调用sodo搞事情,仅凭当前日志里的PID根本没法追溯到是谁发起了恶意操作(比如停服务)。
您提到的PID溯源思路完全可行!而且还有更简便的捷径
其实不用复杂的父进程追溯,sudo本身就给我们留了后门——当用户通过sudo执行命令时,系统会自动设置$SUDO_USER环境变量,这个变量直接存储了发起sudo请求的原始用户名,准确率拉满!
当然,如果遇到极端场景(比如用户先sudo到root再手动运行sodo),$SUDO_USER会失效,这时候再用您说的父进程溯源方案兜底就好。
具体实现方案
我给您修改了sodo脚本,加入了真实用户获取逻辑,同时优化了日志记录:
#!/bin/bash # 获取实际发起请求的用户:优先用sudo环境变量,兜底用父进程追溯 get_real_user() { # 优先读取sudo自带的环境变量,高效准确 if [ -n "$SUDO_USER" ]; then echo "$SUDO_USER" return fi # 当SUDO_USER不存在时,向上追溯父进程链 local pid=$$ while true; do # 获取当前进程的父PID local ppid=$(ps -o ppid= -p "$pid" | tr -d ' ') # 追到init/systemd(PID=1)就停止 if [ "$ppid" -eq 1 ]; then break fi # 获取父进程的所属用户 local user=$(ps -o user= -p "$ppid" | tr -d ' ') # 找到非root的用户就是实际发起者 if [ "$user" != "root" ]; then echo "$user" return fi # 继续向上追溯 pid="$ppid" done # 实在追不到就标记为unknown echo "unknown" } # 白名单命令处理逻辑 case $1 in firewall-cmd|ip|systemctl) eval $* ret=$? ;; *) echo 'your request is not allowed yet, please contact the root user' exit 1 ;; esac # 成功执行后记录日志,加入真实用户信息 if [ $ret -eq 0 ];then real_user=$(get_real_user) # 用$()替代反引号,可读性更好 echo "$(date +"%Y-%m-%d %X"): executed order from $(pwd) by user $real_user pid $$ to $*" >> /root/sodo.log fi
关键细节说明
$SUDO_USER的优势:不管用户是直接在shell里执行sudo ./sodo,还是通过Python脚本嵌套调用,只要是通过sudo触发的,这个变量都会准确记录原始用户,完全不需要追溯进程链。- 父进程溯源的兜底作用:如果有人已经是
root身份运行sodo(虽然您的sudo规则应该限制了这种情况),脚本会沿着PID链向上找,直到找到非root的进程用户,或者追到系统初始化进程为止。 - 日志优化:把原来的反引号换成
$(),可读性更强,同时新增了user $real_user字段,直接在日志里标记真实操作者。
关于漏洞的补充说明
修改后的脚本完美解决了您担心的“公共路径脚本调用无法定位”问题——哪怕用户在/var下的Python脚本里调用sodo,$SUDO_USER依然会记录他的原始用户名,日志里一眼就能看到是谁发起的操作。
备注:内容来源于stack exchange,提问作者George Y
相关产品推荐
相关产品推荐

