题目:

​ 该题是第一道题,通过描述来看是和Linux描述符相关的题目,如下:

​ 首先使用ssh远程链接linux服务器,括号中为密码guest,链接后如下:

​ 查看文件,其中用于登录的fd用户,对于flag并无任何读写权限,而可以可能到fd对于fd.c具有读取权限,所以我们可以查看fd.c的代码进行漏洞利用来获取flag信息:

​ fd.c代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;

}

分析:

  1. fd通过参数(argv[1])-0x1234来计算得到
  2. fd控制read读取到buf的内容,read函数限定了向buf中写入的内容为32字节,没有利用的可能
  3. 通过buf的内容和”LERMEWIN”做比较来cat flag得到flag内容,这里存在一个问题,刚才看到权限的时候,flag并没有权限去读取,为什么运行fd之后,就可以cat flag了。这是应为fd和flag都有着同个所有用户fd_pwn,当fd运行起来后,其本身对应的权限就临时会变为fd_pwn,而fd_pwn对于flag是有读取权限的,所以就可以cat flag了。

文件描述符

参考Linux 下 C/C++ 输入输出

​ 观察代码,这里在分析前需要先了解点Linux下文件描述符的知识,在Linux下启动一个程序时,会打开三个文件描述符0、1、2,Linux内核会管理文件描述符及其背后的文件是什么,所以可以使用系统调用read/write往0、1、2这三个文件描述符里读取/写入内容,这三个文件描述符一般都会链接到终端屏幕上。可以在终端数如tty命令来查看自己终端所绑定的输出位置,也可以使用ls -l /proc/进程pid/fd来查看具体进程打开的所有fd,可以看到很多程序的并没有链接到终端中,而是连接到了文件/套接字中。单无论是输入/输出, 其最终都是要通过系统调用, 读取 0 号 fd, 或者写入 1/2 号 fd。

​ 在C标准输入输出中,为了尽可能不进行系统调用,大佬们想出了缓存,也就是常说的stdinstdoutstderr,这三个东西在C标准库中实现,实际上对应的是FILE*,分别指向了C标准库种得_IO_2_1_stdin_, _IO_2_1_stdout_, _IO_2_1_stderr_这三个FILE,这三个FILE主要就是用来负责管理缓存然后在需要的时候进行read/write系统调用,得到新的输入或者进行真正的输出。

继续分析:

​ 了解了文件描述符的知识后,我们继续看fd程序,可以发现要拿到flag的前提是buf内容为LETEMEWIN,而我们唯一能控制输入的地方在控制台,所以read用到的fd就需要代表终端才能将需要的内容写入buf。所以就要使得fd为stdin也就是0,那么第一个参数argv[1]就要为0x1234也就是字符串”4006”。

​ 分析完毕后进行验证,成功得到flg: