title: [ACTF新生赛2020]fungame
categories: CTF题解——reverse
这个题虽然不难,但出题思路清奇,写个题解
查壳,32位无壳,进IDA
F5main函数
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *v4; // [esp+1Ch] [ebp-4h]
__main();
v4 = malloc(0x14u);
memset(v4, 0, 0x14u);
memset(x, 0, 0x18u);
sub_401340(v4);
sub_4013BA((char *)v4);
return 0;
}
挨个看,第一个函数,有意思,简单异或,提取y2,y1,解密一下
int __cdecl sub_401340(int flag)
{
char i; // [esp+1Fh] [ebp-9h]
printf("Please input:");
scanf("%s", flag); //输入第一段flag
for ( i = 0; i <= 15; ++i )
{
//异或加密
if ( (*(_BYTE *)(i + flag) ^ *((_BYTE *)y1 + i)) != y2[i] )
exit(0);
}
return 0;
}
提取y1,y2解密flag:
# Re_1s_So0_funny!
提交了,假flag,再探,下一位函数
这个就有意思了,16位flag存进了12位的数组,搞溢出哇
int __cdecl sub_4013BA(char *flag)
{
//12位,溢出
char Destination[12]; // [esp+1Ch] [ebp-Ch] BYREF
strcpy(Destination, flag); //传给des,溢出部分作为参数传递
strcpy(x, flag); //又复制一份给x,有问题
return 0;
}
交叉引用查x
void __noreturn sub_40233D()
{
char Str2[13];
char Str1[16];
char Str[12];
size_t v3;
printf("Please input again:");
strcpy(Str2, "YTFzMF9wV24="); //base64加密结果
memset(Str, 0, sizeof(Str));
memset(Str1, 0, sizeof(Str1));
scanf("%s", Str); //第二段输入
v3 = strlen(Str);
sub_402421(Str, v3, Str1); //base64
if ( !strcmp(Str1, Str2) )
{
printf("%s%s", x, Str);
exit(0);
}
exit(0);
}
sub_40233D就是对新的输入进行一个base64加密
但是这个函数是怎么被执行的,答案就是上面的溢出,通过溢出调用了这个函数40233D
所以真正的flag就是:
x + 溢出(注意大小端序问题) + str
解密脚本
#异或解密
list=[0x23,0x61,0x3e,0x69,0x54,0x41,0x18,0x4d,0x6e,0x3b,0x65,0x53,0x30,0x79,0x45,0x5b]
list1=[0x71,0x4,0x61,0x58,0x27,0x1e,0x4b,0x22,0x5e,0x64,0x3,0x26,0x5e,0x17,0x3c,0x7a]
for i in range(0,len(list)):
list[i] = chr(list[i]^list1[i])
list = list[:12]
#溢出
yichu = [0x3d,0x23,0x40]
for i in yichu:
list.append(chr(i))
list = ''.join(list)
#base64
s="YTFzMF9wV24="
import base64
s = str(base64.b64decode(s),encoding='utf-8')
print('flag{' + list + s + '}')
个人博客:woodenmandu.cn