【入门笔记】CSE 365 - Fall 2024之Linux Luminarium(pwn.college)

【笔记】CSE 365 - Fall 2024之Linux Luminarium(pwn.college)

Hello Hackers

https://pwn.college/中的免费靶场,出自亚利桑那州立大学

本模块将教你与命令行交互的基础知识!命令行允许您执行命令。当您启动终端时,它将执行命令行 “shell”,如下所示:

hacker@dojo:~$

这称为 “prompt”,它会提示您输入命令。让我们来看看这里发生了什么:

提示中的hacker是当前用户的用户名。在 pwn.college网站的虚拟机DOJO环境中,默认用户就是“hacker”。

在上面的示例中,提示符的 dojo 部分是 shell 所在的机器的主机名(例如,如果您是每天处理许多机器的系统管理员,则此提醒可能很有用)。在上面的例子中,主机名是 dojo,但在 pwn.college 中,它将从你正在尝试的挑战的名称派生出来。

我们可以看看自己的虚拟机,你可以看到自己的主机名接在你的用户名后边

image-20241019191138269

我们稍后会介绍 ~ 的含义 :-)

提示符末尾的 $ 表示hacker不是管理用户。在 pwn.college 的后面的模块中,当你学会使用漏洞利用程序成为管理用户时,你会看到这里会通过回显 # 而不是 $ 来表示你的权限,然后你就会知道你成功了!

Intro to Commands 命令介绍

在这个挑战中,您将调用您的第一个命令!当您键入命令并按 Enter 键时,将调用该命令,如下所示:

hacker@dojo:~$ whoami
hacker
hacker@dojo:~$

这里,用户执行了 whoami 命令,该命令只是将用户名 (hacker) 打印到终端。当命令终止时,shell 将再次显示提示符,为下一个命令做好准备。

在这一关中,调用 hello 命令以获取flag!请记住:Linux 中的命令区分大小写:helloHELLO 不同。

查看解析
hello
我们直接输入"hello"即可调用"hello"命令

Intro to Argument 参数介绍

让我们尝试更复杂的方法:带有参数的命令,这就是我们所说的传递给命令的附加数据。当您键入一行文本并按 Enter 键时,shell 实际上会将您的输入解析为命令及其参数

第一个单词是命令,后面的单词是参数。示例如下:

hacker@dojo:~$ echo Hello
Hello
hacker@dojo:~$

在本例中,命令是 echo,参数是 Helloecho 是一个简单的命令,它将其所有参数都“回显”到终端上,就像您在上面的会话中看到的那样。

让我们看看具有多个参数的 echo

hacker@dojo:~$ echo Hello Hackers!
Hello Hackers!
hacker@dojo:~$

在本例中,命令是 echo,而 HelloHackers!echo 的两个参数。很简单对吧!

在此挑战中,要获取flag,您必须运行带有一个 hackers 参数的hello命令(不是 echo 命令)。现在就试试吧!

查看解析
hello hackers
我们在"hello"命令后接上"hackers"参数即可

Pondering Paths 思考路径

The Root 根

文件系统从 / 开始。在此之下,还有一大堆其他目录、配置文件、程序,最重要的是,还有flag。在这个关卡中,我们在 / 目录中添加了一个名为 pwn 的程序,它将为你提供flag。在这一关中,您需要做的就是调用此程序!

您可以通过在命令行上提供程序的路径来调用程序。在本例中,您将提供从 / 开始的确切路径,因此路径将为 /pwn。这种以根目录开头的路径样式称为 “绝对路径”。

开始挑战,启动一个终端,使用其绝对路径调用 pwn 程序,然后得到其中的flag!祝你好运!

我们可以观察自己虚拟机的文件结构,可以看出linux系统一切皆文件的理念

查看解析
/pwn
通过在"pwn"程序前加上"/"调用处于根目录的"pwn"程序

Program and absolute paths 程序的路径和绝对路径

让我们探索一条新的稍微复杂的路径!除了上一级之外,pwn.college 中的 很多关卡的挑战 都在 challenge 目录中,而 challenge 目录又在根目录 (/) 中。因此,目录的访问路径是 /challenge

此关卡中挑战的程序名称为 run,它位于 /challenge 目录中。因此,run 的程序路径是 /challenge/run

此挑战要求您通过调用程序的绝对路径来执行它。您需要执行 challenge 目录中的 run 文件,进而执行 / 目录中的运行文件。如果您正确调用了请求,它将为您提供flag。祝你好运!

查看解析
/challenge/run
通过输入"run"程序的绝对路径调用"run"程序

Position thy self 定位自己

Linux 文件系统有大量的目录和大量的文件。您可以使用 cdchange directory) 命令并将路径作为参数传递给命令,如下所示:

hacker@dojo:~$ cd /some/new/directory
hacker@dojo:/some/new/directory$ cd /some/new/directory

这会影响进程的 “当前工作目录” (在本例中为 bash shell) 。每个进程都有一个当前挂起的目录。其原因将在稍后的模块中阐明。

顺便说一句,现在你可以思考终端中的 ~ 是什么了!这一块显示的是 shell 所在的当前路径。

此挑战将要求您从特定路径执行 /challenge/run 程序(它会告诉您)。在重新运行挑战程序之前,您需要 cd 到该目录。祝你好运!

Bash shell是一种命令行界面和脚本语言,广泛用于Unix和Linux系统。它提供了用户与操作系统交互的方式,可以执行命令、运行脚本以及自动化任务

查看解析
/challenge/run
`回显路径`
cd `回显路径`
/challenge/run
通过"cd `回显路径`"跳转到指定路径执行程序

Position elsewhere 定位其他位置

与上一个挑战一样

Position yet elsewhere 再定位其他位置

与上一个挑战一样,重复题型加深记忆

implicit relative paths, from / 隐式相对路径,从/目录开始

现在,您已经熟悉了引用绝对路径和更改目录的概念。如果你到哪都输入绝对路径调用程序,那么你在哪个目录中真的无关紧要,你可能在前面的三个挑战中发现了这一点。

但是,当前工作目录对于相对路径确实很重要。

  • 相对路径是任何不以根开头的路径(即,它不以 / 开头)。
  • 相对路径英文是 current working directorycwd) 。
  • cwd 是显示当前所在的目录的提示符。

这意味着如何指定特定文件取决于终端提示符所在的位置

想象一下,我们想访问位于 /tmp/a/b/my_file 的某个文件

  • 如果我的 cwd/,那么文件的相对路径是 tmp/a/b/my_file
  • 如果我的 cwd/tmp,则文件的相对路径是 a/b/my_file
  • 如果我的 cwd/tmp/a/b/c,则文件的相对路径是 ../my_file.. 用于引用父目录。

父目录即上层目录

让我们在这里试试吧!您需要使用相对路径运行 /challenge/run,同时具有当前工作目录 /。在这一关中,我给你一个提示。您的相对路径需要以字母 c 开头

查看解析
cd /
challenge/run
为了使相对路径以字母c开头,我们在根目录下调用程序

explicit relative paths, from / 显式相对路径,从/目录开始

之前,你的相对路径是 “naked”:它直接指定了从当前目录进入到的下层目录。在这个关卡中,我们将探索更明确的相对路径。

在大多数操作系统(包括 Linux)中,每个目录都有两个隐式条目,您可以在 paths中引用它们:...

第一个.用于直接引用同一个目录,因此以下绝对路径彼此相同:

  • /challenge
  • /challenge/.
  • /challenge/./././././././././
  • /./././challenge/././

以下相对路径也彼此相同:

  • challenge
  • ./challenge
  • ./././challenge
  • challenge/.

当然,如果你现在的工作目录是 /,那么上面的相对路径相当于上面的绝对路径

做好准备,此挑战需要您在相对路径中使用 .

查看解析
cd /
./challenge/run
为了在相对路径中使用"."开头,我们在根目录下使用"./"调用程序

implicit relative 隐式相对路径

在这个关卡中,我们将练习使用 .更多地引用路径。此挑战需要您从 /challenge 目录运行它。在这里,事情变得有点棘手。

当您提供裸路径时,Linux 明确避免自动查找当前目录。请考虑以下事项:

hacker@dojo:~$ cd /challenge
hacker@dojo:/challenge$ run

不会调用 /challenge/run。这实际上是一种安全措施:如果 Linux 每次进入裸路径时都会在当前目录中搜索程序,你可能会不小心在当前目录中执行恰好与核心系统实用程序同名的程序!因此,上述命令将产生以下错误:

bash: run: command not found

我们稍后将探讨此概念背后的机制,但在此挑战中,将学习如何在此场景中显式使用相对路径来启动 run。执行此操作的方法是告诉 Linux 您明确希望在当前目录中执行一个程序,就像上一关一样。现在就试一试吧!

“裸路径”(naked path)指的是不包含任何目录结构或文件扩展名的路径,仅包含文件名。例如,文件名“example”就是一个裸路径,而“/home/user/example.txt”则不是。

查看解析
cd /challenge
./run
这一关旨在告诉我们在路径下直接输入程序名称不能调用程序,linux的安全机制阻止了

显式相对路径:明确指定了当前目录的相对位置,通常以当前工作目录作为起点。例如,如果当前工作目录是 /home/user,则文件 document.txt 的显式相对路径是 ./document.txt,或者直接用 document.txt 表示。

隐式相对路径:不直接指出当前工作目录,而是依赖于上下文或系统默认的路径。例如,直接使用 document.txt 就是一种隐式相对路径,系统会自动将其解析为当前工作目录下的文件。

home sweet home

每个用户都有一个主目录,通常在文件系统中的 /home 下。在 dojo虚拟机 中,您是 hacker 用户,您的主目录是 /home/hacker。主目录通常是用户存储大多数个人文件的位置。当您浏览 pwn.college 时,您将在主目录存储大部分文件。

通常,您的 shell 会话将以您的主目录作为当前工作目录开始。请考虑初始提示:

hacker@dojo:~$

此提示中的 ~ 是当前工作目录,其中 ~/home/hacker 的简写。Bash 提供并使用这种简写,因为同样,您的大部分时间将花在主目录中。因此,每当 bash 以与 path 一致的方式看到 ~ 作为参数的开头时,它就会将其扩展到您的主目录。考虑:

hacker@dojo:~$ echo LOOK: ~
LOOK: /home/hacker
hacker@dojo:~$ cd /
hacker@dojo:/$ cd ~
hacker@dojo:~$ cd ~/asdf
hacker@dojo:~/asdf$ cd ~/asdf
hacker@dojo:~/asdf$ cd ~
hacker@dojo:~$ cd /home/hacker/asdf
hacker@dojo:~/asdf$

请注意,~ 的扩展是绝对路径,并且只有前导 ~ 被扩展。这意味着,例如,~/~ 将扩展为 /home/hacker/~,而不是 /home/hacker/home/hacker

有趣的事实:cd 将使用你的主目录作为默认目标(就是当你使用cd命令不传入任何参数时默认会跳转到主目录):

hacker@dojo:~$ cd /tmp
hacker@dojo:/tmp$ cd
hacker@dojo:~$

现在轮到您玩了!在此挑战中,/challenge/run 会将flag的副本写入您在命令行上的参数指定的文件,并具有以下条件:

  1. 您的参数必须是绝对路径。
  2. 该路径必须位于您的主目录中。
  3. 在扩展之前,您的参数必须为三个字符或更少。
查看解析
/challenge/run ~/a
按照题目提示"run"程序能够将flag的副本写入参数指定的文件,我们使用"~"代替绝对路径"/home/hacker"

Comprehending Commands 理解命令

cat: not the pet, but the command cat:不是宠物而是命令

最关键的 Linux 命令之一是 catcat 最常用于读出文件,如下所示:

hacker@dojo:~$ cat /challenge/DESCRIPTION.md
One of the most critical Linux commands is `cat`.
`cat` is most often used for reading out files, like so:

如果提供了多个参数,cat 将 concatenate(连接)多个文件。例如:

hacker@dojo:~$ cat myfile
This is my file!
hacker@dojo:~$ cat yourfile
This is your file!
hacker@dojo:~$ cat myfile yourfile
This is my file!
This is your file!
hacker@dojo:~$ cat myfile yourfile myfile
This is my file!
This is your file!
This is my file!

最后,如果你根本没有给出任何参数,cat 将从终端 input (输入)中读取并输出它。我们将在后面的挑战中探讨这一点......

在这个挑战中,我会将flag复制到你的主目录(你的 shell 开始的地方)的flag文件中。使用cat去读吧!

查看解析
cat flag
使用"cat"命令读取当前目录下的"flag"文件

catting absolute paths 使用绝对路径cat读取文件

在上一个关卡中,您执行了 cat flag 以从您的主目录中读取flag!当然,你可以将 cat 的参数指定为绝对路径:

hacker@dojo:~$ cat /challenge/DESCRIPTION.md
In the last level, you did `cat flag` to read the flag out of your home directory!
You can, of course, specify `cat`'s arguments as absolute paths:
...

在此挑战中,我不会将其复制到您的主目录,但会使其可读。你可以在它的绝对路径 /flag 中使用 cat 来读取它。

