gpt4 book ai didi

linux - 通过脚本检查根完整性

转载 作者:太空狗 更新时间:2023-10-29 11:32:13 30 4
gpt4 key购买 nike

下面是我检查根路径完整性的脚本,以确保 PATH 变量中没有漏洞。

#! /bin/bash

if [ ""`echo $PATH | /bin/grep :: `"" != """" ]; then
echo "Empty Directory in PATH (::)"
fi

if [ ""`echo $PATH | /bin/grep :$`"" != """" ]; then echo ""Trailing : in PATH""
fi

p=`echo $PATH | /bin/sed -e 's/::/:/' -e 's/:$//' -e 's/:/ /g'`
set -- $p
while [ ""$1"" != """" ]; do
if [ ""$1"" = ""."" ]; then
echo ""PATH contains ."" shift
continue
fi
if [ -d $1 ]; then
dirperm=`/bin/ls -ldH $1 | /bin/cut -f1 -d"" ""`
if [ `echo $dirperm | /bin/cut -c6 ` != ""-"" ]; then
echo ""Group Write permission set on directory $1""
fi
if [ `echo $dirperm | /bin/cut -c9 ` != ""-"" ]; then
echo ""Other Write permission set on directory $1""
fi
dirown=`ls -ldH $1 | awk '{print $3}'`
if [ ""$dirown"" != ""root"" ] ; then
echo $1 is not owned by root
fi
else
echo $1 is not a directory
fi
shift
done

该脚本对我来说工作正常,并显示了 PATH 变量中定义的所有易受攻击的路径。我还想根据上述结果自动执行正确设置 PATH 变量的过程。任何快速的方法来做到这一点。

例如,在我的 Linux 机器上,脚本给出的输出为:

/usr/bin/X11 is not a directory
/root/bin is not a directory

而我的 PATH 变量定义了这些,所以我想有一个删除机制,将它们从 root 的 PATH 变量中删除。许多冗长的想法浮现在脑海中。但请寻找一种快速且“不那么复杂”的方法。

最佳答案

没有冒犯,但您的代码已完全损坏。您以一种……创造性的方式使用引号,但却是一种完全错误的方式。不幸的是,您的代码受到路径名扩展和分词的影响。使用不安全的代码来“保护”您的 PATH 真的很可惜。

一种策略是(安全地!)将您的 PATH 变量分成一个数组,然后扫描每个条目。拆分是这样完成的:

IFS=: read -r -d '' -a path_ary < <(printf '%s:\0' "$PATH")

查看我的 mock whichHow to split a string on a delimiter答案。

使用此命令,您将拥有一个漂亮的数组 path_ary,其中包含 PATH 的每个字段。

然后您可以检查是否有空字段、. 字段或其中的相对路径:

for ((i=0;i<${#path_ary[@]};++i)); do
if [[ ${path_ary[i]} = ?(.) ]]; then
printf 'Warning: the entry %d contains the current dir\n' "$i"
elif [[ ${path_ary[i]} != /* ]]; then
printf 'Warning: the entry %s is not an absolute path\n' "$i"
fi
done

您可以添加更多 elif,例如,检查条目是否不是有效目录:

elif [[ ! -d ${path_ary[i]} ]]; then
printf 'Warning: the entry %s is not a directory\n' "$i"

现在,要检查权限和所有权,不幸的是,没有纯 Bash 方法也没有可移植的方法。但是解析 ls 很可能不是一个好主意。 stat 可以工作,但已知在不同平台上有不同的行为。因此,您必须尝试适合您的方法。下面是一个在 Linux 上使用 GNU stat 的示例:

read perms owner_id < <(/usr/bin/stat -Lc '%a %u' -- "${path_ary[i]}")

您需要检查 owner_id 是否为 0(请注意,目录路径不属于 root 是可以的;例如,我有 /home/gniourf/bin 很好!)。 perms 是八进制的,您可以通过位测试轻松检查 g+wo+w:

elif [[ $owner_id != 0 ]]; then
printf 'Warning: the entry %s is not owned by root\n' "$i"
elif ((0022&8#$perms)); then
printf 'Warning: the entry %s has group or other write permission\n' "$i"

请注意使用 8#$perms 强制 Bash 将 perms 理解为八进制数。

现在,要删除它们,您可以在其中一个测试被触发时unset path_ary[i],然后将所有剩余的放回PATH:

else
# In the else statement, the corresponding entry is good
unset_it=false
fi
if $unset_it; then
printf 'Unsetting entry %s: %s\n' "$i" "${path_ary[i]}"
unset path_ary[i]
fi

当然,您会将 unset_it=true 作为循环的第一条指令。

然后将所有内容放回PATH:

IFS=: eval 'PATH="${path_ary[*]}"'

我知道有些人会大声疾呼 eval 是邪恶的,但这是在 Bash 中连接数组元素的规范(而且安全!)方式(注意单引号)。

最后,相应的函数可能如下所示:

clean_path() {
local path_ary perms owner_id unset_it
IFS=: read -r -d '' -a path_ary < <(printf '%s:\0' "$PATH")
for ((i=0;i<${#path_ary[@]};++i)); do
unset_it=true
read perms owner_id < <(/usr/bin/stat -Lc '%a %u' -- "${path_ary[i]}" 2>/dev/null)
if [[ ${path_ary[i]} = ?(.) ]]; then
printf 'Warning: the entry %d contains the current dir\n' "$i"
elif [[ ${path_ary[i]} != /* ]]; then
printf 'Warning: the entry %s is not an absolute path\n' "$i"
elif [[ ! -d ${path_ary[i]} ]]; then
printf 'Warning: the entry %s is not a directory\n' "$i"
elif [[ $owner_id != 0 ]]; then
printf 'Warning: the entry %s is not owned by root\n' "$i"
elif ((0022 & 8#$perms)); then
printf 'Warning: the entry %s has group or other write permission\n' "$i"
else
# In the else statement, the corresponding entry is good
unset_it=false
fi

if $unset_it; then
printf 'Unsetting entry %s: %s\n' "$i" "${path_ary[i]}"
unset path_ary[i]
fi
done

IFS=: eval 'PATH="${path_ary[*]}"'
}

这种带有 if/elif/.../else/fi 的设计非常适合这个简单的任务,但用于更复杂的测试时可能会变得笨拙。例如,请注意我们必须在测试之前尽早调用 stat,以便在测试后期可以使用信息,甚至在我们检查我们正在处理目录之前。

设计可以通过使用一种意大利面条式的可怕方式来改变,如下所示:

for ((oneblock=1;oneblock--;)); do
# This block is only executed once
# You can exit this block with break at any moment
done

通常最好使用函数而不是 this,并从函数中return。但是因为在下面我还要检查多个条目,所以我需要有一个查找表(关联数组),而且有一个独立函数使用在其他地方定义的关联数组是很奇怪的......

clean_path() {
local path_ary perms owner_id unset_it oneblock
local -A lookup
IFS=: read -r -d '' -a path_ary < <(printf '%s:\0' "$PATH")
for ((i=0;i<${#path_ary[@]};++i)); do
unset_it=true
for ((oneblock=1;oneblock--;)); do
if [[ ${path_ary[i]} = ?(.) ]]; then
printf 'Warning: the entry %d contains the current dir\n' "$i"
break
elif [[ ${path_ary[i]} != /* ]]; then
printf 'Warning: the entry %s is not an absolute path\n' "$i"
break
elif [[ ! -d ${path_ary[i]} ]]; then
printf 'Warning: the entry %s is not a directory\n' "$i"
break
elif [[ ${lookup[${path_ary[i]}]} ]]; then
printf 'Warning: the entry %s appears multiple times\n' "$i"
break
fi
# Here I'm sure I'm dealing with a directory
read perms owner_id < <(/usr/bin/stat -Lc '%a %u' -- "${path_ary[i]}")
if [[ $owner_id != 0 ]]; then
printf 'Warning: the entry %s is not owned by root\n' "$i"
break
elif ((0022 & 8#$perms)); then
printf 'Warning: the entry %s has group or other write permission\n' "$i"
break
fi
# All tests passed, will keep it
lookup[${path_ary[i]}]=1
unset_it=false
done
if $unset_it; then
printf 'Unsetting entry %s: %s\n' "$i" "${path_ary[i]}"
unset path_ary[i]
fi
done

IFS=: eval 'PATH="${path_ary[*]}"'
}

对于 PATH 中的空格、glob 字符和换行符,所有这些都是非常安全的;我唯一不喜欢的是使用外部(和不可移植的)stat 命令。

关于linux - 通过脚本检查根完整性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28740780/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com