实战奇技淫巧


Linux 启明道场.

本模块将通过一些实战小花招,加深你对 Linux 的理解。 了解系统功能如何影响安全,是弄懂系统内部机制的好方法。


shell 启动时,会在你的主目录中查找 .bashrc 文件,并把它作为启动脚本执行。 你可以在 /home/hacker/.bashrc 中加入实用配置,例如设置环境变量、调整 shell 配置等。

你也可以用它来干坏事! 毫无防备的用户的 .bashrc 是常见的攻击目标。 想象一下,你偷偷打开朋友的电脑,加上一条 echo "Hackers were here!" 命令,放在他的 .bashrc 末尾。 这只是个恶作剧,但同样的机制也能用于更恶劣的目的。 例如,恶意软件经常利用 .bashrc 这样的启动脚本,确保以后仍能持续运行!

本挑战假设你已经侵入了一位受害用户的机器! 他的用户名是 zardus,主目录是 /home/zardus。 你以 hacker 用户的身份,对他的 .bashrc 拥有写入权限,而 zardus 可以读取 /flag。 我们用 /challenge/victim 脚本来模拟受害用户,你随时可以启动它,观察受害用户登录电脑的过程。 你能拿到 flag 吗?


提示: 和你在“串联命令”中探索过的脚本一样,.bashrc 本质上就是一个 shell 脚本。 新增一行命令(例如 echo Hello Hackers),这条命令就会被执行。因此,你只需要想清楚什么命令能让你拿到 flag!

注意: 受害用户的 /home/zardus/.bashrc 中已经有很多内容:shell 启动是一个复杂的过程。 别慌,把你的攻击代码追加到末尾,再试试效果就好!

提示: 需要以 zardus 的身份查看环境、调试方案吗? 在特权模式下,你可以使用 sudo su --login zardus 进入 zardus 的会话!

上一关中,你利用 zardus 的 ~/.bashrc,让他替你运行了命令。

这一次,zardus 登录后不会把 flag 留在可读文件中。 他会运行一个名为 flag_checker 的命令,然后手动输入 flag 进行验证。

你的任务是利用你仍然拥有的写入权限,修改 zardus 的 .bashrc,截获这个 flag。 还记得你在“深入 PATH”模块中如何劫持命令吗? 能用同样的办法劫持 flag_checker 吗?


提示: 你的劫持行为吓到 zardus 了吗? 他很谨慎,会检查 flag_checker 是否显示提示文字 Type the flag。 确保你的替代程序也输出这条提示(例如 echo "Type the flag")。 除了输出提示以外,你伪造的 flag_checker 可以选择:a) 用 cat 将 zardus 的输入直接输出到标准输出(例如 不带参数的 cat);或 b) 用 read 将输入读入变量,再用 echo 输出。 任选一种!


提示: 别忘了给你伪造的 flag_checker 加上执行权限,就像你在“理解权限”模块中学到的那样!

zardus 学聪明了——他为什么要让别人能写入自己的 .bashrc 呢? 不过,更常见的情况是,同一系统上的用户为了方便协作,会把主目录设置为所有人可写。 这样有什么问题?

问题在于,Linux 文件和目录权限有一个容易忽略的细节:只要对目录有写入权限,就能移动和删除其中的文件。 例如,假设 zardus 创建了一个所有人可写的协作目录:

zardus@dojo:~$ mkdir /tmp/collab
zardus@dojo:~$ chmod a+w /tmp/collab
zardus@dojo:~$ echo "do pwn.college" > /tmp/collab/todo-list

这时,一个攻击者过来执行了以下操作,即使 todo-list 文件并不属于他!

hacker@dojo:~$ ls -l /tmp/collab/todo-list
-rw-r--r-- 1 zardus zardus 15 Jun  6 13:12 /tmp/collab/todo-list
hacker@dojo:~$ rm /tmp/collab/todo-list
rm: remove write-protected regular file '/tmp/collab/todo-list'? y
hacker@dojo:~$ echo "send hacker money" > /tmp/collab/todo-list
hacker@dojo:~$ ls -l /tmp/collab/todo-list
-rw-r--r-- 1 hacker hacker 18 Jun  6 13:12 /tmp/collab/todo-list
hacker@dojo:~$

这看起来可能违反直觉:hacker 对 todo-list 没有写入权限,却最终改变了它的内容。 换个角度想:文件与目录之间的关联保存在目录中,能写入目录的用户就能修改这种关联。 因此,重要目录若允许所有人写入,就会产生安全隐患。

本挑战中,为了方便,zardus 开放了自己的主目录:

zardus@dojo:~$ chmod a+w /home/zardus

你知道,这个目录中有很多敏感文件,例如 .bashrc! 现在你可以写入 /home/zardus,但不能直接写入 /home/zardus/.bashrc,还能重现之前的攻击吗?

