课程作业,比较入门的知识,传到博客上权当备份吧,实际上没有阅读价值。

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;
        }
    }
}

关键点:

image-20201118110345606

可以直接把箭头处的jz改成jnz。

image-20201118110620062

image-20201118110450870

74改成75

image-20201118110637309

保存修改至程序:

image-20201118110554318

现在随便输入就可以通过密码校验:

image-20201118110748973

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;
}}}

来到验证函数:

image-20201118111619981

双击变量,查看栈内偏移:

image-20201118111647141

输入的密码在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,无法通过密码校验。

image-20201118112744728

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);
}

编译后发现栈内偏移和上一题是一样的:

image-20201118113939115

所以,输入24个任意非空白字符(比如说空格会被%s隔断),后面跟上正确分支的地址0x401653。

注意这里是x64,所以地址是8byte,而且要是小端存储。

image-20201118114221612

image-20201118114231306

overflow3

pass

hackme

去年国庆就做过了,直接复制过来吧。

041 helloworld

要求输入一个数。

img

ida打开后很容易知道。

img

img

最简单的签到题

042 simple

img

"UIJT.JT.ZPVS.GMBH"字符分别减一即可

s = 'UIJT.JT.ZPVS.GMBH'
for i in s:
    print(chr(ord(i)-1),end='')

043passthis

不要直接运行,火绒会报毒,关闭火绒后再运行,电脑直接黑屏。

img

主逻辑就是判断数据库字符串与输入字符串异或值是否为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开始取。

Last modification:April 7th, 2023 at 02:24 pm