有趣的事实:/flag 在 pwn.college 的虚拟机中一直存在 ,但与本次挑战不同的是,您通常无法直接访问该文件。

查看解析
cat /flag
使用"cat"命令读取根目录下的"flag"文件

more catting practice 更多cat读取练习

你可以指定各种路径作为命令的参数,我们将使用 cat 进行更多练习。在这个关卡中,我将把flag放在某个疯狂的目录中,我不允许你用 cd 来改变目录,所以别想着用 cat flag。您必须通过绝对路径检索flag,无论它位于何处。

查看解析
cat "flag的绝对路径"
"flag的绝对路径"在打开终端的那一刻给出

grepping for a needle in a haystack 大海捞针

有时,您可能会发现cat的文件太大。幸运的是,我们有 grep 命令来搜索我们需要的内容!我们将在这次挑战中学习。

grep 的方法有很多种,我们将在以下示例中学习:

hacker@dojo:~$ grep SEARCH_STRING /path/to/file

像这样调用,grep 将在文件中搜索包含 SEARCH_STRING 的文本行,并将它们打印到控制台。

在这次挑战中,我在 /challenge/data.txt 文件中放入了 10 万行文本。使用 grep 寻找flag!

提示: flag总是以 pwn.college 开头。

查看解析
grep pwn.college /challenge/data.txt
使用"grep"命令搜索包含“pwn.college”的文本行

listing files 列出文件

到目前为止,我们已经告诉您要与哪些文件进行交互。但是目录里面可以有很多文件(和其他目录),我们不会总告诉你它们的名字。您需要学习使用 ls 命令来 list 它们的内容!

ls 将列出提供给它的所有目录中的文件,如果未提供参数,则列出当前目录中的文件。观察以下示例:

hacker@dojo:~$ ls /challenge
run
hacker@dojo:~$ ls
Desktop    Downloads  Pictures  Templates
Documents  Music      Public    Videos
hacker@dojo:~$ ls /home/hacker
Desktop    Downloads  Pictures  Templates
Documents  Music      Public    Videos
hacker@dojo:~$

在这个挑战中,我们用一些随机名称命名了 /challenge/run!列出 /challenge 中的文件以查找它。

查看解析
ls /challenge
`run程序的新名字`
/challenge/`run程序的新名字`
使用"ls"命令查看"/challenge"目录下的“run”程序的名称并运行

touching files 创建文件

当然,您也可以创建文件!有几种方法可以做到这一点,但我们在这里看一个简单的命令。您可以通过使用 touch 命令触摸来创建新的空白文件:

hacker@dojo:~$ cd /tmp
hacker@dojo:/tmp$ ls
hacker@dojo:/tmp$ touch pwnfile
hacker@dojo:/tmp$ ls
pwnfile
hacker@dojo:/tmp$

就这么简单!在这个关卡中,请创建两个文件:/tmp/pwn/tmp/college,然后运行 /challenge/run 来获取你的flag!

查看解析
touch /tmp/pwn
touch /tmp/college
/challenge/run
使用"touch"命令创建文件

removing files 删除文件

文件就在你身边。就像糖果包装纸一样,它们最终会太多。在这个关卡中,我们将学习清理它们!

在 Linux 中,使用 rm 命令可以删除文件,如下所示:

hacker@dojo:~$ touch PWN
hacker@dojo:~$ touch COLLEGE
hacker@dojo:~$ ls
COLLEGE     PWN
hacker@dojo:~$ rm PWN
hacker@dojo:~$ ls
COLLEGE
hacker@dojo:~$

让我们练习一下。此挑战在您的主目录中创建了一个 delete_me 文件!删除它,然后运行 /challenge/check,这将确保您已删除它,然后为您提供flag!

查看解析
rm delete_me
/challenge/check
使用"rm"命令删除文件

hidden files 隐藏文件

有趣的是,ls 默认情况下不会列出所有文件。Linux 有一个约定,默认情况下,以 .开头的文件不会显示在 ls 和其他一些上下文中。要使用 ls 查看它们,您需要使用 -a flag调用 ls,如下所示:

hacker@dojo:~$ touch pwn
hacker@dojo:~$ touch .college
hacker@dojo:~$ ls
pwn
hacker@dojo:~$ ls -a
.college	pwn
hacker@dojo:~$

现在,轮到你了!找到那个flag,它隐藏在 / 中是一个带点的文件。

查看解析
ls -a /
使用"ls -a"命令查看根目录的隐藏文件

An Epic Filesystem Quest 史诗级的文件系统任务

凭借您对 cdlscat 的了解,我们已经准备好玩一个小游戏了!

我们将从 / 开始。如下所示:

hacker@dojo:~$ cd /
hacker@dojo:/$ ls
bin   challenge  etc   home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  dev        flag  lib   lib64  media   opt  root  sbin  sys  usr

内容真是太多了!总有一天,你会对它们非常熟悉,但你可能已经认出了flag文件和challenge关卡挑战目录。

