美文网首页
黑客练手入门| pwnable.kr—幼儿瓶—01:fd

黑客练手入门| pwnable.kr—幼儿瓶—01:fd

作者: Young先生 | 来源:发表于2021-02-03 22:04 被阅读0次

    [TOC]

    前言

    担心有人不知道pwnable.kr是什么,所以觉得有必要简单介绍一下它。

    pwnable.kr介绍

    pwnable.kr是一个非商业性的Wargame网站 ,它提供有关系统开发的各种pwn挑战。pwnable.kr的主要目的是'有趣'。并把每个挑战视为游戏。地址:http://pwnable.kr/

    该怎么玩

    每个挑战都有对应的标记文件(类似于CTF),您需要阅读该文件并提交给pwnable.kr以获得相应的分数。为了读取标志文件,您需要一些有关编程,逆向工程,漏洞利用,系统知识,密码学的技能。每个挑战都有作者的预期解决方案,但是,还有许多意外的解决方案。

    挑战分为四类:

    • 幼儿瓶:非常简单的挑战,都是一些简单的错误。
    • Rookiss:新手需要掌握的典型漏洞利用。
    • 怪诞:这些挑战是怪诞的,解决起来很痛苦,但获得Flag后,成就感满满。
    • 黑客的秘密:针对这些挑战的预期解决方案涉及特殊的黑客技术。

    幼儿瓶第一道题:fd

    0x00 问题描述

    Mommy! what is a file descriptor in Linux?

    • try to play the wargame your self but if you are ABSOLUTE beginner, follow this tutorial link:

    https://youtu.be/971eZhMHQQw

    ssh fd@pwnable.kr -p2222 (pw:guest)

    这道题名为fd(file descriptor,翻译过来就是文件描述符),顾名思义,其实考察的就是 Linux 的文件描述符的知识。

    0x01 源码分析

    连接到服务器上后,当前目录存放了几个文件:fd.c fd flag
    通过ls -l,我们可以查看文件权限,发现当前用户没有权限查看flag文件,然后我们就分析fd.c文件,是一段代码,内容如下:

    //fd.c
    #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;
    }
    

    从源代码中,我们可以看到关键一句在于通过第 2 个 if 语句的检查,如果 buf 变量的值为 LETMEWIN 字符串,那么就可以顺利打开 flag 文件。buf 是从哪里来呢?向上溯源,可以看到,buf 的值来源于 read 函数读进来的内容。

    C 语言中 read 函数的原型是:ssize_t read(int fd, void*buf, size_t count)。其中 fd 代表文件描述符,buf 为读出数据的缓冲区,count 是读取的字节数。也就是说,这句代码表示程序从文件描述符中读入数据并放到 buf 中。

    fd 的值应该是什么呢?通过搜索,查到如下描述:Linux 系统将所有设备都当作文件来处理,而 Linux 用文件描述符来标识每个文件对象。比如说,我们用键盘输入数据,用显示器阅读显示的数据,那么键盘输入就是一个文件对象,显示器输出也是一个文件对象。对于每个不同的文件对象,Linux 会用不同数字标识并加以区分。

    Linux 标准文件描述符是这样规定的:

    数字 0 表示 STDIN,即标准输入,也就是我们通过运行程序之后,在命令行输入的数据。

    数字 1 表示 STDOUT,即标准输出,也就是程序运行过程中,在终端显示的数据。

    数字 2 表示 STDERR,即标准错误输入,也就是程序运行时如果发生错误,导致不能正常退出时,终端上会显示的信息。

    在了解了这些知识以后,这道题就可以很顺利的解出了:我们只需要让 fd 的值等于 0,再通过终端命令行输入 LETMEWIN,就可以让 buf 的值等于我们输入的字符串,从而顺利通过 if 语句的检查。

    对着代码,向上溯源,可以看到另外一个关键语句:

    int fd = atoi( argv[1] ) - 0x1234;
    

    这一句定义了 fd 的值,其中 argv 是 main 函数的一个参数,再加上 argc 和 envp,表示程序运行时在命令行输入的命令参数。argc 是一个整型,表示参数的个数(程序文件名也算在内,所以 argc 至少值应该大于等于 1),argv 是一个指针数组,其元素个数是 argc,存放的是指向每一个参数的指针,所以 argv[1] 就表示程序运行的第二个命令参数(第一个命令参数是 argv[0],也就是程序名)。envp 是一个指针数组,指向系统的环境变量字符串,这里没有用到。

    所以,我们只需要让程序运行的第一个命令参数等于 0x1234 即可,转换成 10 进制的值是 4660。

    0x02 解题方法

    至此,解题思路就很明确了,终端输入如下:

    $ ./fd 4660
    LETMEWIN
    good job :)
    mommy! I think I know what a file descriptor is!!
    

    0x03 知识点总结

    本题考察了三个知识点:

    1. Linux 下的文件描述符 fd 的定义和用法;
    2. C 语言中 read 函数的原型和使用方法;
    3. main 函数三个参数 argc, argv 和 envp 的含义。

    本文首发于BigYoung小站

    相关文章

      网友评论

          本文标题:黑客练手入门| pwnable.kr—幼儿瓶—01:fd

          本文链接:https://www.haomeiwen.com/subject/xstvtltx.html