狗儿

热爱的话就坚持吧~

0%

网络安全作业3

比较入门的知识。

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
// 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

目标:借助栈溢出绕过密码校验

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

来到验证函数:

image-20201118111619981

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

image-20201118111647141

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

image-20201118112744728

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

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

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"字符分别减一即可

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

043passthis

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

img

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