前些日子,朋友给我推荐了一个网站,上面可以做跟渗透有关的题。正热衷于此苦于不得其门而入的我很高兴地入坑了。
一开始我做的题是vortex,这个系列的题是跟缓冲区溢出有关的,难度相对较大,做得我苦不堪言。当终于在第四道题上卡死,不知道自己错在哪儿。干脆去别的题目上消遣一下找找手感。
目标转向了,推荐的入门题,bandit。
注:这些题的形式基本相同,通过ssh和给定的用户名密码连接到一个服务器上,再根据所有的资源和它给出的提示,尝试获得下一个等级的密码(用户名即为bandit+level)。服务器是linux系统,因此做题需要对linux有一定的了解。
Bandit这套题主要考验的是对linux bash以及各种工具,命令的灵活运用。
Bandit Level 0
Level Goal
The goal of this level is for you to log into the game using SSH. The host to which you need to connect is bandit.labs.overthewire.org. The username isbandit0 and the password is bandit0. Once logged in, go to the Level 1 page to find out how to beat Level 1.
正如同题目字面意思所说,只要用ssh连接到给出的域名上就好了。用户名密码都已经给出。
$ ssh [email protected]
等到提示要输入密码时,输入bandit0。本人第一次输入时犯傻,纳闷输入为何无反应一点都不显示。直到我想起linux的密码输入从来都是没有回显的……
Bandit Level 0 → Level 1
Level Goal
The password for the next level is stored in a file called readme located in the home directory. Use this password to log into bandit1 using SSH. Whenever you find a password for a level, use SSH to log into that level and continue the game.
由于是入门题目,相当简单,只要从home下读出readme的内容即可。
$ cat readme
就这么简单,就获得了下一个等级的密码。
Bandit Level 1 → Level 2
Level Goal
The password for the next level is stored in a file called - located in the home directory
这道题同样没什么难度。即从home中读出一个文件名为“-”的文件。了解linux的人应该知道,在bash中,“-”即短杠会被解析为stdin,也就是标准输入流。我一开始尝试:
$ cat -
这条命令会等待你从终端输入字符,然后回显你输入的任何字符,直到输入eof (Ctrl-D)为止。如何摆脱bash的转义呢?我使用了一个很简单的方法:
$ cat ./-
在linux中“.”表示当前目录,紧跟其后的短杆就不会被解析为stdin了。于是就顺利读出了下一个等级的密码。
Bandit Level 2 → Level 3
Level Goal
The password for the next level is stored in a file called spaces in this filename located in the home directory
仍然是一个特殊的文件名,这道题可能比上一道还要简单一些。得益于bash的自动补全机制,当输入:
$ cat ./sp
按下tab键,这条命令就会自动补全为:
$ cat ./space\ in \this \filename
可以看到自动对其中的空格进行了转义。
Bandit Level 3 → Level 4
Level Goal
The password for the next level is stored in a hidden file in the inhere directory.
完成它很简单,只要你知道,linux表示隐藏文件的方式,就是在文件名的前面加上“.”,这样执行ls的时候就不会列出这个文件了。
$ cat inhere/.
如上题,按下tab就帮你补全了。
Bandit Level 4 → Level 5
Level Goal
The password for the next level is stored in the only human-readable file in the inhere directory. Tip: if your terminal is messed up, try the “reset” command.
当进入inhere文件夹,你会找到很多个文件,其中大部分用cat读出之后都是乱码。你只要找到唯一一个非乱码的文件,它就是你需要的密码了。
Bandit Level 5 → Level 6
Level Goal
The password for the next level is stored in a file somewhere under the inhere directory and has all of the following properties: - human-readable - 1033 bytes in size - not executable
由于inhere文件夹下的文件并不是很多,并不需要使用所有的条件就可以找到。
$ du | grep 1033
du命令的用处是列出文件夹下的各文件和文件夹的大小,而grep的作用是在一段文本中寻找指定的字符串。“|”符号,即管道,用以将前一个命令的输入不经stdout(即屏幕终端的输出)直接作为下一个命令的输入。这条组合命令的用处就是列出该文件夹下所有文件的大小并找到包含1033的一行。通过目测很快能够确定目标。
Bandit Level 6 → Level 7
Level Goal
The password for the next level is stored somewhere on the server and has all of the following properties: - owned by user bandit7 - owned by group bandit6 - 33 bytes in size
这次终于变成在海量的文件中找符合条件的了~启用find命令:
$ find / -user ‘bandit7’ -group ‘bandit6’ -size 33c | grep -v denied
第一个参数“/”表示搜索从根目录开始,下两个参数指明搜索文件的所属用户,再下两个参数指明文件的所属组,最后两个参数指明大小为33byte(c表明单位为byte,b表示单位为block,即512byte,更多参考man page)。
此时会跳一大堆的permission denied,这是因为你的用户并不能够访问所有的文件夹。此时只要在这里面找出唯一一个没有denied的就好了。于是通过管道用grep进行筛选,-v表示选择不包含此字符串的。
Bandit Level 7 → Level 8
Level Goal
The password for the next level is stored in the file data.txt next to the word millionth
一个有很多内容的文件,但是只要搜索一下就好了。
$ cat data.txt | grep millionth
密码到手。
Bandit Level 8 → Level 9
Level Goal
The password for the next level is stored in the file data.txt and is the only line of text that occurs only once
这道题就需要更复杂一些的文本处理,好在linux提供了相当丰富的文本处理工具。这里需要用到两个:sort和uniq,前者用于将文件排序,后者用于处理相邻的重复情况。
$ cat data.txt | sort | uniq -u
还是用管道技术对文件进行一层层处理,先使用sort排序使相同的行被放到一起,之后使用uniq -u仅保留不重复的项,如此就获得了密码。
Bandit Level 9 → Level 10
Level Goal
The password for the next level is stored in the file data.txt among of few lines of human-readable strings starting with ‘=’ characters.
这道题目很有意思,从一个满是乱码的文件中找出可打印字符组成的行。在做它之前我不知道有这么一个命令:strings。专门用来找出可打印的行。尝试用grep却发现报错。当了解这个命令,这道题目就简单了。
$ cat ./data.txt | strings | grep =
Bandit Level 10 → Level 11
Level Goal
The password for the next level is stored in the file data.txt, which contains base64 encoded data
Linux源生提供了各种编码解码工具,例如此处的base64。
$ cat data.txt | base64 -d
Bandit Level 11 → Level 12
Level Goal
The password for the next level is stored in the file data.txt, where all lowercase (a-z) and uppercase (A-Z) letters have been rotated by 13 positions
仍旧是一道文本处理的题目,可以用更强大的工具sed解决,也可以如我一样用tr。tr用指定的方法替换原文本当中的字符。
$ cat data.txt | tr [a-z] [n-za-m] | tr [A-Z][N-ZA-M]
此处使用的语法很近似于正则表达式。不过生成的是一个字符序列而非集合。两次分别处理大小写字母。
Bandit Level 12 → Level 13
Level Goal
The password for the next level is stored in the file data.txt, which is a hexdump of a file that has been repeatedly compressed. For this level it may be useful to create a directory under /tmp in which you can work using mkdir. For example: mkdir /tmp/myname123. Then copy the datafile using cp, and rename it using mv (read the manpages!)
这道题目是做下来最让我觉得蛋疼的。所给的文件是一个xxd导出的文本,原本是一个压缩文件,用xxd读取其十六进制值后获得了现在的文本。于是第一步是将其还原为压缩文件:
$ xxd -r data.txt data
这仅仅只是一个开始,接下来每一步需要做的事情是,根据文件头判断它是什么类型的压缩文件。Linux常见的文件包有三种,gnuzip压缩的.gz文件;bzip2压缩的.bz2文件;tar打包的.tar文件。
$ xxd data | head
查看其文件头,0x1f8b开头的为gzip文件,注意先将文件名重命名出.gz后缀
$ gzip -d data.gz
若文件头为0x425a则为bz2文件,重命名为.bz2
$bzip2 -d data.bz2
否则为tar文件,重命名为.tar
$ tar -xvf data.tar
如此循环重复若干次,终于有一次你会发现自己解压出来的文件是密码。
Bandit Level 13 → Level 14
Level Goal
The password for the next level is stored in /etc/bandit_pass/bandit14 and can only be read by user bandit14. For this level, you don’t get the next password, but you get a private SSH key that can be used to log into the next level. \ Note: localhost is a hostname that refers to the machine you are working on
在主文件夹内,你会发现有一个叫做ssh_private的文件,里面存放的是一个ssh私钥,其公钥已经在服务器上登记,使用它可以直接以bandit14的身份登陆。
$ ssh -i ./ssh_private [email protected]
使用时需要注意一点,如果ssh_private的访问权限为默认的,即group和other都有读权限,会提示该文件无法使用,这是安全性的考虑,需要先修改权限:
$ chmod 600 ./ssh_private
之后就可以正常登陆。
Bandit Level 14 → Level 15
Level Goal
The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.
这道题考验的是nc这个被誉为瑞士军刀的工具的使用。
$ nc localhost 30000
这个命令的作用是建立一个连接到本地30000端口的tcp连接,之后把你在/etc/bandit_pass/bandit14中获得的密码输入,绑定在30000端口上的服务就会返回新的密码了。
nc还有很多简单实用有好玩的用法,感兴趣的人可以去研究一下
Bandit Level 15 → Level 16
Level Goal
The password for the next level can be retrieved by submitting the password of the current level to port 30001 on localhost using SSL encryption.
Helpful note: Getting “HEARTBEATING” and “Read R BLOCK”? Use -quiet and read the “CONNECTED COMMANDS” section in the manpage. Next to ‘R’ and ‘Q’, the ‘B’ command also works in this version of that command…
一开始没有想明白,该怎么通过ssl连接,在nc和ssh上花了一些时间。之后发现了openssl这个功能丰富的ssl命令。其中的s_client模块可以帮助我们作为客户端与ssl服务器进行交互。
$ openssl s_client -connect localhost:30001 -quiet
-quiet用以关闭session和证书的信息,同时打开-ign_eof这个选项。前者可简化显示的界面,后者则保证在输入完成后不是立即断开连接,否则无法看到回显的下一个等级的密码。
Bandit Level 16 → Level 17
Level Goal
The password for the next level can be retrieved by submitting the password of the current level to a port on localhost in the range 31000 to 32000. First find out which of these ports have a server listening on them. Then find out which of those speak SSL and which don’t. There is only 1 server that will give the next password, the others will simply send back to you whatever you send to it.
与上一关雷同,不同之处在于需要从1001个端口当中找出正确的那一个。这就用到了强大的网络扫描工具nmap。指定地址和端口范围,让其进行扫描即可。
$ nmap localhost -p 31000-32000
输出的便仅有的几个打开的端口。数量不多,因此可以手动检查。
$ openssl s_client -connect localhost:30001 -quiet
仍是使用这条命令,不过端口得换成相应的扫描结果,逐个检查。分三种情况,一是连接不上的,二是连接上了但输入之后只会回显相同的密码的,剩下的仅有的一个端口才会给我们正确的结果。
Bandit Level 17 → Level 18
Level Goal
There are 2 files in the homedirectory: passwords.old and passwords.new. The password for the next level is in passwords.new and is the only line that has been changed between passwords.old and passwords.new
关卡下面的推荐命令是cat,grep与ls。但比较两个文件的异同无疑有着更好的选择,那就是diff命令。
$ diff passwords.old passwords.new
输出结果是两个文件当中不同的行,注意别弄错哪个是new文件中的即可。
Bandit Level 18 → Level 19
Level Goal
The password for the next level is stored in a file readme in the homedirectory. Unfortunately, someone has modified .bashrc to log you out when you log in with SSH.
用上一关的密码登陆进去会给你一个哭笑不得的结果,你会发现自己直接登出。因此需要在连接上的同时执行命令,而不能等着打开shell才输入。有两种方法,一是通过ssh命令,在打开shell之前直接执行命令并获得输出:
$ ssh [email protected] 'cat ./readme'
虽然shell仍然被立刻关闭,但不妨碍作为参数的命令已经执行,我们已经获得了想要的内容。
另一种是通过scp命令。
$ scp [email protected]:.~/readme ./readme
将远程主机上的文件复制到本地。同样不经过shell。
Bandit Level 19 → Level 20
Level Goal
To gain access to the next level, you should use the setuid binary in the homedirectory. Execute it without arguments to find out how to use it. The password for this level can be found in the usual place (/etc/bandit_pass), after you have used to setuid binary.
这一关涉及到的是linux权限的相关知识。/etc/bandit_pass/bandit20的所有者为bandit20,而其权限设置使得只有自身和bandit20这个group的成员能够读取。
setuid这个文件的拥有者为bandit20,而bandit19,也就是当前登录用户有执行的权限。而该文件有s权限,即setuid权限。能够在程序中调用setuid()系统调用,将自身的suid改成与euid相同,也就是在运行中作为bandit20执行命令。
对于手头的这个文件,只要将欲执行的命令作为参数传入即可。
这样的文件如果能够通过一定方式执行命令甚至于获得shell,是渗透人员理想的提升权限途径。
$ ./setuid cat /etc/bandit_pass/bandit20
Bandit Level 20 → Level 21
Level Goal
There is a setuid binary in the homedirectory that does the following: it makes a connection to localhost on the port you specify as a commandline argument. It then reads a line of text from the connection and compares it to the password in the previous level (bandit20). If the password is correct, it will transmit the password for the next level (bandit21).
NOTE: To beat this level, you need to login twice: once to run the setuid command, and once to start a network daemon to which the setuid will connect.
NOTE 2: Try connecting to your own network daemon to see if it works as you think
这道题所给的程序的行为是:连接到localhost的指定端口,读取一行。如果这行与bandit20的密码相同,那就向这个连接写入新的密码。
在这里我们又用到了nc这个强大轻巧的工具。
首先登陆打开第一个shell,运行:
$ nc -l 12345
表明对12345这个端口进行监听。相当于在这个端口上架设了一个简易的服务器。
再打开第二个shell,运行:
$ ./suconnect
然后在第一个shell的nc的交互环境中输入密码,如果正确,就能收到新的密码。
Bandit Level 21 → Level 22
Level Goal
A program is running automatically at regular intervals from cron, the -based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
这关开始是一系列关于cron和shell脚本的内容。cron是一个定时工具,定时执行指定的脚本内容。而题目中/etc/cron.d就是指定的脚本存放的文件夹。查看这个文件夹就可以发现,里面有一个明显是我们要找的:
$ cat /etc/cron.d/cronjob_bandit22
* * * * * bandit22 /usr/bin/cronjob_y.sh &> /dev/null
前面的五个“*”分别对应的是:分,时,日,月,周。填上“*”而不是具体的数字表明每分钟都会执行一次。
$ cat /usr/bin/cronjob_bandit22.sh
#!/bin/bash
chmod 644 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
cat /etc/bandit_pass/bandit22 > /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
这个每分钟都执行的脚本的内容如上,把我们所需要的密码复制进/tmp目录下的一个文件中。将其读出即为我们需要的密码。
$ cat /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv
Bandit Level 22 → Level 23
Level Goal
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
NOTE: Looking at shell scripts written by other people is a very useful skill. The script for this level is intentionally made easy to read. If you are having problems understanding what it does, try executing it to see the debug information it prints.
同上找到我们需要的文件:
$ cat /etc/cron.d/cronjob_bandit23
* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null
$ cat /usr/bin//cronjob_bandit23.sh
#!/bin/bash
myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"
cat /etc/bandit_pass/$myname > /tmp/$mytarget
$() 是bash的转义符号,表示执行括号中的命令并使用其输出值。whoami命令获得的是当前用户。而md5sum对输入进行hash获得其md5值。最后的cut整理格式仅保留md5部分。
理解了上面这个脚本的内容之后就简单了。密码在/tmp中保存的文件名可以通过md5sum计算,如此就能获得密码了。
$ cat /tmp/`echo I am user bandit23 | md5sum`
其中``是反引号而非单引号,其起到的作用与$()是相同的。
Bandit Level 23 → Level 24
Level Goal
A program is running automatically at regular intervals from cron, the time-based job scheduler. Look in /etc/cron.d/ for the configuration and see what command is being executed.
NOTE: This level requires you to create your own first shell-script. This is a very big step and you should be proud of yourself when you beat this level!
NOTE 2: Keep in mind that your shell script is removed once executed, so you may want to keep a copy around…
这道题需要自己写shellscript来完成。首先按照与上面相同的步骤:
$ cat /etc/cron.d/cronjob_bandit24
* * * * * bandit24 /usr/bin/cronjob_bandit24.sh &> /dev/null
$ cat /usr/bin/cronjob_bandit24.sh
#!/bin/bash
myname=$(whoami)
cd /var/spool/$myname
echo "Executing and deleting all scripts in /var/spool/$myname:"
for i in *;
do
echo "Handling $i"
./$i
rm -f $i
done
这段被定时执行脚本的内容是,遍历/var/spool/bandit24文件夹,并执行里面所有的可执行文件。故将所欲执行的脚本放入该文件夹即可。最后别忘了改变它的权限使其成为可执行程序。
$ echo -e '#!/bin/sh \ncat /etc/bandit_pass/bandit24 > /tmp/thenameyoulike' > /var/spool/bandit && chmod +x /var/spool/bandit
稍等一分钟,就可以从指定的文件中读到想要的密码了。
需要注意的是,用于写入的这个文件必须是一个bandit24拥有写权限的文件,我一开始因为指定了一个已经存在但没有写权限的文件,挣扎了很久都读不出结果。而/dev/null吃掉了所有的错误提示,更加需要自己的谨慎。
Bandit Level 24 → Level 25
At this moment, level 25 does not exist yet.
完成了~
完成这套题一共只用了几个小时,加起来可能还不到vortex当中一道难题花的时间,但也颇有心得。linux预装的工具多如牛毛,其中很多甚至不曾听说,但真到用到的时候,不得不赞一声设计得实在是好。处理这样的问题,在命令行中远比图形界面简单,而shellscript的强大更是让命令行的功能不亚于一门编程语言,这也是linux的部分魅力所在吧!