第二题,是一道关于MD5 hash碰撞的 题目,使用ssh链接,题目详情如下:

​ 先链接上看看,密码guest:

​ 还是熟悉的几个文件,col.c是包含漏洞的源码、col为编译后的文件、flag是我们要读取的文件。当前用户col对于flag依旧没有读写权限,要读取flag内容,观察col_pwn就可以发现原理和fd依旧相同,这里直接分析col.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
#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;
}

分析:

  1. 得到flag的前提是argv[1]经过运算后,能够和hashcode对应的值0x21DD09EC相匹配
  2. argv[1]作为参数1,大小为20字节
  3. check_password进行hash运算,函数将20字节的argv[1]拆分位一个int[5]数组进行累加运算

综上,这里只需要找到一组int[5]来满足累加运算后值为0x21DD09EC即可成功破解。

​ 这里可以考虑写程序暴力枚举破解,但对于这个简单的算法其实没必要,只需要保证五个四字节大小的数相加为hashcode即可,那么可以让前4个四字节数都为同一个值也就是参数的前16个字节都相同,比如设为0x0(这里不能为0x00,应为0x00会截断参数输入,其它任何数都可以),那么最后一个四字节数就可以通过0x21DD09EC-0x05050505*4算出来为0x0DC8F5D8。

​ 输入参数需要手动键入的话,很多非字母、数字和符号的ASCII字符是打不出来的,这就需要掌握点技巧,一个方法就是使用python这样的脚本对字符进行输出然后直接作为参数进行漏洞程序执行。使用python构建参数为如下形式:

1
`python2 -c "print '\x05\x05\x05\x05'*0x4+'\xd8\xf5\xc8\x0d'"`

​ 然后我们进行验证,python2成功flag,这里不建议使用python3: