Level 04 —— 绕过限制获得token

详情:

这一关需要读取令牌文件,但代码限制了可读取的文件数量。想办法绕过它吧。要执行此级别,请以 level04 帐户和密码登录。此级别的文件位于 /home/flag04。flag04程序源代码如下:

#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);
}

Solution:

在/home/flag04中有两个文件,一个是可执行文件,一个是token文本文件。要求绕过flag04的限制来读出token的内容,这个token就是账号flag04的登录密码。

我们可以通过ls -al看到,token文件的权限是-rw———-,所属用户是flag04,也就是说,除root权限外只有flag04这个用户可以对它进行读写操作。

image-20250602205546699

而flag04这个可执行程序的所属用户组是level04,而我们的用户level04也是属于用户组level04的。而用户组对flag04这个程序只有x(执行)权限,所以只有通过flag04下手了。仔细看flag04源代码,找出问题:

注意代码第23行:

fd = open(argv[1], O_RDONLY);
if(fd == -1) {
err(EXIT_FAILURE, "Unable to open %s", argv[1]);
}

🧠 分析逐行含义

🔹 第 1 行:

>fd = open(argv[1], O_RDONLY);
  • open() 是一个系统调用,用来打开一个文件

  • argv[1] 是命令行参数,表示用户运行程序时传入的第一个参数,即文件路径。

  • O_RDONLY 是标志,表示以只读方式打开

  • fd 是返回的文件描述符,如果打开成功,会是一个大于等于 0 的整数;否则会返回 -1

🔹 第 2-4 行:

>if(fd == -1) {
err(EXIT_FAILURE, "Unable to open %s", argv[1]);
>}
  • 如果 open() 返回 -1,说明文件打开失败

  • err() 是一个标准库函数(在 <err.h> 中),用于打印错误并退出程序。

  • EXIT_FAILURE 是退出状态码(值通常为 1),表示失败。

  • "Unable to open %s" 是错误信息模板,%s 会被 argv[1] 替换(即你试图打开的文件名)。

  • err() 会自动在你提供的消息后加上系统错误原因(来自 errno)

它是对参数argv[1]进行open操作,argv[1]输入的是文件名,但是这个文件名不能含有”token”字符串,因为在代码18行进行了限制,如果文件名中包含了”token”字符串,程序会直接提示“You may not access token”,并且退出执行。

🧠 分析

🔹 strstr(argv[1], "token") != NULL

  • strstr(a, b) 是 C 标准库函数,用于在字符串 a 中查找子串 b

  • 如果找到了,返回第一次出现的位置的指针;如果找不到,返回 NULL

  • 所以 strstr(argv[1], "token") != NULL 意思是:argv[1] 中包含字符串 "token"

问题在与:strstr函数,它会找出指定的关键字(这里是token)在字符串中第一次出现的位置,如果没有找到,就返回NULL。因此,只要我们保证在文件名里不包含“token”字符串就可以了。虽然我们没有权限更改token文件的文件名,但是我们可以创造一个软链接,指向/home/flag04/token,再执行flag04:

image-20250602212435747

通过执行flag04,然后传参数token读出了token的值,这个token就是flag04用户的密码,登录并执行getflag。

image-20250602212826477