PWNABLE学习笔记【updating】

PWNABLE学习笔记 [updating]

这是我学习system exploit时, 在pwnable上做题的一个记录, 感谢这个平台提供的练习, 帮助我入门学习。

PWNABLE:Link

WriteUp(14 challenges): Link

Challenge 1: [fd]

题目文件:文件fd.c , 文件fd(fd.c编译后的可执行二进制文件), 文件flag

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;

}

题目要点

作为第一个题目,主要的知识点是让我们掌握C语言的文件IO标识符,open和read(题目中)。

关注题目中的以下几个要点:

  • 主函数中的参数

    • argc 保存的是命令行中总的参数个数,并且包含程序名。 e.g. ./test 1 2 3 4,那么,argc的值即为 5
    • agrv[] 数组中保存传入的参数,参数可以是多个的,e.g. ./test 1 2 3,那个argv[0] == 1, argv[1] == 2, argv[2] == 3
    • envp[] 数组中保存系统的环境变量,操作系统运行程序时,通过envp参数将系统环境变量传递给程序
  • atoi() 函数

    • 该函数(atoi, ascii to integer)会将字符串转化为整数
    • 函数会扫描输入的参数,跳过空白字符(空格、tab缩进等),将数字的字符转为整型,如果无法有效转换(字符串以英文字母开头),则会返回0
    • 注意,函数会保留+-符号,但会舍弃小数点及后面的数字
  • read() 函数

    • ssize_t read (int fd, void *buf, size_t count);

    • 功能:用于从文件描述符(fd, file description)对应的文件读取数据(从打开的设备或文件中读取数据,也可以为终端上的数据)

    • 在UNIX/Linux平台上,fd有三个(fd = 0, fd = 1; fd = 2),分别对应控制台(Console)的标准输入,标准输出,标准错误输出

    • e.g. 在read(0,buf,32) 中,fd=0,表示进行标准输入(控制台,键盘输入),读取最多32个字节到buf中

    • 常规的用途是配合open()函数,实现文件的读取

1
2
int fp = open("./test.txt", O_RDONLY); //只读模式打开文件
res = read(fp, buffer, 60);
  • strcmp() 函数

    • int strcmp(const char *s1, const char *s2);
    • 功能:比较字符串s1与字符串s2,区分大小写,相同返回0,不同则返回s1与s2的差值
  • system() 函数

    • int system(char *command);
    • 功能:发出一个terminal命令
  • 补充:open() 函数

    • int open(const char *path, int oflags,mode_t mode);

    • 功能:用于建立了一条到文件或设备的访问路径,配合read()等函数,实现文件的读写和设备的操作

重要补充:文件权限

在题目中,我们以fd的用户身份登入,我们的操作都是受身份限制的,因此我们需要对题目中的文件进行权限的识别。使用groups fd判断fd用户所属的组为fd。使用命令ls -l可以查看当年目录下的所有文件的权限:

1
2
3
-r-sr-x--- 1 fd_pwn fd   7322 Jun 11  2014 fd
-rw-r--r-- 1 root root 418 Jun 11 2014 fd.c
-r--r----- 1 fd_pwn root 50 Jun 11 2014 flag

依次分析:

  • 权限:前面由连字符和字母组成的部分,例如-r-sr-x---, 该部分由四个部分组成,共占10位(1 + 3 + 3 + 3)

    • 类型 所有者权限 所属组权限 其他人权限
      - r - s r - x - - -
      • 类型部分

        - 代表文件

        d 代表目录

        l 代表链接

        c 代表字符型设备

        b 代表块设备

        n 代表网络设备

      • 权限部分

        - 权限为空

        r 可读

        w 可写

        x 可执行

        s 当执行该文件时将具有该文件所有者的权限,注意这个,比较特殊

  • 所有者:例如fd_pwn,表示fd文件的所有者是fd_pwn

    • 分析第一条,可以发现fd和目标文件flag是同一个所有者
  • 所属组:例如fd, 表示fd文件所属组是fd,同一个组中的有不同的用户/角色

    • 继续分析第一条,可以发现fd和flag是不是同一个组,flag属于root组
  • 文件大小

  • 创建事件

  • 文件名称


综合以上的条件,我们分析目标文件flag,可以得出:

  • flag是文件
  • flag的权限为:所有者可读;所属组可读;其他人无权限
  • flag的所有者为:fd_pwn
  • flag的所属组为:root

分析我们可以利用的二进制可执行文件fd可以发现:

  • fd是文件

  • fd的权限为:所有者可读,并且当执行该文件时将具有该文件所有者的权限;所属组可读可执行;其他人无权限

  • fd的所有者为fd_pwn

  • fd的所有组为fd,注意,这里很重要, 可以发现我们登入使用的用户fd属于用户组fd,与该文件相同。结合文件权限中表明的,所属组可以执行该文件,并且执行该文件时可以获取该文件所有者的权限,而文件fd与文件flag属于同一个所有者fd_pwn, 文件flag的所有者可以读取文件flag。

    那么,我们的用户fd就可以执行文件fd,暂时获取所有者fd_pwn的权限,进而可以读取文件flag

总结一下,在Linux/Unix中一切皆文件,弄清楚文件的权限,我们的角色,才可以明确我们想进行的操作,一切从实际出发,而思维又要高于实际。

题目总结

这是第一道题目,主要考察文件IO的知识点。在分析过程中,我们不经要去看程序代码,更要注意理清文件权限和我们的角色,这样才能更加明确总体的思路。

在做题或者分析的过程中,我们的第一步不是直接去分析程序文件,而是要查看当前用户角色和文件权限,明确自己可以做什么,不可以做什么,这会更好地帮助我们组织后面的操作。