课程作业,比较入门的知识,传到博客上权当备份吧,实际上没有阅读价值。
crackme 目标修改汇编以绕过密码验证。
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> #define PASSWORD "1234567" int verify_password (char *password) { int authenticated; authenticated=strcmp (password,PASSWORD); return authenticated; } main(){ int valid_flag=0 ; char password[8 ]; while (1 ) { printf ("please input password: " ); scanf ("%s" ,password); valid_flag=verify_password(password); if (valid_flag) { printf ("incorrect password!\n\n" ); } else { printf ("Congratulation! You have passed the verification!\n" ); break ; } } }
关键点:
可以直接把箭头处的jz改成jnz。
74改成75
保存修改至程序:
现在随便输入就可以通过密码校验:
overflow1 目标:借助栈溢出绕过密码校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // overflow1.cpp #include <stdio.h> #include <string.h> #define PASSWORD "1234567" int verify_password(char *password){ int authenticated; char buffer[8]; authenticated=strcmp(password,PASSWORD); strcpy(buffer,password); return authenticated; } main(){ int valid_flag=0; char password[1024]; while(1){ printf("please input password: "); scanf("%s",password); valid_flag=verify_password(password); if(valid_flag){ printf("incorrect password!\n\n"); }else{ printf("Congratulation! You have passed the verification!\n"); break; }}}
来到验证函数:
双击变量,查看栈内偏移:
输入的密码在0x10,验证的返回值在0x4,所以输入12个字符时,第13个字符就是\x00,覆盖验证值的最低字节。
strcmp(a, b)的结果等于0,表示两个字符串相等。
大于0(一般是等于1),表示a > b
小于0(一般是等于-1),表示a < b
搞不懂的跑下这个程序就懂了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> #include <string.h> int main () { char str1[15 ]; char str2[15 ]; int ret; strcpy (str1, "abcde" ); strcpy (str2, "ABCDEF" ); ret = strcmp (str1, str2); if (ret == -1 ) { printf ("str1 is less than str2" ); } else if (ret == 1 ) { printf ("str2 is less than str1" ); } else { printf ("str1 is equal to str2" ); } return (0 ); }
但是,你需要注意,验证值是一个int,而不是一个bool
字符串不相等有两种情况,一种返回值等于1,此时输入12个字节,第13个字节必然是\x00,覆盖int的最低字节,验证值是1,被覆盖成了0。所以返回的就是验证正确。
而返回值等于-1的时候,这个int的数值其实是0xffffffff。即使覆盖了最低字节,但其值此时是0xffffff00,仍然不等于0,无法通过密码校验。
overflow2 目标:覆盖验证函数返回地址,跳转至验证成功的分支。
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 // overflow2.cpp #include <iostream> #include <string.h> #define PASSWORD "1234567" int verify_password(char *password) { int authenticated; char buffer[8]; authenticated=strcmp(password,PASSWORD); strcpy(buffer,password); return authenticated; } main(){ int valid_flag=0; char password[1024]; FILE * fp; if(!(fp=fopen("password.txt","rw+"))){ exit(0); } fscanf(fp,"%s",password); valid_flag=verify_password(password); if(valid_flag){ printf("incorrect password!\n\n"); }else{ printf("Congratulation! You have passed the verification!\n"); } fclose(fp); }
编译后发现栈内偏移和上一题是一样的:
所以,输入24个任意非空白字符(比如说空格会被%s隔断),后面跟上正确分支的地址0x401653。
注意这里是x64,所以地址是8byte,而且要是小端存储。
overflow3 pass
hackme 去年国庆就做过了,直接复制过来吧。
041 helloworld 要求输入一个数。
ida打开后很容易知道。
最简单的签到题
042 simple
"UIJT.JT.ZPVS.GMBH"
字符分别减一即可
1 2 3 s = 'UIJT.JT.ZPVS.GMBH' for i in s: print(chr(ord(i)-1),end='')
043passthis 不要直接运行,火绒会报毒,关闭火绒后再运行,电脑直接黑屏。
主逻辑就是判断数据库字符串与输入字符串异或值是否为135。(46行)
将byte_404040处的数据复制,通过winhex生成文件。
1 2 3 4 5 with open('11.txt','rb')as f: #二进制读入 s = f.read() print(s) for i in s: print(chr(i^135),end='')
顺便说一下_bittest(*a, b),检查地址a中,第b位的值是0还是1。注意到b的值从0开始取。