PWNABLE_02_hash
linux_hash 缺陷代码如下:
#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;
}
- hint: hash collision
- guest用户无flag文件执行权限,代码中如果
hashcode == check_password( argv[1] )
执行成功会输出flag结果。 - 需要令res的值为0x21DD09EC(十进制568134124)
check_password
将输入的argv1分为五份,并且相加起来- 应该是四个113626825加上一个113626824
- 也就是四个06c5cec9加上一个06c5cec8
- 所以argv1应设置为\x06\xc5\xce\xc9\x06\xc5\xce\xc9\x06\xc5\xce\xc9\x06\xc5\xce\xc9\x06\xc5\xce\xc8
- 但C语言的编译器默认为小端存储,所以我们需要倒置输入的排序
- 最终应输入的16进制字符串如下: \xc9\xce\xc5\x06\xc9\xce\xc5\x06\xc9\xce\xc5\x06\xc9\xce\xc5\x06\xc8\xce\xc5\x06
- 最终执行,结果如下:
col@pwnable:~$ ./col `python -c "print 4*'\xc9\xce\xc5\x06'+'\xc8\xce\xc5\x06'"`
daddy! I just managed to create a hash collision :)
对check_password()
不太明白的点
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;
}
-
const char* p
const表示不可修改,char是字符型,*是个指针
这里还有三种情况:
const char *p
// 声明一个指向字符或字符串常量的指针(p所指向的内容不可修改)
char const *p
// 同上
char * const p
//声明一个指向字符或字符串的指针常量,即不可以修改p的值,也就是地址无法修改。 -
(int*) p
是啥意思
将p强制类型转换为int型指针,之前是字符型指针 -
res += ip[i]
循环了五次,也就是说res的结果是ip指向地址第一到五位的和,但输入长度是20,程序是如何确定一次读4的长度的
输入20字节=5×int=20×char
当通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。 我是int型指针,我指的是int,他在内存里占4个字节。
这里是由于指针类型被强制转换了,所以循环5次,如果是16位编译器,int长2,那就还得循环10次。
这里并不是均分,+1后除5好计算,其他计算方法只要五次相加后和是0x21DD09EC均可。
最后一句,程序确定了一次读4个字节的长度,因为从指向一个字节的字符指针,变成了指向四个字节的int指针。读的最小单位一直是“一个”,但种类有所不同。