深入 PATH


Linux 启明道场.

到目前为止,你已经用过以下几种方式调用命令:

  • 使用绝对路径(例如 /challenge/run)。
  • 使用相对路径(例如 ./run)。
  • 直接使用命令名(例如 ls)。

前两种方式,也就是绝对路径和相对路径,很容易理解:run 文件位于 /challenge 目录中,这两种写法都指向该文件(当然,使用相对路径时,当前工作目录必须是 /challenge)。 但最后一种方式呢? ls 程序到底在哪里? shell 又怎么知道该去那里查找?

本模块将揭开其中的奥秘,回答这个问题! 继续学下去吧。


其实,“shell 如何找到 ls?”这个问题的答案很简单。 shell 中有一个名为 PATH 的特殊变量,其中保存了一系列目录路径。shell 会在这些目录中查找命令对应的程序。 如果清空这个变量,就会出问题:

hacker@dojo:~$ ls
Desktop    Downloads  Pictures  Templates
Documents  Music      Public    Videos
hacker@dojo:~$ PATH=""
hacker@dojo:~$ ls
bash: ls: No such file or directory
hacker@dojo:~$

没有 PATH,bash 就找不到 ls 命令了。

本关中,你要干扰 /challenge/run 程序的运行。 这个程序会删除 flag 文件,使用的命令是 rm。 不过,如果它找不到 rm 命令,flag 就不会被删除,挑战程序就会把 flag 交给你! 所以,你需要让 /challenge/run 也找不到 rm 命令!

记住:如果你没有成功,flag 被删掉了,就需要重新启动挑战再试!

清空 PATH 会让命令无法正常运行。 那么,怎样利用它做一些有用的事情呢?我们来看看如何设置 PATH。

例如,怎样把一个新目录里的程序加入可用命令的行列? 回顾一下,PATH 中保存着用于查找命令的目录列表。如果命令位于非标准位置,通常必须通过路径来执行:

hacker@dojo:~$ ls /home/hacker/scripts
goodscript	badscript	okayscript
hacker@dojo:~$ goodscript
bash: goodscript: command not found
hacker@dojo:~$ /home/hacker/scripts/goodscript
YEAH! This is the best script!
hacker@dojo:~$

如果你有一些常用脚本,希望直接输入名称就能运行,每次都写路径会很麻烦。 不过,只要在这个列表中添加或替换目录,就可以直接使用名称启动这些程序! 例如:

hacker@dojo:~$ PATH=/home/hacker/scripts
hacker@dojo:~$ goodscript
YEAH! This is the best script!
hacker@dojo:~$

来练习一下。 本关的 /challenge/run 会直接通过名称运行 win 命令,但该命令位于 /challenge/more_commands/ 目录中,而这个目录最初并不在 PATH 中。 win 命令是 唯一一个 /challenge/run 需要调用的命令,因此你可以直接把 PATH 的值替换为这个目录。 祝你好运!

当你输入一个命令名时,实际执行的是某个程序,它位于 $PATH 变量列出的某个目录中(当然,内建命令除外!)。 但具体是哪一个文件呢? 你可以用名字十分贴切的 which 命令来查明:

hacker@dojo:~$ which cat
/bin/cat
hacker@dojo:~$ /bin/cat /flag
YEAH
hacker@dojo:~$

和 shell 查找命令的方式一样,which 会依次检查 $PATH 中的每个目录,并输出它找到的第一个与所传参数同名的文件。

本挑战添加了一个 win 命令,它位于你的 $PATH 的某个目录中,但运行它并不会得到 flag。 它所在的目录里还有一个 flag 文件,我们已经允许你读取该文件! 你需要先找到 win(使用 which 命令),然后使用 cat 读出该目录中的 flag!

回顾上一关中的例子:

hacker@dojo:~$ ls /home/hacker/scripts
goodscript	badscript	okayscript
hacker@dojo:~$ PATH=/home/hacker/scripts
hacker@dojo:~$ goodscript
YEAH! This is the best script!
hacker@dojo:~$

在这个例子中,hacker 用户添加了自己的命令,让 shell 更符合自己的需求。 随着经验积累,你也会拥有一套得心应手的工具。 就从 win 开始吧!

之前,win 命令会被 /challenge/run 调用,并且存放在 /challenge/more_commands 中。 这一次,win 还不存在! 回想一下“串联命令”模块的最后一关,创建一个名为 win 的 shell 脚本,把它所在的目录加入 PATH,让 /challenge/run 能找到它!


提示: /challenge/run 以 root 身份运行,并会调用 win。因此,win 只需用 cat 读取 flag 文件即可。 同样,win 命令是 唯一一个 /challenge/run 需要调用的命令,因此你可以直接把 PATH 的值替换为这个目录。 但记住,如果这么做,你的 win 命令就会找不到 cat。

有三种方法可以避免这个问题:

  1. 找到文件系统中 cat 程序的位置。它一定位于 PATH 变量列出的某个目录中,所以你可以先输出这个变量(如果忘了怎么做,参阅“Shell 变量”!),再逐个查看其中的目录(记住,各个条目用 : 分隔),找出哪个目录中有 cat,然后使用绝对路径调用 cat。
  2. 设置一个 PATH,保留原来的目录,再加上你创建 win 时所用的目录。
  3. 使用 read(同样可以参阅“Shell 变量”)来读取 /flag。由于 read 是 bash 的内建功能,因此不会受 PATH 变化的影响。

现在,去运行 win,赢下这一关吧!

掌握了这些知识,你就可以玩点花样了。 本挑战与本模块的第一关几乎一样。 挑战程序仍然会使用 rm 命令删除 flag。 不过,这次它不会为你输出任何内容。

该怎么解决呢? 你知道,shell 会查找 rm 命令,查找范围是 PATH 变量列出的目录。 上一关中,你已经为挑战创建过 win 命令。 你还能创建什么命令呢?


30天排行榜:

此排行榜反映本模块在道场上线后各挑战的解出情况。

排名 黑客 徽章 得分
暂无解题排行数据 —— 注册账号并完成挑战即可登上榜单!