今天咱们来继续玩 pwnable.kr
pwnable.kr collision
image同样的,我们远程连接上服务器,然后查看一下当前目录中的文件。
$ ls
col col.c flag
和第一题一样,这里我们直接查看源代码。
$ cat col.c
#include
#include
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;
}
这题比较简单,只需传一个长度为 20 字符串使得字符串经过强制类型转换后的和等于 hashcode 即可。
简单谈一下碰撞(collision)的概念:不同的字符串经过一系列处理得到同一结果串。举个例子:一个数经过加号规则处理得到一个等式,如 3 = 1+1+1 也可以得到 3 = 0+1+2,这就是碰撞原理。(读者可以自己去百度一下 hash 碰撞,前面的解释为个人的见解!)
说一下强制类型转换
sizeof(int) = 4;
sizeof(char) = 1;
所以,char * 转 int *的时候需要循环五次,懂了吧?什么不懂?好吧,咱们继续解释一下。
char hashcode[20]; // 一个大小为20的char型数组
char * p = hashcode; // 一个指向 大小为20的char型数组的首地址 的 指针
上面代码的意思,一个指针 p 指向一个数组,数组中的每一个元素都是 char 类型(其实我想说的是,要是你不懂指针你就看成数组吧)。系统在声明变量的时候会为其开辟相应大小的内存空间,这里 char hashcode[20] 就是为其开辟一个 20 * sizeof(char) = 20 大小的空间。而 sizeof(int) = 4,所以同样的 20 个字节的大小空间只需要 5 * sizeof(int) ,这就是为什么后面循环的时候循环了五次的原因。
下面我们来构造一下等式:
0x21DD09EC = (0x21DD09EC - 0x010101014) + 0x010101014
下面是利用 python 的解题步骤:
$ ls
col col.c flag
$ python
Python 2.7.12 (default, Jul 1 2016, 15:12:24)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(0x21DD09EC - 0x01010101*4)
'0x1dd905e8'
>>>
$ ./col $(python -c "print '\xe8\x05\xd9\x1d'+'\x01'*16")
daddy! I just managed to create a hash collision :)
最终得到 flag: daddy! I just managed to create a hash collision :)
网友评论