课程作业,比较入门的知识,传到博客上权当备份吧,实际上没有阅读价值。
crackme
目标修改汇编以绕过密码验证。
// crackme.cpp
#include <stdio.h>
#include <string.h>
#define PASSWORD "1234567"
int verify_password(char *password)
{
int authenticated;
authenticated=strcmp(password,PASSWORD);
// strcpy(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
目标:借助栈溢出绕过密码校验
// 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
搞不懂的跑下这个程序就懂了:
#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
目标:覆盖验证函数返回地址,跳转至验证成功的分支。
// 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"
字符分别减一即可
s = 'UIJT.JT.ZPVS.GMBH'
for i in s:
print(chr(ord(i)-1),end='')
043passthis
不要直接运行,火绒会报毒,关闭火绒后再运行,电脑直接黑屏。
主逻辑就是判断数据库字符串与输入字符串异或值是否为135。(46行)
将byte_404040处的数据复制,通过winhex生成文件。
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开始取。