在这次挑战中,我隐藏了flag!在这里,您将使用 lscat 来跟踪我的线索并找到它!以下是它的工作原理:

  1. 你的第一个线索在 / 中。向那边走。
  2. ls 环顾四周。将会有一个名为 HINT 或 CLUE 或类似名称的文件!
  3. cat那个文件来读线索!
  4. 根据线索所说的内容,前往下一个目录(或者不要!
  5. 循线索到flag!

祝你好运!

查看解析
灵活运用"cd""ls""cat"三条指令即可< /challenge/read_me

making directories 创建目录

我们可以创建文件。目录可以创建吗?你可以使用mkdir命令来创建目录,然后你就可以把文件贴进去了!

这里给出实例:

hacker@dojo:~$ cd /tmp
hacker@dojo:/tmp$ ls
hacker@dojo:/tmp$ ls
hacker@dojo:/tmp$ mkdir my_directory
hacker@dojo:/tmp$ ls
my_directory
hacker@dojo:/tmp$ cd my_directory
hacker@dojo:/tmp/my_directory$ touch my_file
hacker@dojo:/tmp/my_directory$ ls
my_file
hacker@dojo:/tmp/my_directory$ ls /tmp/my_directory/my_file
/tmp/my_directory/my_file
hacker@dojo:/tmp/my_directory$

现在创建一个 /tmp/pwn 目录并在其中创建名为college的文件!然后运行 /challenge/run,它将检查您的答案并为您提供flag!

查看解析
mkdir /tmp/pwn
touch /tmp/pwn/college
/challenge/run

finding files 查找文件

现在我们知道如何列出、读取和创建文件了。但是我们如何查找它们呢?我们使用 find 命令!

find 命令采用描述搜索条件和搜索位置的可选参数。如果未指定搜索条件,则 find 将匹配每个文件。如果未指定搜索位置,则 find 将使用当前工作目录 (.)。例如:

hacker@dojo:~$ mkdir my_directory
hacker@dojo:~$ mkdir my_directory/my_subdirectory
hacker@dojo:~$ touch my_directory/my_file
hacker@dojo:~$ touch my_directory/my_subdirectory/my_subfile
hacker@dojo:~$ find
.
./my_directory
./my_directory/my_subdirectory
./my_directory/my_subdirectory/my_subfile
./my_directory/my_file
hacker@dojo:~$

指定搜索位置时:

hacker@dojo:~$ find my_directory/my_subdirectory
my_directory/my_subdirectory
my_directory/my_subdirectory/my_subfile
hacker@dojo:~$

当然,我们可以指定标准!例如,在这里我们使用-name参数按名称进行筛选:

hacker@dojo:~$ find -name my_subfile
./my_directory/my_subdirectory/my_subfile
hacker@dojo:~$ find -name my_subdirectory
./my_directory/my_subdirectory
hacker@dojo:~$

如果你愿意,你可以在整个文件系统中搜索!

hacker@dojo:~$ find / -name hacker
/home/hacker
hacker@dojo:~$

现在轮到你了。我已将flag隐藏在文件系统上的随机目录中。它仍然被称为 flag。快去找吧!

几个笔记:首先,文件系统上还有其他名为 flag 的文件。如果您尝试的第一个没有实际的flag,请不要惊慌。其次,文件系统中有很多地方是普通用户无法访问的。这些将导致 find 生成错误,但您可以忽略这些错误;我们不会把flag藏在那里!最后,find可能需要一段时间;请耐心等待!

查看解析
find / -name flag
使用"find"命令查找整个文件系统中名为"flag"的文件

linking flag 链接文件

如果您使用 Linux(或计算机)进行任何合理的时间来执行任何实际工作,您最终可能会遇到以下情况:您希望两个程序访问相同的数据,但程序希望该数据位于两个不同的位置。 幸运的是,Linux 为这个困境提供了一个解决方案:链接

链接有两种类型:链接和(也称为符号)链接。 我们将通过一个比喻来区分两者:

链接是指您使用多个地址来称呼您的公寓,这些地址都直接指向同一个地方(例如,岭南1栋南雅1栋是同一栋楼)。

链接是指您移动公寓并修改快递地址,快递公司自动将您的快递从旧地方转发到新地方。

在文件系统中,从概念上讲,文件是该文件内容所在的地址。 硬链接是一个备用地址,它索引该数据---对硬链接的访问和对原始文件的访问是完全相同的,因为它们会立即产生必要的数据。 而软/符号链接则包含原始文件名。 当您访问符号链接时,Linux 将意识到它是一个符号链接,读取原始文件名,然后(通常)自动访问该文件。 在大多数情况下,这两种情况都会导致访问原始数据,但机制不同。

硬链接对大多数人来说听起来更简单(例如,我在上面的一句话中解释了它,而软链接则有两句),但它们有各种缺点和实现问题,这使得软/符号链接成为迄今为止更流行的选择。

在这个挑战中,我们将学习符号链接(也就是软链接)。 符号链接是使用带有 -s 参数的 ln 命令创建的,如下所示:

hacker@dojo:~$ cat /tmp/myfile
This is my file!
hacker@dojo:~$ ln -s /tmp/myfile /home/hacker/ourfile
hacker@dojo:~$ cat ~/ourfile
This is my file!
hacker@dojo:~$

你可以看到,访问符号链接会导致获取原始文件内容! 此外,您还可以查看 ln -s 的用法。 请注意,原始文件路径位于命令中的链接路径之前

可以通过几种方法识别符号链接。 例如,file 命令(它接受文件名并告诉你它是什么类型的文件)将识别符号链接:

hacker@dojo:~$ file /tmp/myfile
/tmp/myfile: ASCII text
hacker@dojo:~$ file ~/ourfile
/home/hacker/ourfile: symbolic link to /tmp/myfile
hacker@dojo:~$

好了,现在你试试吧! 在这个关卡中,flag一如既往地在 /flag 中,但 /challenge/catflag 程序将读取 /home/hacker/not-the-flag文件。 使用符号链接,并欺骗它给你flag!

文件A -----> 数据块X

硬链接1 ---> 数据块X
硬链接2 ---> 数据块X

软链接1 -----> 文件A

查看解析
ln -s /flag /home/hacker/not-the-flag 
/challenge/catflag
使用"ln -s"命令将"/flag"与"/home/hacker/not-the-flag"进行软链接,这样当"/challenge/catflag"程序读取"/home/hacker/not-the-flag"文件时会被链接读取到"/flag"文件

Digesting Documentation 摘要文档

Learning From Documentation 从文档中学习

我们使用文档只是想要弄清楚如何使用所有这些程序,其中一个具体的例子就是弄清楚在命令行上指定什么参数。本模块将主要深入研究这个概念,作为了解如何一般使用这些程序的代理。在本模块的其余部分中,您将了解向环境寻求程序帮助的各种方法,但首先,我们将深入了解阅读文档的概念。

程序的正确使用在很大程度上取决于对它们的参数的正确规范。回想一下基本命令模块的隐藏文件查询中指令 ls -a-a

-a 是一个参数,它告诉 ls 列出隐藏文件和非隐藏文件。因为我们想要列出隐藏的文件,所以在我们的场景中使用 ls-a 参数是正确的使用它的方法。

此挑战的程序是 /challenge/challenge,您需要正确调用它才能为您提供flag。让我们假设这是它的文档:

Welcome to the documentation for `/challenge/challenge`! To properly run this program, you will need to pass it the argument of `--giveflag`. Good luck!
欢迎使用 /challenge/challenge 的文档!要正确运行此程序,您需要向其传递 --giveflag 的参数。祝你好运!

有了这些知识,就去获取这题的flag吧!

查看解析
/challenge/challenge --giveflag
我们通过题目给出的提示文档得知我们需要给"challenge"程序传入"--giveflag"的参数

Learning Complex Usage 学习复杂用法

虽然使用大多数命令很简单,但某些命令的使用可能会变得相当复杂。例如,像 sedawk 这样的命令的参数(我们现在先不讨论这些)是用深奥的编程语言编写的整个程序!在 cdawk 之间的某些地方是将参数转换为其参数的命令......

这听起来很疯狂,但您已经在 基本命令 中的 find 关卡遇到过这种情况。find 有一个 -name 参数,而 -name 参数本身需要一个参数,指定要搜索的名称。许多其他命令都是类似的。

以下是 /challenge/challenge 的本层级文档:

Welcome to the documentation for /challenge/challenge! This program allows you to print arbitrary files to the terminal, when given the --printfile argument. The argument to the --printfile argument is the path of the flag to read. For example, /challenge/challenge --printfile /challenge/DESCRIPTION.md will print out the description of the level!

欢迎使用 /challenge/challenge 的文档!当给定 --printfile 参数时,该程序允许您将任意文件打印到终端。--printfile 参数的参数是要读取的flag的路径。例如, /challenge/challenge --printfile /challenge/DESCRIPTION.md 将打印出关卡的描述!

有了这个文档,就去获取flag吧!

查看解析
/challenge/challenge --printfile /flag
按照文档指示使用"challenge"程序读取"/flag"

Reading Manuals 阅读手册

此关卡介绍了 man 命令。manmanual 的缩写,它将显示(如果可用的话)您作为参数传递的命令的手册。例如,假设我们想了解 yes 命令(是的yes是一个真正的命令,不信你试试):

hacker@dojo:~$ man yes

这将显示 yes 的手册页,如下所示:

YES(1)                           User Commands                          YES(1)

NAME
       yes - output a string repeatedly until killed

SYNOPSIS
       yes [STRING]...
       yes OPTION

DESCRIPTION
       Repeatedly output a line with all specified STRING(s), or 'y'.

       --help display this help and exit

       --version
              output version information and exit

AUTHOR
       Written by David MacKenzie.

REPORTING BUGS
       GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
       Report any translation bugs to <https://translationproject.org/team/>

COPYRIGHT
       Copyright  ©  2020  Free Software Foundation, Inc.  License GPLv3+: GNU
       GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
       This is free software: you are free  to  change  and  redistribute  it.
       There is NO WARRANTY, to the extent permitted by law.

SEE ALSO
       Full documentation <https://www.gnu.org/software/coreutils/yes>
       or available locally via: info '(coreutils) yes invocation'

GNU coreutils 8.32               February 2022                          YES(1)

重要的部分包括:

NAME(1)                           CATEGORY                          NAME(1)

NAME
	This gives the name (and short description) of the command or
	concept discussed by the page.

SYNOPSIS
	This gives a short usage synopsis. These synopses have a standard
	format. Typically, each line is a different valid invocation of the
	command, and the lines can be read as:

	COMMAND [OPTIONAL_ARGUMENT] SINGLE_MANDATORY_ARGUMENT
	COMMAND [OPTIONAL_ARGUMENT] MULTIPLE_ARGUMENTS...

DESCRIPTION
	Details of the command or concept, with detailed descriptions
	of the various options.

SEE ALSO
	Other man pages or online resources that might be useful.

COLLECTION                        DATE                          NAME(1)

您可以使用箭头键和 PgUp/PgDn 在手册页中滚动。阅读完手册页后,可以按 q 退出。

手册页存储在集中式数据库中。如果您好奇,这个数据库位于 /usr/share/man 目录中,但您永远不需要直接与它交互:您只需使用 man 命令查询它。man 命令的参数不是文件路径,而只是条目本身的名称(例如,您运行 man yes 来查找 yes 手册页,而不是 man /usr/bin/yes,这将是 yes 程序的实际路径,但会导致 man 显示垃圾)。

此关卡的挑战有一个秘密选项,当您使用它时,将导致挑战打印flag。您必须通过 challenge 的手册页来了解此选项

查看解析
man /challenge/challenge
我们通过"man"命令查看challenge"程序的使用手册

Searching Manuals 搜索手册

您可以使用箭头键(和 PgUp/PgDn)滚动手册页,并使用 / 进行搜索。搜索后,您可以按 n 转到下一个结果,按 N 转到上一个结果。你可以使用 ?来向后搜索!

通过阅读 challenge 的使用手册找到为您提供flag的选项

查看解析
man /challenge/challenge
我们通过"man"命令查看"challenge"程序的使用手册

Searching For Manuals 搜索“搜索”的使用手册

这个关卡很棘手:它通过随机化其名称来隐藏挑战的手册页。幸运的是,所有的手册页都收集在一个可搜索的数据库中,因此您将能够搜索手册页数据库以找到隐藏的挑战手册页!要了解如何搜索正确的手册页,请通过执行以下操作阅读手册页:man man

提示 1:man man 教你 man 命令本身的高级用法,你必须利用这些知识来弄清楚如何搜索隐藏的 manpage,它会告诉你如何使用 /challenge/challenge

提示 2:虽然手册页是随机命名的,但您实际上仍然使用 /challenge/challenge 来获取flag!

查看解析
man -K /challenge/challenge
我们通过"man -K"命令搜索手册页中包含“/challenge/challenge”这个字符串的所有条目(因为权限问题难以直接读取"challenge"程序的使用手册)

Helpful Programs 有帮助的程序

有些程序没有手册页,但如果使用特殊参数调用,可能会告诉您如何运行它们。通常,此参数是 --help,但通常可以是 -h,或者在极少数情况下是 -?help 或其他深奥的值,如 /?(尽管后者在 Windows 上更常见)。

在这个关卡中,你将练习使用 --help 阅读程序的文档。试试看!

查看解析
/challenge/challenge --help

Help for Builtins 内置软件的帮助功能

某些命令(不是带有手册页和帮助选项的程序)内置在 shell 本身中。这些称为 builtin。内置函数的调用方式与命令类似,但 shell 在内部处理它们,而不是启动其他程序。你可以通过运行内置帮助来获取 shell 内置函数的列表,如下所示:

hacker@dojo:~$ help

您可以通过将特定帮助传递给内置 help 来获得该帮助。让我们看看我们之前已经使用过的 builtin,cd

hacker@dojo:~$ help cd
cd: cd [-L|[-P [-e]] [-@]] [dir]
    Change the shell working directory.
    
    Change the current directory to DIR.  The default DIR is the value of the
    HOME shell variable.
...

这有一些好信息!在这个挑战中,我们将练习使用 help 来查找内置函数的帮助。此挑战的 challenge 命令是内置的 shell,而不是程序。和以前一样,你需要查找它的帮助以找出要传递给它的 secret 值!

查看解析
help challenge

File Globbing 文件通配

Matching with * 与*匹配

我们将学习的第一个通配符是 *。当它在任何参数中遇到 * 字符时,shell 会将其视为 “通配符” 并尝试用任何与模式匹配的文件替换该参数。展示一个示例比解释更容易:

hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a	file_b	file_c
hacker@dojo:~$ echo Look: file_*
Look: file_a file_b file_c

当然,尽管在这种情况下,glob 导致了多个参数,但它也可以简单地只匹配一个。例如:

hacker@dojo:~$ touch file_a
hacker@dojo:~$ ls
file_a
hacker@dojo:~$ echo Look: file_*
Look: file_a

当匹配到零个文件时,默认情况下,shell 会保持 glob 不变:

hacker@dojo:~$ touch file_a
hacker@dojo:~$ ls
file_a
hacker@dojo:~$ echo Look: nope_*
Look: nope_*

* 匹配文件名中除 / 或前导 . 字符之外的任何部分(也就是说不能像这样匹配:*flag->/flag*flag->.flag)。例如:

hacker@dojo:~$ echo ONE: /ho*/*ck*
ONE: /home/hacker
hacker@dojo:~$ echo TWO: /*/hacker
TWO: /home/hacker
hacker@dojo:~$ echo THREE: ../*
THREE: ../hacker

现在,自己练习吧!从你的主目录开始,将你的目录改为 /challenge,请使用通配符将你传递给 cd 的参数在四个字符以内!达成条件后,运行 /challenge/run 以获取flag!

查看解析
cd /ch*
./run
我们使用通配符"*"将"/ch*"匹配为"/challenge"(以"ch"开头的文件是独一无二的"challenge",不能是其他的)

Matching with ? 与?匹配

接下来,让我们了解 ?。当它在任何参数中遇到 ?字符时,shell 会将其视为单字符通配符。这与 * 类似,但只匹配一个字符。例如:

hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_cc
hacker@dojo:~$ ls
file_a	file_b	file_cc
hacker@dojo:~$ echo Look: file_?
Look: file_a file_b
hacker@dojo:~$ echo Look: file_??
Look: file_cc

现在,自己练习吧!从您的主目录开始,将您的目录更改为 /challenge,但在 cd 的参数中使用 ?字符来替代 cl!达成条件后,运行 /challenge/run 以获取flag!

查看解析
cd /?ha??enge
./run
我们使用通配符"?"将"/?ha??enge"匹配为"/challenge"

Matching with [] 与[]匹配

接下来,我们将介绍 []。方括号实质上是 ?的有限形式,因为 [] 不是匹配任何字符,而是在方括号内指定的某些潜在字符子集的通配符。例如,[pwn] 将匹配字符 pwn。例如:

hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a	file_b	file_c
hacker@dojo:~$ echo Look: file_[ab]
Look: file_a file_b

在这里试试吧!我们在 /challenge/files 中放置了一堆文件。将工作目录更改为 /challenge/files,并使用一个参数运行 /challenge/run,使用[]file_bfile_afile_sfile_h 作为参数输入!

查看解析
cd /challenge/files
../run file_[bash]
我们使用通配符"[]"将"file_[bash]"匹配为`file_b`、`file_a`、`file_s`、`file_h`四个文件

Matching paths with [] 使用[]匹配路径

通配是基于路径发生的,因此你可以使用通配参数扩展整个路径。例如:

hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a	file_b	file_c
hacker@dojo:~$ echo Look: /home/hacker/file_[ab]
Look: /home/hacker/file_a /home/hacker/file_b

现在轮到你了。我们再次在 /challenge/files 中放置了一堆文件。从您的主目录开始,使用单个参数运行 /challenge/run,该参数将 file_bfile_afile_sfile_h 文件的绝对路径括起来!

查看解析
/challenge/run /challenge/files/file_[bash]
我们使用通配符"[]"将"file_[bash]"匹配为`file_b`、`file_a`、`file_s`、`file_h`四个文件

Mixing globs 混合globs

现在,让我们把前面的关卡放在一起吧!我们在 /challenge/files 中放置了一些 Happy 但名称不同的文件。去 cd 那里,使用你学到的 globing,编写一个简短的(6 个字符或更少)的 glob,它将匹配 “challing”、“academical” 和 “pwning” 文件!

查看解析
cd /challenge/files
../run  [cap]*
我们使用通配符"[]"和"*"将"[cap]*"匹配为`challing`、`academical`、`pwning`四个文件

Exclusionary globbing 排他性通配

有时,您想过滤掉 glob 中的文件!幸运的是,[] 可以帮助你做到这一点。如果括号中的第一个字符是 或着^^用于较新版本的 bash 中),则 glob 将反转,并且该括号实例匹配列出的字符。例如:

hacker@dojo:~$ touch file_a
hacker@dojo:~$ touch file_b
hacker@dojo:~$ touch file_c
hacker@dojo:~$ ls
file_a	file_b	file_c
hacker@dojo:~$ echo Look: file_[!ab]
Look: file_c
hacker@dojo:~$ echo Look: file_[^ab]
Look: file_c
hacker@dojo:~$ echo Look: file_[ab]
Look: file_a file_b

有了这些知识,就转到 /challenge/files 并对所有不以 pwn 开头的文件运行 /challenge/run

注意:字符不是 [] glob 的第一个字符时,它在 bash 中具有不同的特殊含义,因此如果事情不再有意义,请记住这一点!^ 没有这个问题,但也不兼容旧的 shell

查看解析
cd /challenge/files
../run  [!pwn]*
我们使用通配符"[!]"和"*"将"[!pwn]*"匹配为开头不为`p`、`w`、`n`的文件

Practicing Piping 练习管道

Redirecting output 重定向输出

首先,让我们看看将 stdout 重定向到文件。您可以使用 > 字符完成此操作,如下所示:

hacker@dojo:~$ echo hi > asdf

这会将 echo hi 的输出(即 hi)重定向到文件 asdf。然后,你可以使用 cat 等程序输出此文件:

hacker@dojo:~$ cat asdf
hi

在此挑战中,您必须使用此输入重定向将单词 PWN(全部大写)写入文件名 COLLEGE(全部大写)

查看解析
echo PWN > COLLEGE
我们使用"echo"将"PWN"作为输出流,并使用">"将输出流写入"COLLEGE"文件中

stdout 是标准输出流(Standard Output)的缩写,我们将它视为终端的输出回显即可

Redirecting more output 重定向更多输出

除了重定向 echo 的输出之外,您当然还可以重定向任何命令的输出(比如printcat)。在这个关卡中,/challenge/run 将再次给你一个flag,但前提是你将其输出重定向到文件 myflag中。当然,您的flag最终会重定向出现在 myflag 文件中!

你会注意到尽管你重定向了 stdout ,/challenge/run 仍然会有输出打印到你的终端。那是因为它通过标准错误(stderr)来传达其指令和反馈,并且只在stdout上打印flag!

stderr 是标准错误流(Standard Error)的缩写,用于输出错误消息或诊断信息。

查看解析
/challenge/run > myflag
cat myflag
我们使用">"将"/challenge/run"输出流写入"COLLEGE"文件中

image-20241020163401388

Appending output 附加输出

输出重定向的一个常见用例是保存一些命令结果以供以后分析。通常,您希望汇总执行此操作:运行一堆命令,保存其输出,并在以后 grep 完成它。在这种情况下,您可能希望所有输出都继续附加到同一个文件,但 > 每次都会创建一个新的输出文件,并删除旧内容。

您可以使用 >> 而不是 >附加模式下重定向输入,如下所示:

hacker@dojo:~$ echo pwn > outfile
hacker@dojo:~$ echo college >> outfile
hacker@dojo:~$ cat outfile
pwn
college
hacker@dojo:$

练习一下,运行challenge/run时,将输出以附加模式重定向到文件/home/hacker/the-flag。这种做法将把flag的前半部分写入文件,如果将标准输出重定向到文件,则将后半部分写入标准输出。如果您以追加模式正确地重定向,则后半部分将追加到第一部分,但如果您以截断模式(>)重定向,则后半部分将覆盖第一部分,并且您将无法获得flag!(此时请重启靶机

现在开始吧!

查看解析
/challenge/run >> the-flag
cat the-flag
我们使用">>"将"/challenge/run"输出流附加写入"the-flag"文件中

Redirecting errors 重定向错误

就像标准输出一样,您也可以重定向命令的错误通道。在这里,我们将学习文件描述符编号。文件描述符(FD)是Linux中描述通信通道的数字。你已经在使用它们了,尽管你没有意识到。我们已经熟悉了三个:

  • FD 0: Standard Input 标准输入
  • FD 1: Standard Output 标准输出
  • FD 2: Standard Error 标准误差

当您重定向进程通信时,您可以通过 FD 编号来执行此操作,尽管某些 FD 编号是隐式的。例如,没有数字的 > 表示 1>,这会重定向 FD 1(标准输出)。因此,以下两个命令是等效的:

hacker@dojo:~$ echo hi > asdf
hacker@dojo:~$ echo hi 1> asdf

从这一点开始,重定向错误非常容易。如果你有一个命令可能通过标准错误(比如 /challenge/run)生成数据,你可以这样做:

hacker@dojo:~$ /challenge/run 2> errors.log

这会将标准错误 (FD 2) 重定向到 errors.log 文件。此外,您可以同时重定向多个文件描述符!例如:

hacker@dojo:~$ some_command > output.log 2> errors.log

该命令会将输出重定向到 output.log 并将错误重定向到 errors.log

让我们把它付诸实践吧!在这个挑战中,你需要像之前的关卡一样,首先将 /challenge/run 的输出重定向到 myflag

然后将 “errors”(即标准错误输出)重定向到 instructions。您会注意到不会将任何内容打印到终端,因为您已经重定向了所有内容!当您成功完成此操作时,您可以在instructions中找到说明/反馈,并在 myflag 中找到flag!

查看解析
/challenge/run > myflag 2> instructions
cat instructions
cat myflag
我们使用"2>"将标准错误输出流写入"instructions"文件中

Redirecting input 重定向输入

就像您可以重定向程序的输出一样,您也可以将输入重定向到程序!这是使用 < 完成的,如下所示:

hacker@dojo:~$ echo yo > message
hacker@dojo:~$ cat message
yo
hacker@dojo:~$ rev < message
oy

您可以使用输入重定向在许多不同的程序中做有趣的事情!在这个关卡中,我们将练习使用 /challenge/run,这将需要您将 PWN 文件重定向到它,并让 PWN 文件包含值 COLLEGE!要将该值写入 PWN 文件,请回想一下之前对 echo 的输出重定向的挑战!

查看解析
echo PWN > COLLEGE
/challenge/run < PWN
我们使用"<"将文件"PWN"作为输入流

Grepping stored results 对存储结果进行grep

您知道如何运行命令,如何重定向其输出(例如 >),以及如何搜索结果文件(例如 grep)。让我们把这个放在一起吧!

在这个更复杂的关卡时,我们希望您:

  1. /challenge/run 的输出重定向到 /tmp/data.txt
  2. 这将产生 10 万行文本,其中之一是 /tmp/data.txt 中的flag。
  3. 使用grep得到flag!
查看解析
/challenge/run > /tmp/data.txt
grep pwn.college /tmp/data.txt

Grepping live output grep实时输出

事实证明,您可以 “省去中间人”,避免将结果存储到文件中的需要,就像您在上一关中所做的那样。您可以使用 |(管道符)运算符来使用它。管道左侧命令的标准输出将连接到管道右侧的命令的标准输入端(通过管道连接到该管道)。例如:

hacker@dojo:~$ echo no-no | grep yes
hacker@dojo:~$ echo yes-yes | grep yes
yes-yes
hacker@dojo:~$ echo yes-yes | grep no
hacker@dojo:~$ echo no-no | grep no
no-no

现在自己试试吧!/challenge/run 将输出 10 万行文本,包括flag。用 Grep 找出flag!

查看解析
/challenge/run | grep pwn.college

image-20241020183031498

Grepping errors grep错误

您知道如何将错误输出重定向到文件,并且知道如何通过管道将输出传输到另一个程序。但是,如果您想直接 grep 错误输出怎么办?

> 运算符将给定的文件描述符重定向到文件,并且您使用了 2> 重定向 fd 2,这是标准错误。管道符 | 仅将标准输出重定向到另一个程序,并且不存在管道符的 2|形式!它只能重定向标准输出(FD 1)。

shell 有一个 >& 运算符,它将一个文件描述符重定向到另一个文件描述符。这意味着我们可以有一个两步过程来grep修复错误:首先,我们将标准错误重定向到标准输出(2>&1),然后将现在组合的stderr和stdout作为正常管道(|)!

现在就试试吧!与上一关一样,此关卡将用输出为难您,但这次是标准错误输出。解决它并找到flag!

查看解析
/challenge/run 2>&1 | grep pwn.college

image-20241020184751573

Duplicating piped data with tee 使用tee复制管道数据

当您将数据从一个命令传递到另一个命令时,您当然不会再在屏幕上看到它。这并不总是需要的:例如,您可能希望查看数据在命令之间流动时的数据,以调试意外结果(例如,“为什么第二个命令不起作用???”)。

幸运的是,有一个解决方案!tee 命令以管道中的“T 型分离器”命名,它将流经管道的数据复制到命令行上提供的任意数量的文件中。例如:

hacker@dojo:~$ echo hi | tee pwn college
hi
hacker@dojo:~$ cat pwn
hi
hacker@dojo:~$ cat college
hi
hacker@dojo:~$

如您所见,通过向 tee 提供两个文件,我们最终得到了三个管道传入数据的副本:一个到 stdout,一个到 pwn 文件,一个到 college 文件。您可以想象如何使用它来调试事情变得混乱:

hacker@dojo:~$ command_1 | command_2
Command 2 failed!
hacker@dojo:~$ command_1 | tee cmd1_output | command_2
Command 2 failed!
hacker@dojo:~$ cat cmd1_output
Command 1 failed: must pass --succeed!
hacker@dojo:~$ command_1 --succeed | command_2
Commands succeeded!

image-20241020190021882

现在,你试试吧!在这关中 /challenge/pwn 必须通过管道传输到 /challenge/college,但你需要拦截数据才能看到 pwn 需要你做什么!

查看解析
/challenge/pwn | tee output | /challenge/college
cat output
通过使用"tee"将"pwn"程序的输出流复制到"output"

Writing to multiple programs 写入多个程序

好的,现在我们明白了我们可以用 tee 将数据复制到两个文件:

hacker@dojo:~$ echo HACK | tee THE > PLANET
hacker@dojo:~$ cat THE
HACK
hacker@dojo:~$ cat PLANET
HACK
hacker@dojo:~$

您已经使用 tee 将数据复制到文件和命令中:

hacker@dojo:~$ echo HACK | tee THE | cat
HACK
hacker@dojo:~$ cat THE
HACK
hacker@dojo:~$

但是复制到两个命令呢? 正如 tee 在其手册页中所说,它被设计为写入文件和标准输出:

TEE(1)                           User Commands                          TEE(1)

NAME
       tee - read from standard input and write to standard output and files

Luckily, Linux follows the philosophy that "everything is a file". This is, the system strives to provide file-like access to most resources, including the input and output of running programs! The shell follows this philosophy, allowing you to, for example, use any utility that takes file arguments on the command line (such as tee) and hook it up to the input or output side of a program!
幸运的是,Linux 遵循“一切都是文件”的理念。 也就是说,系统努力提供对大多数资源的类似文件的访问,包括正在运行的程序的输入和输出! shell 遵循这一理念,例如,允许您使用任何在命令行上获取文件参数的实用程序(例如 tee)并将其挂接到程序的输入端或输出端!

这是使用所谓的 进程替换 完成的。 如果你写一个 >(rev) 的参数,bash 将运行 rev 命令(rev这个命令从标准输入中读取数据,逆序,并将其写入标准输出!),但将其输入挂接到它将创建的临时文件。 当然,这不是一个真正的文件,它是所谓的命名管道,因为它有一个文件名:

hacker@dojo:~$ echo >(rev)
/dev/fd/63
hacker@dojo:~$

/dev/fd/63 从何而来? bash>(rev) 替换为与 rev 的输入挂钩的命名管道文件的路径! 当命令正在运行时,写入此文件会将数据通过管道传输到命令的标准输入。 通常,这是使用将输出文件作为参数的命令(如 tee)完成的:

hacker@dojo:~$ echo HACK | rev
KCAH
hacker@dojo:~$ echo HACK | tee >(rev)
HACK
KCAH

在上面,发生了以下事件序列:

  1. bash 启动了 rev 命令,将命名管道(可能是 /dev/fd/63,我们可以使用命令echo >(rev)看看命名管道)挂接到 rev 的标准输入
  2. bash 启动了 tee 命令,将管道挂接到其标准输入,并将 tee 的第一个参数替换为 /dev/fd/63tee 甚至从未看到过参数 >(rev);Shell 在推出 tee之前替换了
  3. bash 使用 echo 内置函数将 HACK 打印到 tee 的标准输入中
  4. tee 读取 HACK,将其写入标准输出,然后将其写入 /dev/fd/63(连接到 rev 的 stdin管道)
  5. rev 从其标准输入中读取 HACK,将其反转,并将 KCAH 写入标准输出

image-20241020195346858

个人理解是将输出流写入文件是直接使用>,而使用>()是将输出流导到下一个程序输入流的管道中

stdin 是标准输入流(Standard Input)的缩写,通常用于程序接收输入数据。

现在轮到你了! 在这个挑战中,我们有 /challenge/hack/challenge/the/challenge/planet。 运行 /challenge/hack 命令,并将其输出复制为 /challenge/the/challenge/planet 命令的输入!


补充!

细心的学习者会意识到以下内容是等效的:

hacker@dojo:~$ echo hi | rev
ih
hacker@dojo:~$ echo hi > >(rev)
ih
hacker@dojo:~$

管道数据的方法不止一种! 当然,第二条路线更难阅读,也更难扩展。 例如:

hacker@dojo:~$ echo hi | rev | rev
hi
hacker@dojo:~$ echo hi > >(rev | rev)
hi
hacker@dojo:~$

那太愚蠢了!这里的教训是,虽然过程替代是工具箱中一个强大的工具,但它是一个非常专业的工具;不要什么都用它!

查看解析
/challenge/hack | tee >(/challenge/the) >(/challenge/planet)
通过使用"tee"将"pwn"程序的输出流复制到"output"

Split-piping stderr and stdout 拆分管道stderr和stdout

现在,让我们把你的知识放在一起。您必须掌握最终的管道任务:将 stdout 重定向到一个程序,将 stderr 重定向到另一个程序。

当然,这里的挑战在于 | 运算符将左侧命令的 stdout 与右侧命令的 stdin 链接起来。当然,您已经使用 2>&1 将 stderr 重定向到 stdout,因此,管道 stderr 重叠,但这会混合 stderr 和 stdout。如何保持不混合?

您需要结合您对 >(),2>,|的知识和理解,完成我给你留下的任务。

在本次挑战中,给出以下提示:

  • /challenge/hack:该程序会在 stdoutstderr 上生成数据
  • /challenge/the: 您必须将 Hackstderr 重定向到此程序
  • /challenge/planet: 您必须将 Hackstdout 重定向到此程序

Go get the flag! 去拿flag吧!

查看解析
/challenge/hack > >(/challenge/planet) 2> >(/challenge/the)
这里试着解释一下为什么
/challenge/hack >(/challenge/planet) 2>(/challenge/the)
不行
使用 `>(command)` 时,它会创建一个可用于重定向的文件描述符,而不是用作参数
`>`用于提取出输出流,`>()`用于指定程序输入流的管道

image-20241020204553520

Shell Variables Shell 变量

Printing Variables 打印变量

让我们从打印变量开始。这次/challenge/run 程序不会也不能给你flag,但这没关系,因为这个flag已经被放到名为 “FLAG” 的变量中了!就让你的shell打印出来吧!

您可以使用多种方法完成此操作,但我们将从 echo 开始。此命令仅打印内容。例如:

hacker@dojo:~$ echo Hello Hackers!
Hello Hackers!

你也可以通过在变量名称前加上 $ 来打印出带有 echo 的变量。例如,有一个变量 PWD,它始终保存当前 shell 的当前工作目录。您可以按如下方式打印出来:

hacker@dojo:~$ echo $PWD
/home/hacker

现在轮到你了。让您的 shell 打印出 FLAG 变量并解决此挑战!

查看解析
echo $FLAG
我们通过"$"符来指定变量

Setting Variables 设置变量

当然,除了读取存储在变量中的值外,您还可以将值写入变量。与许多其他语言一样,这是使用 = 完成的。要将变量 VAR 设置为值 1337,您可以使用:

hacker@dojo:~$ VAR=1337

请注意=的使用!如果你加上空格(例如,VAR = 1337),shell 将无法识别变量赋值,而是尝试运行 VAR 命令(不存在)

还要注意,这使用 VAR 而不是 $VAR$ 仅用于访问变量。在 shell 术语中,这个 $ 的前缀会触发所谓的变量扩展,并且令人惊讶地,它是许多潜在漏洞的来源(如果您对此感兴趣,请在熟悉命令行后查看 Art of the Shell 道场(pwn.college)!

设置变量后,您可以使用之前学到的技术访问它们,例如:

hacker@dojo:~$ echo $VAR
1337

要解决此关卡问题,必须将 PWN 变量设置为值 COLLEGE。注意:变量的名称和值都区分大小写!PWNpwn 不同,COLLEGECollege 不同

查看解析
PWN=COLLEGE
我们通过"="符来设置变量

Multi-word Variables 多字变量

在这个关卡,您将学习报价。空格在 shell 中具有特殊意义,有些地方你不能随意使用它们。回想一下我们的变量设置:

hacker@dojo:~$ VAR=1337

这会将 VAR 变量设置为 1337,但如果要将其设置为 1337 SAUCE,该怎么办?您可以尝试以下操作:

hacker@dojo:~$ VAR=1337 SAUCE

这看起来很合理,但它不起作用,原因与需要在 = 周围没有空格的原因类似。当 shell 看到空格时,它会结束变量赋值并将下一个单词(在本例中为 SAUCE)解释为命令。要将 VAR 设置为 1337 SAUCE,您需要引用它:

hacker@dojo:~$ VAR="1337 SAUCE"

在这里,shell 将 1337 SAUCE 读取为单个标记,并愉快地将该值设置为 VAR。在此关卡中,您需要将变量 PWN 设置为 COLLEGE YEAH。祝你好运!

查看解析
PWN="COLLEGE YEAH"

Exporting Variables 导出变量

默认情况下,您在 shell 会话中设置的变量是该 shell 进程的本地变量。也就是说,您运行的其他命令不会继承它们。您可以通过简单地在自己的 shell 中调用另一个 shell 进程来对此进行试验,如下所示:

hacker@dojo:~$ VAR=1337
hacker@dojo:~$ echo "VAR is: $VAR"
VAR is: 1337
hacker@dojo:~$ sh
$ echo "VAR is: $VAR"
VAR is: 

在上面的输出中,$ 提示符是 sh 的提示符,sh 是作为主 shell 进程的进程调用的最小 shell 实现。而且它不会接收 VAR 变量!

这当然是有道理的。你的 shell 变量可能包含敏感或奇怪的数据,除非它明确应该泄露给你运行的其他程序,否则你不会希望它泄露给你运行的其他程序的。你应该怎么标记它呢?您导出变量。导出变量时,它们将传递到子进程的环境变量中。您将在其他挑战中遇到环境变量的概念,但您将在此处观察它们的效果。下面是一个示例:

hacker@dojo:~$ VAR=1337
hacker@dojo:~$ export VAR
hacker@dojo:~$ sh
$ echo "VAR is: $VAR"
VAR is: 1337

在这里,子 shell 收到了 VAR 的值,并能够将其打印出来!您还可以合并前两行。

hacker@dojo:~$ export VAR=1337
hacker@dojo:~$ sh
$ echo "VAR is: $VAR"
VAR is: 1337

在此挑战中,您调用 /challenge/run前,要将 PWN 变量导出并设置为值 COLLEGE,并将 COLLEGE 变量设置为值 PWN 但不导出(不被 /challenge/run 继承)。祝你好运!

查看解析
PWN=COLLEGE
COLLEGE=PWN
export PWN
/challenge/run
我们使用"export"命令导出变量

Printing Exported Variables 打印导出的变量

有多种方法可以访问 bash 中的变量。Echo 只是其中之一,我们现在将在这次挑战中至少再学习一个。

试试 env 命令:它会打印出 shell 中设置的每个导出变量,你可以查看该输出以找到 FLAG 变量!

查看解析
env | grep FLAG
我们使用"env"命令查看变量

Storing Command Outpt 存储命令输出

在使用 shell 的过程中,您经常希望将某些命令的输出存储到变量中。幸运的是,shell 使用称为 Command Substitution 的东西使这变得非常容易!观察:

hacker@dojo:~$ FLAG=$(cat /flag)
hacker@dojo:~$ echo "$FLAG"
pwn.college{blahblahblah}
hacker@dojo:~$

现在是你的练习时刻。将 /challenge/run 命令的输出直接读取到名为 PWN 的变量中,它将包含flag!


补充:你也可以用反引号代替 $()在上面的例子中,

FLAG=`cat /flag` 

而不是 FLAG=$(cat /flag)。这是一种较旧的格式,并且有一些缺点(例如,假设您想要嵌套命令替换)。你会怎么用? $(cat $(find / -name flag))吗?pwn.college 的官方立场是你应该使用 $(blah) 而不是

`blah`
查看解析
PWN=$(/challenge/run)
cat $PWN

Reading Input 读取输入

我们将从读取用户 (你) 的输入开始。这是使用恰如其分地命名为 read builtin 完成的,它读取 input!

下面是一个使用 -p 参数的示例,它允许您指定一个提示符(否则,现在阅读本文时,您将很难在下面的示例中将输入与输出分开):

hacker@dojo:~$ read -p "INPUT: " MY_VARIABLE
INPUT: Hello!
hacker@dojo:~$ echo "You entered: $MY_VARIABLE"
You entered: Hello!

请记住,read会从您的标准输入中读取数据!上面的第一个 Hello!input 而不是 output。让我们试着更明确地说明这一点。在这里,我们对每行的开头进行了注释,该行是表示用户的 INPUT 还是用户的 OUTPUT

 INPUT: hacker@dojo:~$ echo $MY_VARIABLE
OUTPUT:
 INPUT: hacker@dojo:~$ read MY_VARIABLE
 INPUT: Hello!
 INPUT: hacker@dojo:~$ echo "You entered: $MY_VARIABLE"
OUTPUT: You entered: Hello!

在这个挑战中,你的工作是使用 readPWN 变量设置为值 COLLEGE。祝你好运!

查看解析
read PWN
COLLEGE
我们使用"read"指令来输入设置变量

Reading Files 读入文件

通常,当 shell 用户想要将文件读入环境变量时,他们会执行以下操作:

hacker@dojo:~$ echo "test" > some_file
hacker@dojo:~$ VAR=$(cat some_file)
hacker@dojo:~$ echo $VAR
test

这很有效,但它代表了牢骚满腹的黑客所说的cat命令的无效使用。也就是说,运行一个完全不同的程序来读取文件是一种浪费。事实证明,你可以直接使用 shell 的力量!

之前,您将用户输入read到一个变量中(将用户输入读入一个变量)。您之前还将文件重定向到命令输入!将它们放在一起,您就可以使用 shell 读取文件。

hacker@dojo:~$ echo "test" > some_file
hacker@dojo:~$ read VAR < some_file
hacker@dojo:~$ echo $VAR
test

上面发生了什么?该示例将 some_file重定向到 read 的标准输入,因此当 read 读入 VAR 时,它会从文件中读取!

现在,使用上述方法将 /challenge/read_me 读取到 PWN 环境变量中,我们将为您提供flag!/challenge/read_me 会不断变化,因此您需要使用一个命令将其直接读取到 PWN 变量中!

查看解析
read PWN < /challenge/read_me

Processes and Jobs 进程和作业

Listing Prcocess 列出进程

首先,我们将学习使用 ps 命令列出正在运行的进程。ps 代表 “进程快照” 或 “进程状态”,它列出了进程。默认情况下,ps 只列出在你的终端中运行的进程,老实说,这并不是很有用:

hacker@dojo:~$ ps
    PID TTY          TIME CMD
    329 pts/0    00:00:00 bash
    349 pts/0    00:00:00 ps
hacker@dojo:~$

在上面的示例中,我们列出正在终端中运行的进程有 shell (bash) 和 ps 进程本身,这就是全部内容。我们还看到每个进程都有一个数字标识符(进程 ID 或 PID),这是一个唯一标识 Linux 环境中每个正在运行的进程的数字。我们还可以看到运行命令的终端(在本例中为名称 pts/0),以及到目前为止该进程已经消耗的 cpu 时间总量(因为这些进程的CPU消耗需求非常低,它们甚至还没有消耗 1 秒!)

在大多数情况下,这就是您在默认 ps 中看到的全部内容。为了使其有用,我们需要传递一些参数。

由于 ps 是一个非常古老的实用程序,因此它的使用有点混乱。有两种方法可以指定参数。

“标准”语法:在此语法中,您可以使用 -e 列出“每个”进程,使用 -f 列出“完整格式”输出,包括参数。这些可以组合成一个参数 -ef

“BSD” 语法:在此语法中,您可以使用 a 列出所有用户的进程,使用 x 列出未在终端中运行的进程,使用 u 表示“用户可读”输出。这些可以组合成一个参数 aux

ps -efps aux 这两种方法产生的输出略有不同,但可以交叉识别。

让我们在 dojo虚拟机 中尝试一下:

hacker@dojo:~$ ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
hacker         1       0  0 05:34 ?        00:00:00 /sbin/docker-init -- /bin/sleep 6h
hacker         7       1  0 05:34 ?        00:00:00 /bin/sleep 6h
hacker       102       1  1 05:34 ?        00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server --auth=none -
hacker       138     102 11 05:34 ?        00:00:07 /usr/lib/code-server/lib/node /usr/lib/code-server/out/node/entr
hacker       287     138  0 05:34 ?        00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server/lib/vscode/ou
hacker       318     138  6 05:34 ?        00:00:03 /usr/lib/code-server/lib/node --dns-result-order=ipv4first /usr/
hacker       554     138  3 05:35 ?        00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server/lib/vscode/ou
hacker       571     554  0 05:35 pts/0    00:00:00 /usr/bin/bash --init-file /usr/lib/code-server/lib/vscode/out/vs
hacker       695     571  0 05:35 pts/0    00:00:00 ps -ef
hacker@dojo:~$

您可以在此处看到,有一些进程正在运行:用于初始化挑战环境 (docker-init)、自动终止挑战前的超时以保留计算资源(sleep 6h,6 小时后超时)、VSCode 环境(多个code-server帮助进程)、shell (bash) 和我的 ps -ef 命令。这与 ps aux 基本相同:

hacker@dojo:~$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
hacker         1  0.0  0.0   1128     4 ?        Ss   05:34   0:00 /sbin/docker-init -- /bin/sleep 6h
hacker         7  0.0  0.0   2736   580 ?        S    05:34   0:00 /bin/sleep 6h
hacker       102  0.4  0.0 723944 64660 ?        Sl   05:34   0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       138  3.3  0.0 968792 106272 ?       Sl   05:34   0:07 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       287  0.0  0.0 717648 53136 ?        Sl   05:34   0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       318  3.3  0.0 977472 98256 ?        Sl   05:34   0:06 /usr/lib/code-server/lib/node --dns-result-order=
hacker       554  0.4  0.0 650560 55360 ?        Rl   05:35   0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       571  0.0  0.0   4600  4032 pts/0    Ss   05:35   0:00 /usr/bin/bash --init-file /usr/lib/code-server/li
hacker      1172  0.0  0.0   5892  2924 pts/0    R+   05:38   0:00 ps aux
hacker@dojo:~$

ps -efps aux 之间有许多共同点:都显示用户(USER 列)、PID、TTY、进程的开始时间 (STIME/START)、总利用的 CPU 时间 (TIME) 和命令 (CMD/COMMAND)。ps -ef 还输出父进程 IDPPID),就是与进程启动相关的进程的 PID,而 ps aux 输出进程正在使用的系统 CPU 和内存总数的百分比。另外,还有许多其他内容我们现在不会讨论。

image-20241020221511143

无论如何!让我们练习一下。在这个关卡中,我再次将 /challenge/run 重命名为随机文件名,这一次你不能ls /challenge 目录!但是我也启动了它,所以可以在正在运行的进程列表中找到它,找出文件名,然后直接为flag重新启动它!祝你好运!

注意:ps -efps aux 都将命令列表截断到终端的宽度(这就是为什么上面的示例在屏幕右侧排列得如此漂亮。如果您无法读取进程的整个路径,则可能需要放大终端(或将输出重定向到某个位置以避免这种截断行为)!

查看解析
ps -ef
使用"ps -ef"命令查看正在运行的进程,其中包含了/challenge/run的程序名< /challenge/read_me

Killing Processes kill进程

您已经启动了流程,查看了流程,现在您将学习如何终止流程!在 Linux 中,这是使用名称激进的 kill 命令完成的。使用默认选项(这就是我们将在本关卡中介绍的全部内容),kill 将终止一个进程,使其有机会在不再存在之前将其事务整理好。

假设您在另一个终端中启动了一个讨厌的 sleep 进程(sleep 是一个程序,它只是在命令行上指定的秒数内挂起,在本例中为 1337 秒),如下所示:

hacker@dojo:~$ sleep 1337

我们如何摆脱它?您可以通过将进程标识符(来自 psPID)作为参数传递来使用 kill 来终止它,如下所示:

hacker@dojo:~$ ps -e | grep sleep
 342 pts/0    00:00:00 sleep
hacker@dojo:~$ kill 342
hacker@dojo:~$ ps -e | grep sleep
hacker@dojo:~$

现在,是时候终止您的第一个进程了!在这个挑战中,/challenge/run 将拒绝在 /challenge/dont_run 运行时运行!您必须找到dont_run进程并终止它。如果你失败了,pwn.college 将不认为你理解了知识点。祝你好运。

查看解析
使用"ps -ef"命令查看正在运行的"dont_run"程序的PID,然后使用"kill"命令终止"dont_run"进程< /challenge/read_me

Interrupting Processes 中断进程

您已经学会了如何使用 kill 命令杀死其他进程,但有时您只想摆脱阻塞终端的进程!幸运的是,终端有一个热键:Ctrl-C(例如,按住 Ctrl 键并按 C)向正在等待终端输入的任何应用程序发送“中断”,通常,这会导致应用程序干净地退出。

在这里试试吧!/challenge/run 将拒绝给你flag,直到你中断它。祝你好运!


对于非常感兴趣的人,请查看这篇关于终端和“控制代码”(例如 Ctrl^C)的文章。

查看解析
/challenge/run
Ctrl+c

Suspending Process 暂停进程

您已经学会了使用 Ctrl-C 中断进程,但您可以使用不那么激烈的措施来恢复您的终端!您可以使用 Ctrl-Z 将进程挂起到后台。在这个关卡中,我们将探索它是如何工作的,在下一个关卡中,我们将弄清楚如何恢复那些暂停的进程!

查看解析
/challenge/run
Ctrl+z
/challenge/run

Resuming Process 恢复进程

通常,当您暂停进程时,您需要在某个时候恢复它们。否则,为什么不直接终止他们呢?为了恢复进程,您的 shell 提供了 fg 命令,这是一个内置命令,用于获取暂停的进程,恢复它,并将其放回终端的前台。

快来试试吧!此挑战的run进程需要您暂停它,然后恢复它。祝你好运!

查看解析
/challenge/run
Ctrl+z
fg

Backgrounding Processes 后台进程

您已使用 fg 命令在前台恢复了进程。您还可以使用 bg 命令在后台恢复进程!这将允许进程继续运行,同时将 shell 交还给你以调用更多命令。

此关卡的run希望看到自己的另一个副本正在运行,而不是暂停,并且使用相同的终端。如何?使用终端启动它,然后暂停它,然后使用 bg 将其置于后台,并在第一个副本在后台运行时启动另一个副本!


提高:如果您对一些更深入的细节感兴趣,请查看如何查看暂停和后台属性之间的差异!请允许我演示一下。首先,让我们暂停sleep

hacker@dojo:~$ sleep 1337
^Z
[1]+  Stopped                 sleep 1337
hacker@dojo:~$

sleep进程现在在后台暂停。我们可以通过使用 -o 选项启用 stat 列输出来通过 ps 看到这一点:

hacker@dojo:~$ ps -o user,pid,stat,cmd
USER         PID STAT CMD
hacker       702 Ss   bash
hacker       762 T    sleep 1337
hacker       782 R+   ps -o user,pid,stat,cmd
hacker@dojo:~$ 

看到那个 T 了吗?这意味着由于我们的 Ctrl-Z,进程已暂停。bashSTAT 列中的 S 表示 bash 在等待输入时处于休眠状态。ps 列中的 R 表示它正在积极运行,+ 表示它位于前台!

观察当我们在后台恢复sleep进程时会发生什么:

hacker@dojo:~$ bg
[1]+ sleep 1337 &
hacker@dojo:~$ ps -o user,pid,stat,cmd
USER         PID STAT CMD
hacker       702 Ss   bash
hacker       762 S    sleep 1337
hacker      1224 R+   ps -o user,pid,stat,cmd
hacker@dojo:~$

BOOM!sleep现在有一个 S。它在运行的时候,就是在睡觉而已,但它并没有暂停!它也在后台运行,因此没有 +

查看解析
/challenge/run
Ctrl+z
bg
/challenge/run

Foregrounding Processes 前台进程

假设您有一个后台进程,并且您希望对它进行更多操作。你是做什么工作的?好吧,您可以使用 fg 将后台进程置于前台,就像将暂停的进程置于前台一样!这个关卡将引导您完成这个任务!

查看解析
/challenge/run
Ctrl+z
bg
fg

Starting Backgrounded Processes 后台启动进程

当然,您不必暂停进程来使它们成为后台:您可以立即后台启动进程!这很容易;您只需在命令后附加一个&,就像这样:

hacker@dojo:~$ sleep 1337 &
[1] 1771
hacker@dojo:~$ ps -o user,pid,stat,cmd
USER         PID STAT CMD
hacker      1709 Ss   bash
hacker      1771 S    sleep 1337
hacker      1782 R+   ps -o user,pid,stat,cmd
hacker@dojo:~$ 

在这里,sleep 在后台主动运行,而没有暂停。现在轮到你练习了!在的后台启动 /challenge/run进程!

查看解析
/challenge/run &

Process Exit Codes 处理退出代码

每个 shell 命令,包括每个程序和每个内置命令,在完成运行并终止时都会以退出代码退出,shell 或 shell 的用户(就是您)可以使用它来检查进程是否成功实现了其功能(当然,这个决定首先取决于进程应该做什么)

您可以使用特殊的变量?来访问最近终止的命令的退出代码(不要忘记在它前面加上 $ 以读取其值!

hacker@dojo:~$ touch test-file
hacker@dojo:~$ echo $?
0
hacker@dojo:~$ touch /test-file
touch: cannot touch '/test-file': Permission denied
hacker@dojo:~$ echo $?
1
hacker@dojo:~$

如您所见,成功的命令通常返回 0,失败的命令通常返回非零值,最常见的是 1,但有时是标识特定故障模式的错误代码

在此关卡中,您必须检索 /challenge/get-code 返回的退出代码,然后使用该错误代码作为参数运行 /challenge/submit-code。祝你好运!

查看解析
/challenge/get-code
echo $?

Perceiving Permissions 感知权限

Changing File Ownership 更改文件所有权

首先我们要理解的概念是:文件所有权。

Linux 中的每个文件都由系统上的用户拥有。大多数情况下,在日常生活中,该用户是我们每天登录的用户。

在共享系统上(例如在计算机实验室中),可能有许多人使用不同的用户帐户,在他们自己的主目录中都有自己的文件。但是,即使在非共享系统(例如您的个人PC)上,Linux仍然有许多用于不同任务的“服务”用户帐户。

两个最重要的用户帐户是:

  1. 您的用户帐户!在 pwn.college 上,无论你的用户名是什么,这都是hacker用户。
  2. root。这是 admin 账户,在大多数安全情况下,这是最终的奖品。如果您接管了 root 用户,您几乎可以肯定已经实现了您的黑客任务!(得到了linux系统主机的最高用户权限

就算如此对我们有什么影响?嗯,事实证明,我们阻止你执行 cat /flag 的方法是让 root 用户拥有 /flag,配置它的权限,这样其他用户就不能读取它(你稍后会学习如何配置权限),并将实际的质询配置为以 root 用户身份运行(你稍后也会学习如何这样做)。结果是,当你执行 cat /flag 时,你会得到:

hacker@dojo:~$ ls -l /flag
-r-------- 1 root root 53 Jul  4 04:47 /flag
hacker@dojo:~$ cat /flag
cat: /flag: Permission denied
hacker@dojo:~$

在这里,您可以看到该flag由 root 用户(第二行中的第一个root)和 root 组(第二行中的第二个root)拥有。当我们尝试以hacker用户的身份读取它时,我们被拒绝了。但是,如果我们是 root 用户(黑客的梦想),那么读取这个文件就不会有问题:

root@dojo:~# cat /flag
pwn.college{demo_flag}
root@dojo:~#

可以看见我们提示符末尾由$变成了#

有趣的是,我们可以更改文件的所有权!这是通过 chownchange owner) 命令完成的:

chown [username] [file]

通常,chown 只能由 root 用户调用。让我们假设我们又是 root 了,并观察 chown 的典型用法:

root@dojo:~# mkdir pwn_directory
root@dojo:~# touch college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root root    0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~# chown hacker college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 hacker root    0 May 22 13:42 college_file
drwxr-xr-x 2 root   root 4096 May 22 13:42 pwn_directory
root@dojo:~#

college_file 的所有者已更改为hacker用户,以及 hacker 如何对它执行任何 root 操作!如果这是 /flag 文件,则意味着hacker用户将能够读取它!

在这个关卡中,我们将练习将 /flag 文件的所有者更改为 hacker 用户,然后是 flag。仅对于这个挑战,hacker用户拥有使用chown命令的权限,这样您就可以作为hacker用户尽情地使用 chown(要记住,通常这需要您是 root用户)。明智地使用这种力量,然后得到flag!

查看解析
chown hacker /flag
cat /flag
使用"chown"更改"/flag"文件的所有者用户

Group and Files 用户组和文件

分享就是关怀,而分享是 Linux 设计中内置的。文件拥有权同时属于用户。一个组中可以有多个用户,并且一个用户可以是多个组的成员。

您可以使用 id 命令检查您所属的组:

hacker@dojo:~$ id
uid=1000(hacker) gid=1000(hacker) groups=1000(hacker)
hacker@dojo:~$

这里,hacker 用户hacker 组中。

组最常见的用例是控制对不同系统资源的访问。例如,pwn.college 中的 “Practice Mode”(练习模式) 授予你 root 权限,以便更好地进行调试,等等。这是通过在 "Practice Mode" 虚拟机启动时为您提供一个额外的组来处理的:

hacker@dojo:~$ id
uid=1000(hacker) gid=1000(hacker) groups=1000(hacker),27(sudo)
hacker@dojo:~$

在"Practice Mode"中我们在"sudo"用户组,在这个用户组中的用户可以使用sudo命令,即以root用户的身份运行程序

经典Linux桌面系统的默认主用户有许多组。例如,这是Zardus的桌面:

zardus@yourcomputer:~$ id
uid=1000(zardus) gid=1000(zardus) groups=1000(zardus),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),114(bluetooth),117(lpadmin),120(scanner),995(docker)
zardus@yourcomputer:~$

所有这些组都使 Zardus 能够读取 CD 和软盘(现在谁还用软盘了?)、管理系统、播放音乐、绘制视频监视器、使用蓝牙等等。通常,这种访问控制是通过文件系统上的组所有权来实现的!例如,图形输出可以通过特殊的 /dev/fb0 文件来完成:

zardus@yourcomputer:~$ ls -l /dev/fb0
crw-rw---- 1 root video 29, 0 Jun 30 23:42 /dev/fb0
zardus@yourcomputer:~$

此文件是一个特殊的设备文件c 意味着它是一个“字符设备”),与它交互会导致显示输出发生变化(而不是像普通文件那样改变磁盘存储!Zardus 在其计算机上的用户帐户可以与它交互,因为该文件具有 video 的组所有权,并且 Zardus 是 video 组的成员。

字符设备是计算机系统中的一种设备类型,主要用于处理以字符为单位的输入和输出

不过,dojo 中的 /flag 文件就没有这样的运气了!请思考以下示例:

hacker@dojo:~$ id
uid=1000(hacker) gid=1000(hacker) groups=1000(hacker)
hacker@dojo:~$ ls -l /flag
-r--r----- 1 root root 53 Jul  4 04:47 /flag
hacker@dojo:~$ cat /flag
cat: /flag: Permission denied
hacker@dojo:~$

这里,flag 文件归 root 用户和 root 组所有,hacker 用户既不是 root 用户,也不是 root 组的成员,因此无法访问该文件。幸运的是,可以使用 chgrpchange group) 命令更改组所有权!除非你对文件有写入权限新组的成员身份,否则这通常需要 root 访问权限,所以让我们以 root 身份检查一下:

root@dojo:~# mkdir pwn_directory
root@dojo:~# touch college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root root    0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~# chgrp hacker college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root hacker    0 May 22 13:42 college_file
drwxr-xr-x 2 root root   4096 May 22 13:42 pwn_directory
root@dojo:~#

在这个关卡中,我使拥有它的任何组都可以读取该flag,但该组目前是 root。幸运的是,我还允许您以hacker用户身份调用 chgrp!更改flag文件的组所有权,然后读取flag!

查看解析
chgrp hacker /flag
cat /flag
使用"chgrp"更改"/flag"文件的所有组

Fun With Group Names 用户组名中的乐趣

在前面的关卡中,您可能已经注意到您的hacker用户是hacker组的成员,而 zarduszardus 组的成员。Linux 中有一个约定,每个用户都有自己的组,但并非必须如此。例如,许多计算机实验室会将其所有用户放入一个共享users组中。

重点是,您之前使用的都是 hacker用户组,但在这个关卡中,这行不通。我仍然允许您使用 chgrp,但我已随机化了您的用户所在的组的名称。您需要使用 id 命令来计算出该名称,然后 chgrp 过关!

查看解析
id
使用"id"查看"hacker"用户当前处在的用户组

Changing Permissiongs 更改权限

所以现在我们已经精通所有权的概念了。 现在让我们谈谈另一个概念:文件权限。 回想一下我们的例子:

hacker@dojo:~$ mkdir pwn_directory
hacker@dojo:~$ touch college_file
hacker@dojo:~$ ls -l
total 4
-rw-r--r-- 1 hacker hacker    0 May 22 13:42 college_file
drwxr-xr-x 2 hacker hacker 4096 May 22 13:42 pwn_directory
hacker@dojo:~$

提醒一下,-rw-r--r--中第一个字符是文件类型。 接下来的 9 个字符是文件或目录的实际访问权限, 3 个字符表示拥有用户的权限,3 个字符表示拥有组的权限,3 个字符表示所有其他访问权限(例如,其他用户和其他组)对文件的权限。

这三个字符中的每个字符都表示不同类型的权限:

r -用户/组/其他可以读取文件(或列出目录)
w -用户/组/其他可以修改文件(或创建/删除目录中的文件)
x -用户/组/其他可以作为程序执行文件(或者可以进入目录,例如,使用‘ cd ’)
- -没权限

对于上述college_file,rw-r--r-- 权限条目解码为:``

  • r:拥有该文件的用户(用户 hacker)可以读取该文件
  • w:拥有该文件的用户(用户 hacker)可以写入该文件
  • -:拥有该文件的用户(用户 hacker无法执行该文件
  • r:拥有该文件的组(Hacker 组)中的用户可以读取该文件
  • -:拥有该文件的组中的用户 (group hacker无法写入该文件
  • -:拥有该文件的组中的用户(hacker 组无法执行该文件
  • r:所有其他用户都可以读取
  • -:所有其他用户都无法写入它
  • -:所有其他用户都无法执行它

现在,让我们看看 /flag 的默认权限:

hacker@dojo:~$ ls -l /flag
-r-------- 1 root root 53 Jul  4 04:47 /flag
hacker@dojo:~$

这里,只设置了一个位:拥有用户(在本例中为 root)的 read 权限。 拥有组 (root组) 的成员和所有其他用户无权访问该文件。

您可能想知道,如果没有对文件的组访问权限,chgrp 是如何工作的。 对于这些,我以不同的方式设置权限:

hacker@dojo:~$ ls -l /flag
-r--r----- 1 root root 53 Jul  4 04:47 /flag
hacker@dojo:~$

root小组可以访问! 这就是为什么 chgrp文件使您能够读取该文件的原因。

无论如何! 与所有权一样,文件权限也可以更改。 这是通过 chmodchange mode) 命令完成的。 chmod 的基本用法是:

chmod [OPTIONS] MODE FILE

您可以通过两种方式指定 MODE:作为现有权限模式的修改,或作为覆盖旧模式的全新模式。

在本关卡中,我们将介绍前者:修改现有模式。

chmod 允许您使用 WHO+/-WHAT 的模式格式调整权限,其中 WHO 是 user/group/other,WHAT 是 read/write/execute。

例如,要为拥有用户添加读取访问权限,您可以指定 u+r 模式。 GRoup 和 OTher(或 All 模式)的 WRite 和 Execute 访问权限以相同的方式指定。 更多示例:

  • u+r 为用户的权限添加了 Read 访问权限
  • g+wx 为组的权限添加了 Write 和 Execute 访问权限
  • o-w删除其他用户的 Write 访问权限
  • a-rwx 删除用户、组和其他用户的所有权限

所以:

root@dojo:~# mkdir pwn_directory
root@dojo:~# touch college_file
root@dojo:~# ls -l
total 4
-rw-r--r-- 1 root root    0 May 22 13:42 college_file
drwxr-xr-x 2 root root 4096 May 22 13:42 pwn_directory
root@dojo:~# chmod go-rwx *
root@dojo:~# ls -l
total 4
-rw------- 1 hacker root    0 May 22 13:42 college_file
drwx------ 2 root   root 4096 May 22 13:42 pwn_directory
root@dojo:~#

在本次挑战中,您必须更改 /flag 的文件权限才能读取它! 通常,您需要具有文件的写入权限才能更改其权限,但是我已经使 chmod 命令在此关卡中非常强大,即使您是hacker用户,也可以 chmod 任何您想要的东西。 这是一种终极的力量。 /flag 文件归 root 所有,您无法更改它,但可以使其可读。 快来解决这个问题吧!

查看解析
chmod o+r /flag
cat /flag
使用"chmod"修改"/flag"其他用户的文件读取权限

Executable Files 可执行文件

到目前为止,您主要一直在处理读取权限。这是有道理的,因为您一直在使 /flag 文件可读以便读取它。在此关卡中,我们将探索执行权限。

当您调用程序(如 /challenge/run)时,Linux 只有在您具有程序文件的执行访问权限时才会实际执行该程序。考虑:

hacker@dojo:~$ ls -l /challenge/run
-rwxr-xr-x 1 root root    0 May 22 13:42 /challenge/run
hacker@dojo:~$ /challenge/run
Successfully ran the challenge!
hacker@dojo:~$

在这种情况下,/challenge/run 会运行,因为它可由hacker用户执行。由于该文件归 root 用户和 root 组所有,因此这需要在其他用户的权限上设置执行权限。如果我们删除这些权限,执行将失败!

hacker@dojo:~$ chmod o-x /challenge/run
hacker@dojo:~$ ls -l /challenge/run
-rwxr-xr-- 1 root root    0 May 22 13:42 /challenge/run
hacker@dojo:~$ /challenge/run
bash: /challenge/run: Permission denied
hacker@dojo:~$

在这个挑战中,/challenge/run 程序会给你这个flag,但你必须先让它可执行!记住你的 chmod,然后获取 /challenge/run 来告诉你这面flag!

查看解析
chmod a+x /challenge/run
/challenge/run
使用"chmod"修改"/flag"所有用户的文件执行权限

Permission Tweaking Practice 权限调整练习

你觉得你可以 chmod?让我们练习吧!

此挑战将要求您连续几次以特定方式更改 /challenge/pwn 文件的权限。如果您获得错误的权限,游戏将重置,您可以重试。如果你连续八次获得正确的权限,挑战将让你 chmod /flag 使其对自己可读 :-)启动 /challenge/run 以开始挑战!

查看解析
按照题目提示修改`/challenge/pwn`文件的权限即可

Permission Setting Practice 权限设置练习

除了像上一关卡一样添加或删除权限之外,chmod 还可以简单地完全设置权限,覆盖旧的权限。这是通过使用 = 而不是 -+ 来完成的。例如:

  • u=rw 为用户设置读写权限,并擦除执行权限
  • o=x 仅设置其他用户的可执行权限,擦除 read 和 write 权限
  • a=rwx 为 user、group 和 world 设置读取、写入和可执行权限!

但是,如果您想以与组权限不同的方式更改用户权限,该怎么办?假设您想为拥有用户设置 rw,但只为拥有组设置 r?你可以通过使用

  • chmod u=rw,g=r /challenge/pwn 会将用户权限设置为读写,组权限设置为只读
  • chmod a=r,u=rw /challenge/pwn 会将用户权限设置为读写,将 group 和 world 权限设置为只读

此外,您可以使用 - 将权限归零:

  • chmod u=rw,g=r,o=- /challenge/pwn 将 User permissions 设置为 read 和 write,将 group permissions 设置为 read-only,并将 world 权限设置为完全不

请记住,出现在 = 之后的 - 与直接出现在 ugo 之后的上下文不同(在这种情况下,它会导致删除特定位,而不是所有内容)。

此关卡通过以上说的方式来更改权限,您需要 =, -来实现。祝你好运!

查看解析
与上一关一样,按照题目提示修改`/challenge/pwn`文件的权限即可

The SUID Bit SUID设置用户标识

在许多情况下,非 root 用户需要提升访问权限才能执行某些系统任务。系统管理员不能在每次用户想要执行只有 root/sudoers 才能执行的任务时都在那里给他们密码。“设置用户标识” (SUID) 权限位允许用户以程序文件的所有者身份运行程序。

这实际上是用于让您运行的挑战程序读取flag或在 pwn.college 之外启用系统管理工具(如 susudo 等)的确切机制。具有 SUID 列表的文件的权限如下所示:

hacker@dojo:~$ ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 232416 Dec 1 11:45 /usr/bin/sudo
hacker@dojo:~$

可执行权限位为s 表示程序可以使用 SUID 执行。这意味着,无论哪个用户运行该程序(只要他们具有可执行权限),程序都将以所有者用户(在本例中为 root 用户)的身份执行。

作为文件的所有者,您可以使用 chmod 设置文件的 SUID 位:

chmod u+s [program]

但要小心!将 SUID 位提供给 root 拥有的可执行文件可能会为攻击者提供可能成为对 root 用户的攻击媒介。您将在 Program Misuse 模块中了解有关此内容的更多信息。

现在,我们将让您将 SUID 位添加到 /challenge/getroot 程序中,以便生成一个根 shell,以便您自己 cat flag!

查看解析
chmod u+s /challenge/getroot
/challenge/getroot
cat /flag

Untangling Users 理清用户关系

Becoming root with su 使用su成为root

在上一关中,您使用了 /challenge/getroot 程序成为 root 用户。成为 root 是 Linux 用户采取的一种相当常见的操作,而您的经典 Linux 显然没有 /challenge/getroot程序。相反,有两个实用程序用于此目的:susudo

在这个挑战中,我们将介绍较旧的 suswitch user 命令)。这通常不再用于提升为 root 访问权限,但它是来自更文明时代的优雅实用程序,我们将首先介绍它
su 是一个具有设置用户标识(setuid)权限的二进制文件:

hacker@dojo:~$ ls -l /usr/bin/su
-rwsr-xr-x 1 root root 232416 Dec 1 11:45 /usr/bin/su
hacker@dojo:~$

因为它设置了 SUID 位,所以 su 以 root 身份运行。以 root 身份运行,它可以启动一个 root shell!当然,su 是有检测机制的:在允许用户将权限提升到 root 之前,它会检查以确保用户知道 root 密码:

hacker@dojo:~$ su
Password: 
su: Authentication failure
hacker@dojo:~$

这种针对 root 密码的检查使 su显得过时。现代系统很少有 root 密码,并且使用不同的机制(我们将在后面学习)来授予管理访问权限

但是在这个挑战中(也只有这个挑战中)确实有 root 密码。该密码是 hack-the-planet,您必须将其提供给 su 才能成为 root!去做那个,读一下flag!

查看解析
su
hack-the-planet
cat /flag
使用"su"程序提升到root权限

Other users with su 其他具有su的用户

在没有参数的情况下,su 将启动一个 root shell(在使用 root 的密码进行身份验证后)。但是,您也可以将 username 作为参数来切换到用户而不是 root。例如:

hacker@dojo:~$ su some-user
Password:
some-user@dojo:~$

很好!在这个关卡中,你必须切换到 zardus 用户,然后运行 /challenge/run。Zardus 的密码是 dont-hack-me。祝你好运!

查看解析
su zardus
dont-hack-me
/challenge/run
使用"su"程序切换到zardus用户

Cracking passwords 破解密码

当您输入 su 的密码时,它会将其与该用户的存储密码进行比较。这些密码曾经存储在 /etc/passwd 中,但因为 /etc/passwd 是一个全局可读的文件,这对密码不利,所以这些密码被移到了 /etc/shadow。下面是上一关的示例 /etc/shadow

root:$6$s74oZg/4.RnUvwo2$hRmCHZ9rxX56BbjnXcxa0MdOsW2moiW8qcAl/Aoc7NEuXl2DmJXPi3gLp7hmyloQvRhjXJ.wjqJ7PprVKLDtg/:19921:0:99999:7:::
daemon:*:19873:0:99999:7:::
bin:*:19873:0:99999:7:::
sys:*:19873:0:99999:7:::
sync:*:19873:0:99999:7:::
games:*:19873:0:99999:7:::
man:*:19873:0:99999:7:::
lp:*:19873:0:99999:7:::
mail:*:19873:0:99999:7:::
news:*:19873:0:99999:7:::
uucp:*:19873:0:99999:7:::
proxy:*:19873:0:99999:7:::
www-data:*:19873:0:99999:7:::
backup:*:19873:0:99999:7:::
list:*:19873:0:99999:7:::
irc:*:19873:0:99999:7:::
gnats:*:19873:0:99999:7:::
nobody:*:19873:0:99999:7:::
_apt:*:19873:0:99999:7:::
systemd-timesync:*:19901:0:99999:7:::
systemd-network:*:19901:0:99999:7:::
systemd-resolve:*:19901:0:99999:7:::
mysql:!:19901:0:99999:7:::
messagebus:*:19901:0:99999:7:::
sshd:*:19901:0:99999:7:::
hacker::19916:0:99999:7:::
zardus:$6$bEFkpM0w/6J0n979$47ksu/JE5QK6hSeB7mmuvJyY05wVypMhMMnEPTIddNUb5R9KXgNTYRTm75VOu1oRLGLbAql3ylkVa5ExuPov1.:19921:0:99999:7:::

每行的第一个字段以 分隔,每个行的第一个字段是用户名,第二个字段是密码。 *在功能上表示帐户的密码登录被禁用,空白字段表示没有密码(一种并不罕见的错误配置,在某些配置中允许无密码的 su),而长字符串(如 Zardus的密码) $6$bEFkpM0w/6J0n979$47ksu/JE5QK6hSeB7mmuvJyY05wVypMhMMnEPTIddNUb5R9KXgNTYRTm75VOu1oRLGLbAql3ylkVa5ExuPov1. 是单向加密(哈希)Zardus 的密码的结果(在本例中为 don't-hack-me)。此文件中的其他字段具有其他含义,您可以在此处阅读有关它们的更多信息。

当你在 su 中输入密码时,它会单向加密(散列)它,并将结果与存储的值进行比较。如果结果匹配,则 su 将授予您访问该用户的权限!

但是,如果您不知道密码怎么办?如果你有密码的哈希值,就可以破解它!尽管 /etc/shadow 默认情况下只能由 root 读取,但泄漏还是会发生!例如,备份通常存储在文件服务器上,未加密且保护不足,这导致了无数的数据泄露。

如果黑客掌握了泄露的 /etc/shadow,他们就可以开始破解密码并造成严重破坏。破解可以通过著名的John the Ripper来完成,如下所示:

hacker@dojo:~$ john ./my-leaked-shadow-file
Loaded 1 password hash (crypt, generic crypt(3) [?/64])
Will run 32 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
password1337      (zardus)
1g 0:00:00:22 3/3 0.04528g/s 10509p/s 10509c/s 10509C/s lykys..lank
Use the "--show" option to display all of the cracked passwords reliably
Session completed
hacker@dojo:~$

在上例中,John the Ripper(一款密码破解工具)破解了 Zardus 泄露的密码哈希,找到了 password1337 的真实值。可怜的Zardus!

此关卡模拟了这个示例,给你一个 /etc/shadow 的泄漏(在 /challenge/shadow-leak 中)。破解它(这可能需要几分钟),su 转换到 zardus,然后运行 /challenge/run 来获得flag!

查看解析
john /challenge/shadow-leak
su zardus
使用"john"工具破解zardus用户泄露的密码哈希值

【CTF入门】BUUCTF Misc刷题(持续更新) - Super_Snow_Sword - 博客园这里有使用Jhon破解密码的实战CTF题目

Using sudo 使用sudo

在过去,典型的Linux系统有一个root密码,管理员可以使用它来su到root(在使用正常的帐户密码登录到他们的帐户后)。但是根密码维护起来很麻烦,它们(或它们的哈希值!)可能会泄露,而且它们不适合大型环境(例如,服务器群)。为了解决这个问题,近几十年来,世界已经从通过su进行管理转向通过sudo(superuser do)进行管理。

与 su 不同,su 默认以指定用户身份启动 shell,而 sudo 默认以 root 身份运行命令:

hacker@dojo:~$ whoami
hacker
hacker@dojo:~$ sudo whoami
root
hacker@dojo:~$

或者,与获取flag更相关:

hacker@dojo:~$ grep hacker /etc/shadow
grep: /etc/shadow: Permission denied
hacker@dojo:~$ sudo grep hacker /etc/shadow
hacker:$6$Xro.e7qB3Q2Jl2sA$j6xffIgWn9xIxWUeFzvwPf.nOH2NTWNJCU5XVkPuONjIC7jL467SR4bXjpVJx4b/bkbl7kyhNquWtkNlulFoy.:19921:0:99999:7:::
hacker@dojo:~$

su 不同的是,sudo 不是通过密码进行身份验证,而是依赖于它检查的策略来确定用户以 root 身份运行程序的授权。这些策略在 /etc/sudoers 中定义,虽然它大多超出了我们的需要,但有大量资料可以学习这些!

因此,大部分用户转向使用 sudo 并 (出于系统管理目的) 将 su 抛在后面。事实上,即使是 pwn.college 的练习模式也是通过为您提供 sudo 访问权限来提升权限的!

在这个级别中,我们将为你提供 sudo 访问权限,你将使用它来读取flag。很好,很容易!


注意:在此级别之后,我们将启用练习模式!当您在 Practice Mode 中启动挑战时(通过单击 Practice 按钮而不是 Start 按钮),生成的容器将为您提供完整的 sudo 访问权限,以便您根据自己的喜好进行内省和调试,但当然会带有占位符标志。

查看解析
sudo cat /flag
使用"sudo"以root身份读取"flag"内容

Chaining Commands 命令串联

Chaining with Semicolons 使用分号链接

链接命令的最简单方法是 ;。在大多数上下文中,; 分隔命令的方式与 Enter 分隔行的方式类似。所以,在下例中:

hacker@dojo:~$ echo COLLEGE > pwn
hacker@dojo:~$ cat pwn
COLLEGE
hacker@dojo:~$

大致与此相同:

hacker@dojo:~$ echo COLLEGE > pwn; cat pwn
COLLEGE
hacker@dojo:~$

基本上,当您按 Enter 键时,shell 会执行您键入的命令,并在该命令终止后提示您输入另一个命令。分号与此类似,只是没有提示符,并且您在执行任何内容之前输入两个命令

现在就试一试吧!在这个关卡中,你必须运行 /challenge/pwn,然后运行 /challenge/college,用分号将它们连接起来

查看解析
/challenge/pwn; /challenge/college
使用`;`链接两个程序"

Your First Shell Script 你的第一个shell脚本

随着你组合越来越多的命令来实现复杂的效果,组合输入的长度很快就会变得非常烦人。发生这种情况时,您可以将这些命令放在一个称为 shell 脚本的文件中,然后通过执行该文件来运行它们!例如以下分号的使用:

hacker@dojo:~$ echo COLLEGE > pwn; cat pwn
COLLEGE
hacker@dojo:~$

我们可以创建一个名为 pwn.sh 的 shell 脚本(按照惯例,shell 脚本通常使用 sh 后缀命名):

echo COLLEGE > pwn
cat pwn

然后我们可以将其作为参数传递给我们的 shell 的新实例 (bash) 来执行!当像这样调用 shell 时,它不会从用户那里获取命令,而是从文件中读取命令。

hacker@dojo:~$ ls
hacker@dojo:~$ bash pwn.sh
COLLEGE
hacker@dojo:~$ ls
pwn
hacker@dojo:~$

您可以看到 shell 脚本执行了这两个命令,创建并打印了 pwn 文件。

现在,轮到你了!与上一关相同,运行 /challenge/pwn,然后运行 /challenge/college,但这次是在名为 x.sh 的 shell 脚本中运行,然后使用 bash 运行它!


注意:我们还没有讨论过 Linux 令人惊叹的一系列强大的命令行文件编辑器。现在,您可以随意使用桌面模式下的Text Editor应用程序 ( Applications->Accessories->Text Editor ) 或 VSCode 工作区中的默认编辑器!

查看解析
vim pwn.sh
/challenge/pwn
/challenge/college
bash pwn.sh
使用`vim`创建文本文件,并使用"esc"+":wq"保存并退出

Redirecting Script Output 重定向脚本输出

让我们尝试一些更棘手的事情!您已经使用 |在程序之间通过管道传输了输出,但到目前为止,这只是一个命令的输出和另一个命令的输入之间。但是,如果您想将多个程序的输出发送到一个命令,该怎么办?有几种方法可以做到这一点,我们将在这里探讨一个简单的方法:重定向脚本的输出!

就 shell 而言,您的脚本只是另一个命令。这意味着您可以重定向其输入和输出,就像在 Piping 模块中对命令所做的那样!例如,您可以将其写入文件:

hacker@dojo:~$ cat script.sh
echo PWN
echo COLLEGE
hacker@dojo:~$ bash script.sh > output
hacker@dojo:~$ cat output
PWN
COLLEGE
hacker@dojo:~$

所有的各种重定向方法都有效:>用于stdout,2>用于stderr,<用于stdin,>>2>>用于附加模式重定向,>&用于重定向到其他文件描述符,以及|用于管道到另一个命令。

在这个级别中,我们将练习从你的脚本到另一个程序的管道 (|)。和以前一样,您需要创建一个脚本,先调用 /challenge/pwn 命令,然后调用 /challenge/college 命令,并将脚本的输出通过管道传输到 /challenge/solve 命令的单个调用中!

查看解析
vim pwn.sh
/challenge/pwn
/challenge/college
bash pwn.sh | /challenge/solve

Executable Shell Scripts 可执行shell脚本

您已经编写了第一个 shell 脚本,但是通过 bash script.sh 调用它很痛苦。为什么需要那个 bash

调用 bash script.sh 时,您当然会启动带有 script.sh 参数的 bash 命令。这告诉 bash 从 script.sh 而不是标准输入中读取其命令,从而执行您的 shell 脚本。

事实证明,您可以避免手动调用 bash 的需要。如果您的 shell 脚本文件是可执行的(回想一下文件权限的内容),您只需通过其相对或绝对路径调用它即可!例如,如果您在主目录中创建 script.sh 并使其可执行,则可以通过 /home/hacker/script.sh 或 ~/script.sh 或(如果您的工作目录是 /home/hacker)./script.sh 调用它。

在这里试试吧!创建一个将调用 /challenge/solve 的 shellscript,使其可执行,并在不显式调用 bash 的情况下运行它!

查看解析
vim pwn.sh
/challenge/solve
chmod +x pwn.sh
./pwn.sh

Pondering PATH 对PATH环境变量的深入思考

The PATH Variable PATH环境变量

事实证明,“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 程序的运行。该程序将使用 rm 命令删除flag文件。但是,如果找不到 rm 命令,则不会删除该flag,挑战会将其交给您!因此,您必须使 /challenge/run 也找不到 rm 命令!

请记住:/challenge/run 将是 shell 的子进程,因此您必须应用在 Shell 变量中学到的概念来弄乱其 PATH 变量!如果您没有成功,并且标记被删除,您将需要重新开始挑战才能重试!

查看解析
PATH=""
/challenge/run
使PATH环境变量为空使得"run"程序无法运行`rm`

Setting PATH 设置PATH环境变量

好的,所以当你清空 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:~l

如果您维护了一个有用的脚本目录,并且希望能够通过裸名称启动,不然一个个输入路径很烦人。但是,通过向此列表中添加目录或替换目录中的目录,您可以使用它们的裸名称公开这些要启动的程序!例如:

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="/challenge/more_commands"
/challenge/run
设置PATH环境变量为空使得"run"程序能够直接裸名称运行`win`命令

Adding Commands 添加命令

回想一下上一关的示例:

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:~$

当然,我们在这里看到的是,黑客通过将自己的命令带到PATH环境变量中,使 shell 对自己更有用。随着时间的推移,您可能会积累自己的优雅工具。让我们从 win 开始吧!

之前,/challenge/run 执行的 win 命令存储在 /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。由于 readbash 的内置功能,因此它不受 PATH 恶作剧的影响。

现在,开始win吧!

查看解析
这里使用第二种方法,设置一个包含旧目录和新目录的PATH环境变量
vim win
chmod +x win
echo $PATH
export PATH=/home/hacker:$PATH
/challenge/run
使用"export"命令将新添加的PATH环境变量添加到源PATH环境变量前面

Hijacking Commands 劫持命令

有了现在的知识,你现在可以进行一些恶作剧了。此挑战与本模块中的第一个挑战几乎相同。同样,此挑战将使用 rm 命令删除flag。但与以前不同的是,它不会为您打印任何内容

你怎么解决这个问题呢?您知道 rm 是在 PATH 变量中列出的目录中搜索的。您有在上一个挑战需要时创建 win 命令的经验。您还可以创建哪些内容?

查看解析
vim rm
chmod +x rm
export PATH=/home/hacker:$PATH
/challenge/run
使PATH环境变量为空使得"run"程序无法运行`rm`
posted @ 2024-10-20 22:59  Super_Snow_Sword  阅读(120)  评论(0编辑  收藏  举报