乐趣区

关于python:黑客练手入门-pwnablekr幼儿瓶01fd

[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 小站

退出移动版