pwnable.kr记录

来源:互联网 发布:java 多个泛型 编辑:程序博客网 时间:2024/06/05 21:55

pwnable.kr记录

fd

我的思考过程:

  • 首先pwd(查看当前目录),在/home/fd下;
  • 然后ls查看所有文件,于是发现有flag;试图打开,没有权限;而且文件是在远程服务器,自己不能改权限;于是打开fd.c查看代码,其中有可以打开flag的方式,但是要了解read()函数的用法
  • 疑惑于文件描述符fd,题目提示学习file io,了解之后只有fd为0、1、2三种情况,并不知道那个flag文件的文件描述符怎么计算啊?于是陷入……
  • 看了解题视频;无知是罪

解题:

  • 使用whoami命令可以查看操作用户
  • ls -l可以查看详细的文件内容,可以看到各个文件的权限,可以看到fd文件是可执行文件;fd.c只读;flag对用户没有权限
  • 那么打开fd.c查看内部代码的含义;使用cat fd.c
  • 其中令fd=atoi(argv[1])-0x1234=0;含义为fd这个文件描述符是标准输入,即之后可以利用这个fd从终端读入字符;并且字符将读入到buf中;之后与“LETMEWIN”进行比较,相等即可得到flag;这也提示了应该在终端输入”LETMEWIN”
  • 于是,终端执行:./fd 4660(4660是0x1234)
  • 此时函数在等待标准输入“LETMEWIN”,于是输入并回车
  • 就可以看到flag:mommy! I think I know what a file descriptor is!!

我的收获:

  1. main函数参数含义 此文中提到main函数的第三个变量中主要放的是环境变量;第一个参数argc表示参数的个数;第二个参数argv[]数组中存放各个参数,其中argv[0]是执行函数的名字,此题中即为“fd.c”
  2. 文件 I/O read函数中的文件描述符fd的使用;常用的fd是由open函数返回得到的,一般格式为int fd=open(const char *pathname, int flags);而此题中并不需要从其他文件中读取内容,而是可以利用标准输入给buf赋值
  3. ls -l中各个参数的含义 第一列是user;group;guest的权限,并且如果是文件,此列前边有一个横杠;第二列是文件的数量,如果是文件则为1,如果是目录则为目录下文件的个数;第三列是文件或目录的拥有者;第四列是所属的组;第五列是文件大小;第六列创建日期;第七列是文件名
  4. cat filename即可在终端下显示文件内容
  5. 在windows的cmd下不能连接ssh?

col

#include <stdio.h>#include <string.h>unsigned long hashcode = 0x21DD09EC;unsigned long check_password(const char* p){        int* ip = (int*)p;        int i;        int res=0;        for(i=0; i<5; i++){                res += ip[i];        }        return res;}int main(int argc, char* argv[]){        if(argc<2){                printf("usage : %s [passcode]\n", argv[0]);                return 0;        }        if(strlen(argv[1]) != 20){                printf("passcode length should be 20 bytes\n");                return 0;        }        if(hashcode == check_password( argv[1] )){                system("/bin/cat flag");                return 0;        }        else                printf("wrong passcode.\n");        return 0;}

我的思考过程

  • 在上一题的经验下,了解到首先查看目录下各个文件的权限,这样有利于提高效率;然后打开col.c查看源代码,如上;
    这里写图片描述
  • 分析了源代码之后,发现通过对argv[1]进行处理后需要等于hashcode
  • 分析check_password()函数,函数参数为char类型指针,但是下面代码中使用int类型指针进行操作;这里需要注意的是char在内存中占1byte(8bit);int在内存中占4byte(32bit);又通过下边的提示,可以得到,p应该是指向一个20bytes的内容/然后这20bytes的内容分成5组,5组相加后需要等于hashcode
  • 至此,思路都很明晰。但是0x21DD09EC/5=113626824.8;这怎么能只有4bytes呢?于是卡在这里了

解题

  • 继续上述思路,去看了别人的writeup,原来是没有彻底搞清楚byte和bit的关系;现在就需要用5个32bit之和构造已有的hashcode

  • hex(113626824)=0x6c5cec8(4次)

  • hex(113626828)=0x6c5cecc

  • 那么输入上述内容即可;但是这里要注意的是大小端存储 的事情:

  • 小端:较高的有效字节存放在较高的的存储器地址,较低的有效字节存放在较低的存储器地址。大端:较高的有效字节存放在较低的存储器地址,较低的有效字节存放在较高的存储器地址。

  • 此外,我们的输入是从低字节向高地址写入的,系统是小端存储;所以(0xc8/0xce/0xc5/0x06)x4 (0xcc/0xce/0xc5/0x06)

*这里写图片描述
*

  • ./col $(perl -e 'print "\xc8\xce\xc5\x06"x4 . "\xcc\xce\xc5\x06"')这句话我还不会写
  • daddy! I just managed to create a hash collision :)

我的收获

  • 大小端存储 :小端:较高的有效字节存放在较高的的存储器地址,较低的有效字节存放在较低的存储器地址。大端:较高的有效字节存放在较低的存储器地址,较低的有效字节存放在较高的存储器地址。
  • 代码中的argv[1]是从低地址向高地址读取内容;那么如果是按照小端存储的话,第一个字节应该是最低位;因此我们在给argv[1]赋值时需要按照 Little endian ,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放据的低位字节到高位字节 这样的顺序
  • byte&&bit
  • 各个进制之间的转换-python
原创粉丝点击