zardus 又学聪明了! 他不再共享主目录,虽然没那么方便,但还是改为共享 /tmp/collab。 他让所有人都能写入这个目录,还开始整理一份危险命令清单,以便记住它们!

zardus@dojo:~$ mkdir /tmp/collab
zardus@dojo:~$ chmod a+w /tmp/collab
zardus@dojo:~$ echo "rm -rf /" > /tmp/collab/evil-commands.txt

本挑战中,当你运行 /challenge/victim 时,zardus 会把 cat /flag 加入这份命令清单:

hacker@dojo:~$ /challenge/victim

Username: zardus
Password: **********
zardus@dojo:~$ echo "cat /flag" >> /tmp/collab/evil-commands.txt
zardus@dojo:~$ exit
logout

hacker@dojo:~$

回顾上一关,只要能写入 /tmp/collab,hacker 用户就能替换 evil-commands.txt 文件。 你也在“理解命令”中学过,文件可以链接到其他文件。 如果 hacker 把 evil-commands.txt 替换为一个指向敏感文件的符号链接,而 zardus 恰好能写入那个文件,会发生什么? 这就有机会大显身手了!

你已经知道该链接到哪个文件。 完成攻击,拿到 /flag(本关中,zardus 又能读取它了!)。


提示: 你需要运行 /challenge/victim 两次:第一次把 cat /flag 写到你想要的位置,第二次触发这条命令!

使用 /tmp 很危险吗??? 虽然这里展示了一种攻击方式,但 /tmp 仍然可以安全使用。 这个目录确实允许所有人写入,不过它设置了一个特殊的权限位:

hacker@dojo:~$ ls -ld /tmp
drwxrwxrwt 29 root root 1056768 Jun  6 14:06 /tmp
hacker@dojo:~$

最后的 t 是粘滞位(sticky bit)。 粘滞位让目录中的文件只能由其所有者重命名或删除。 它正是为防范这种攻击而设计的! 本挑战的问题就在于,zardus 没有为 /tmp/collab 设置粘滞位。 在这个具体场景中,以下操作就能堵住漏洞:

zardus@dojo:~$ chmod +t /tmp/collab

当然,所有人可写的目录这类共享资源仍然可能存在危险。 之后学习绿带课程中的“竞争条件”时,你会看到这类资源引发安全问题的多种方式!

可怜的 zardus,已经被你攻破了好几次。 不过他终于学聪明了,把主目录保护好了! 这就结束了吗?

还没有! 一台电脑上有多个账户时,人们常常忽略一个问题:自己的命令调用会泄露哪些数据。 还记得运行 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:~$

如果某个命令的参数恰好包含敏感信息,例如 flag 或密码,会怎样? 这种情况确实会发生。同一台机器上的恶意用户,或其他能列出该机器进程的人,就能窃取并利用这些数据!

本挑战就来探索这个问题。 zardus 使用了一个自动化脚本,并把账户密码作为参数传给它。 zardus 还被允许使用 sudo(因此也能运行 sudo cat /flag!)。 窃取密码,登录 zardus 的账户(回想一下 su 命令,你在“理清用户”模块中介绍过),然后拿到 flag!

即使没有明显犯错,用户也可能在无意中暴露自己。 例如,普通用户主目录中的很多文件默认所有人可读,但这些文件又经常用来存储敏感信息。 信不信由你,如果不主动修改权限,你的 .bashrc 就是所有人可读的!

hacker@dojo:~$ ls -l ~/.bashrc
-rw-r--r-- 1 hacker hacker 148 Jun  7 05:56 /home/hacker/.bashrc
hacker@dojo:~$

你可能会想:“至少默认不是所有人可写嘛!” 但即使只是所有人可读,也会带来风险。 由于 shell 启动时会执行 .bashrc,人们通常把需要自定义的环境变量初始化设置放在这里。 大多数时候只是 PATH 这样的普通配置,但有时也会为了方便使用,把 API 密钥存放在里面。 例如,本挑战中:

zardus@dojo:~$ echo "FLAG_GETTER_API_KEY=sk-XXXYYYZZZ" > ~/.bashrc

这样,zardus 就能很方便地引用 API 密钥。 本关中,用户可以用有效的 API 密钥获取 flag:

zardus@dojo:~$ flag_getter --key $FLAG_GETTER_API_KEY
Correct API key! Do you want me to print the key (y/n)? y
pwn.college{HACKED}
zardus@dojo:~$

自然,zardus 把他的密钥保存在 .bashrc 中。 你能窃取密钥并拿到 flag 吗?


注意: 拿到 API 密钥后,直接以 flag_getter 命令获取 flag,使用的身份是 hacker 用户。 本挑战的 /challenge/victim 只是为了营造场景,你不需要运行它。


30天排行榜:

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

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