
这里题目提示是哈希碰撞。然后是利用ssh工具连接pwnable.kr 端口2222,用户名为col,密码为guest。

这里我们可以看到含有col、col.c、flag三个文件,显然flag我们不能直接读取。这里正常的ssh工具是通过执行ls命令来查看该文件夹下的文件及文件夹。

先让我们cat col.c来看看这个源文件。
#include<...>是调用头文件。
unsigned long hashcode = 0x21DD09EC; 这里是定义了一个hashcode为无符号长整型变量,大小为0x21DD09EC这里的0x代表是十六进制,要是不习惯可以用计算器的程序员模式看看十进制数。
unsigned long check_password(const char* p) 这里是定义了check_passwprd为无符号长整型变量,const char* p意味着定义一个指向字符常量的指针,const意味着这个指针不可修改。
int* ip = (int*)p; 这里是将char*p强制转换成int*p,这里要将4个char类型字符强制转换成1个int类型,因为这是一个32位程序,一个int 4个字节,一个char 1个字节。这里就是定义一个int类型变量ip,将p转化为int型的值赋给ip。
int i;
int res=0;
for(i=0; i<5; i++){
res += ip[i];
}
return res;
这里定义了一个i,用于做循环。还定义了一个整型数res(result的简写),这里用的是一个for循环,i初始为0,循环条件i<5,i++每次循环+1。循环体是res+=ip[i],意思是res=res+ip[i],就是把我们的输入累加到一起,最后返回一个res。
int main(int argc, char* argv[]) 这个的详细描述在我们上一篇文档中有呈现。本文我也简单阐述一下,int main(int argc, char* argv[])这里意味着定义一个main函数,第一个参数argc的值表示程序运行时,命令行参数的个数。第二个参数*argv[]的值表示指向字符串数组的指针,每个字符串对应一个参数。argv[0]是输入的路径,argv[1]、argv[2]......就是我们的第一个、第二个....个输入。
if(argc<2){
printf("usage : %s [passcode]\n", argv[0]);
return 0;
}
这里argc<2,将会输出usage : ./col [passcode],因为这里做了个判断,是否有两个输入,./col就是一个输入,第二个输入是我们应该赋的值。
if(strlen(argv[1]) != 20){
printf("passcode length should be 20 bytes\n");
return 0;
}
这里strlen是判断我们输入的字符长度,!=20意味着不等于而是就会输出passcode length should be 20 bytes。所以我们这里一定要输入20个字符。
if(hashcode == check_password( argv[1] )){
system("/bin/cat flag");
return 0;
}
else
printf("wrong passcode.\n");
return 0;
这里就是把argv[1]我们的输入放进check_password里,最后来判断是否等于hashcode,如果等于则cat flag。否则则输出wrong passcode。
这边我们就把这几十行C的代码看完了,那接下来我们就想一下如何构造吧。这里要输入的字符最后累加为0x21DD09EC。我们先看看它对应十进制的多少。

这个最后一位为4,我们可以把他整除5。ps这里的方法很多,我只是推荐一种我使用的,各位见仁见智吧,只要最后配出来的是0x21DD09EC即可。

这里我整除了五,发现它的十六进制数为0x06C5CEC8,然后不知道大家知不知道我们的计算机是小端机,小端机的输入应该反过来,我们应该输入C8 CE C5 06这样往里输入。由于这里整除的时候有个余数4,所以我们最后一位要构造成0x06C5CECC,输入应为CC CE C5 06。然后由于ASCII码只包含128位,所以有些是不可显示字符,我们无法直接输入进去,在这边我们就需要使用python大法了。./col `python -c "print '\xC8\xCE\xC5\x06' * 4 + '\xCC\xCE\xC5\x06'"`

flag:daddy! I just managed to create a hash collision :)
这题拿下!