这个比赛是一个对新人很友好的比赛,不过也能学到一些知识
64位elf文件
用ida打开,发现程序将输入的字符串存入s2中,与s1字符串比较,若相同则输出正确的flag
所以我们只需要运行程序并输入s1字符串即可得到flag
64位无壳
用它给出的数据减去1337既得flag
1 2 3 4 5 6 7 8 9 10 encoder = [1412 , 1404 , 1421 , 1407 , 1460 , 1452 , 1386 , 1414 , 1449 , 1445 , 1388 , 1432 , 1388 , 1415 , 1436 , 1385 , 1405 , 1388 , 1451 , 1432 , 1386 , 1388 , 1388 , 1392 , 1462 ] v7 = 1337 flag = []for i in range(len(encoder)): flag.append(encoder[i] - v7) print(flag) for i in range(len(flag)): print(chr(flag[i]),end='')
这道题我最开始一直以为是音频隐写,后来发现并不是,用jd-gui 打开
将0xflag对应部分用base64解密(base64解密网站 )
将文件用ida打开,找到main函数如下
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 int __cdecl main(int argc, const char **argv, const char **envp) { char v4[512]; // [rsp+0h] [rbp-240h] BYREF char v5[51]; // [rsp+200h] [rbp-40h] BYREF char v6; // [rsp+233h] [rbp-Dh] int v7; // [rsp+234h] [rbp-Ch] int j; // [rsp+238h] [rbp-8h] int i; // [rsp+23Ch] [rbp-4h] strcpy(v5, "08'5[Z'Y:H3?X2K3V)?D2G3?H,N6?G$R(G]" ); printf("Give me a flag : " ); __isoc99_scanf("%s" , v4); for ( i = 0; v4[i]; ++i ) { if ( v4[i] <= 64 || v4[i] > 90 ) { if ( v4[i] <= 96 || v4[i] > 122 ) v4[i] = v4[i]; else v4[i] = -37 - v4[i]; } else { v4[i] = -101 - v4[i]; } } for ( j = 0; v4[j]; ++j ) v4[j] -= 32; v7 = 0; v6 = 0; while ( v5[v7] ) { if ( v5[v7] != v4[v7] ) { v6 = 0; break; } v6 = 1; ++v7; } if ( v6 ) puts("You have entered the right flag." ); else puts("Sorry ! Its wrong flag." ); return 0; }
由伪代码可知,程序将flag存入v4中,经过一系列加密后与v5字符串进行比较,所以只需要将已知的v5字符串解密即得flag,注意v4中每个元素的范围都在ascii码的范围内,所以要将运算结果对128取余,脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 v5 = "08'5[Z'Y:H3?X2K3V)?D2G3?H,N6?G$R(G]" coded_flag = [] for x in v5: coded_flag.append(ord(x) + 32 ) for i in range(len(coded_flag)): if 90 < coded_flag[i] <= 96 or coded_flag[i] > 122 or coded_flag[i] <= 64 : coded_flag[i] = coded_flag[i] elif 96 < coded_flag[i] <= 122 : coded_flag[i] = (-37 - coded_flag[i]) else: coded_flag[i] = (-101 - coded_flag[i]) for z in coded_flag: print(chr(z), end='' )
运行即得flag
ida反编译如下
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 32 33 34 35 36 37 38 int __cdecl main(int argc, const char **argv, const char **envp) { char v4; // [rsp+Bh] [rbp-435h] int i; // [rsp+Ch] [rbp-434h] int v6; // [rsp+Ch] [rbp-434h] char v7[48]; // [rsp+10h] [rbp-430h] BYREF char v8[1016]; // [rsp+40h] [rbp-400h] BYREF unsigned __int64 v9; // [rsp+438h] [rbp-8h] v9 = __readfsqword(0x28u); strcpy(v7, "*9J<qiEUoEkU]EjUc;U]EEZU`EEXU^7fFoU^7Y*_D]s" ); puts("Hello There..\nWelcome to KS Vault." ); printf("Please enter vault password : " ); __isoc99_scanf("%s" , v8); for ( i = 0; v8[i]; ++i ) { v8[i + 512] = v8[i] - 10; if ( v8[i + 512] == 65 ) v8[i + 512] = 42; } v6 = 0; v4 = 0; while ( v7[v6] ) { if ( v7[v6] != v8[v6 + 512] ) { v4 = 0; break; } v4 = 1; ++v6; } if ( v4 ) win(); else puts("Wrong password !" ); return 0; }
解密脚本如下
1 2 3 4 5 6 7 8 encoded_flag = '*9J<qiEUoEkU]EjUc;U]EEZU`EEXU^7fFoU^7Y*_D]s' flag = []for i in encoded_flag: if ord(i) == 42 : flag .append (75 ) else :flag .append (ord(i) + 10 ) for i in range(len(flag )): print(chr(flag [i]), end='' )
运行得flag
这道题也是给出了加密后的字符串以及加密过程,求出加密前的字符串即得flag
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 int __cdecl main(int argc, const char **argv, const char **envp) { char v4[512]; // [rsp+0h] [rbp-430h] char v5[512]; // [rsp+200h] [rbp-230h] BYREF char v6[32]; // [rsp+400h] [rbp-30h] BYREF int i; // [rsp+420h] [rbp-10h] char v8; // [rsp+427h] [rbp-9h] int v9; // [rsp+428h] [rbp-8h] int v10; // [rsp+42Ch] [rbp-4h] strcpy(v6, "ZRIU]HdANdJAGDIAxIAvDDsAyDDq_" ); v10 = 0; v9 = 0; puts("-------------------------------------" ); puts("\tKnight Switch Bank" ); puts("--------------------------------------" ); puts("Welcome to Knight Switch Bank...." ); printf("Please enter your password : " ); __isoc99_scanf("%s" , v5); while ( v5[v10] ) { if ( v5[v10] <= 64 || v5[v10] > 77 ) { if ( v5[v10] <= 96 || v5[v10] > 109 ) { if ( v5[v10] <= 77 || v5[v10] > 90 ) { if ( v5[v10] <= 109 || v5[v10] > 122 ) v4[v10] = v5[v10] - 32; else v4[v10] = v5[v10] - 13; } else { v4[v10] = v5[v10] - 13; } } else { v4[v10] = v5[v10] + 13; } } else { v4[v10] = v5[v10] + 13; } ++v10; } while ( v4[v9] ) v4[v9++] += 2; v8 = 0; for ( i = 0; v6[i]; ++i ) { if ( v6[i] != v4[i] ) { v8 = 0; break; } v8 = 1; } if ( v8 ) winner(); else puts("Oh My God ! You entered a wrong password." ); return 0; }
可以看到,程序对不同范围的输入字符串进行了不同的加密,所以可以爆破求字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 encoded_flag = 'ZRIU]HdANdJAGDIAxIAvDDsAyDDq_'flag = [] for j in range(len(encoded_flag)): for i in range(0 , 128 ): if i <= 64 or i > 77 : if i <= 96 or i > 109 : if i <= 77 or i > 90 : if i <= 109 or i > 122 : k = i - 32 else : k = i - 13 else : k = i - 13 else : k = i + 13 else : k = i + 13 if k == ord(encoded_flag[j]) - 2 : flag .append(i) for i in range(len(flag)): print (chr(flag[i]), end='')
运行既得flag
这道题比赛时我没有做出来,原因是不会寻找字符串
方法一,用jeb直接打开DroidFlag.apk,在MainActivity中可以看到,flag即为getS1(),getS3(),getS2(),getS4()几个函数的返回值拼接起来
双击getS1(),可以跳转到定义这几个函数的位置
可以看到,jeb已经将这几个字符串的值注释出来了,易得flag
1 2 3 4 5 6 7 s1="3LpM1s" s3="D10RdNa" s2="3Sr3V3r" a = s1 + "_" +s2+ "_" +s3b = a [::-1] print ('KCTF{' +b+'}' )
另一种方法参考了这篇wp
[Droid Flag Rev] Knight CTF 2022 (github.com)
首先将apktools复制到DroidFlag.apk所在的文件夹,执行如下命令
在values文件夹中找到strings.xml
同样可以查看字符串