-
-
[原创]2019看雪CTF 团队赛 第六题 RepwnWP
-
2019-3-21 15:24 2730
-
用PEID扫描程序,使用了des算法
第二部分的flag会用到,这里先不看。
打开程序时提示"Please Input Your Key_ Now!",用IDA搜索并且定位到sub_4014C0
int __thiscall sub_4014C0(void *this) { unsigned int v1; // ebx char *Str; // [esp+0h] [ebp-68h] char v4[4]; // [esp+10h] [ebp-58h] int v5; // [esp+20h] [ebp-48h] int v6; // [esp+24h] [ebp-44h] int v7; // [esp+28h] [ebp-40h] int v8; // [esp+2Ch] [ebp-3Ch] int v9; // [esp+30h] [ebp-38h] int v10; // [esp+34h] [ebp-34h] int v11; // [esp+38h] [ebp-30h] int v12; // [esp+3Ch] [ebp-2Ch] char v13; // [esp+40h] [ebp-28h] sub_404970(0x10u, (int)this, (int)Str); sub_4044F0(); v1 = 0; v5 = 'yt^'; v6 = '+pLc'; v7 = 'a+SG'; v8 = 'G-QG'; v9 = 'Gl(V'; v10 = ')y}J'; v11 = 'SGA)'; v12 = 'ea+'; strcpy(v4, "Ansome_Is_Wrong"); while ( v1 < strlen((const char *)&v5) ) *((_BYTE *)&v5 + v1++) ^= 0x18u; puts("Please Input Your Key_ Now!"); scanf("%s", &v13); if ( sub_4012F0((int)&v13) ) { sub_401460(&v13); system("pause"); } else { puts(v4); } return 0; }
分析下sub_4012F0,sub_401460
signed int __cdecl sub_4012F0(int a1) { signed int v1; // ecx signed int v2; // edx int v4; // [esp+0h] [ebp-38h] int v5; // [esp+10h] [ebp-28h] v1 = 8; v2 = 0; strcpy((char *)&v5, "Your_Input_Is_Wrong"); strcpy((char *)&v4, "X1Y0uN3tG00d"); while ( *((_BYTE *)&v4 + v2) == *(_BYTE *)(v1 + a1) ) { ++v2; ++v1; if ( v2 > 11 ) return 1; } return 0; }
sub_4012F0的代码比较简单,判断输入的key的8-12位是否为"X1Y0uN3tG00d"。
int __cdecl sub_401460(char *Str) { char Dest; // [esp+8h] [ebp-10h] if ( strlen(Str) == 24 ) { if ( sub_4013B0((int)Str) ) { Str[20] -= 0x58; Str[21] -= 0x46; Str[22] -= 3; Str[23] -= 0x6B; strcpy(&Dest, Str); } } else { printf("String Length is Wrong"); } return 0; }
sub_401460先判断key是否为24位,那我们可以知道key应该是这种形式:xxxxxxxxX1Y0uN3tG00dxxxx。
之后在sub_4013B0继续处理flag,处理完以后将key后4位的值分别减去不同的值,用strcpy覆盖掉堆栈里的返回地址。
我们先看看sub_4013B0做了什么
int __cdecl sub_4013B0(int a1) { int v1; // ebx int v2; // ecx int v3; // esi int result; // eax sub_401380(a1); // 只能输入十进制整数 v1 = key4 + 1000 * key1 + 100 * key2 + 10 * key3; v2 = key6 + 10 * key5; v3 = key8 + 10 * key7; result = 2 * (v1 + v2); if ( result == 4040 ) { result = 3 * v2 / 2; if ( result + 100 * v3 == 115 ) { result = 1; if ( v1 - 110 * v3 != 1900 ) result = printf("Key_Is_Wrong,Please_Input_Again!"); } } return result; }
sub_401380是将前8位key都减去0x30,然后添加到全局变量地址里面,这里我把地址重新命名了。
要算出key,我们可以先列出关于v1,v2,v3的方程组
2 v1 + 2 v2 = 4040
1.5 v2 + 100 v3 = 115
v1 - 110 v3 = 1900
可解得v1=2010,v2=10,v3=1
知道v1,v2,v3的值后就能算出前8位key的值了,分别为2,0,1,0,1,0,0,1,
key还差最后4位。
前面提到过key的后4位是处理过后覆盖掉堆栈的返回地址,而该程序的基址总是为0x00400000,我们可以先算出后两位
0x40+0x3=0x43,也就是'C'
0x6B则是'k'
好像挺眼熟的,看了一眼出题战队的名字是"
HaCky_
",尝试输入"20101001X1Y0uN3tG00dHaCk",通过了,进入第二部分Please_Input_The_Flag
HaCk处理过后得到的地址是401BF0,其主要代码
...//前面在处理printf的字符串,忽略 system("cls"); printf("%.*s\n", 21, &v5); v2 = 'oyiX'; v3 = 'teNu'; v4 = 0; fflush(iob[0]); flag = (char *)sub_401D30(8u); gets(flag); generate_sub_keys((int)&v2); // deskey=XiyouNet sub_4018B0((int)flag, (int)flag);
最开始用PEID扫描到程序使用了DES算法,用标准DES的代码来对照分析,与标准DES并没有太大差异,只是数据在内存中表示成二进制,以及加密后的字节拆开,比如0000009D拆成00000009和
0000000D
sub_4018B0的部分代码如下
... memcpy(v12, &trueflag, 0x94u); qmemcpy(Format, &success, sizeof(Format)); v6 = 0; v11 = 0; while ( v6 < strlen(Format) ) { Format[v6] ^= 0x18u; // 解密要输出的字符串 ++v6; } v7 = 0; do // 二进制转十六进制 { Dst[v7] = (unsigned __int8)flag_shift_byte3[4 * v7] + 2 * ((unsigned __int8)flag_shift_byte2[4 * v7] + 2 * ((unsigned __int8)flag_shift_byte1[4 * v7] + 2 * (unsigned __int8)flag_shift_byte[4 * v7])); ++v7; } while ( v7 <= 15 );// ...//补齐加密结果 while ( 1 ) { if ( Dst[v8] != v12[v8] ) // 与des加密后的flag比较,相等则成功 v9 = 1; if ( ++v8 > 31 ) { if ( !v9 ) printf(Format); putchar(10); system("pause"); ExitProcess(0); } }
我们直接提取trueflag的数据,处理后des解密即可
encryptdata:9DB084AC97041E305697D5A499355A28
decryptdata:57656C3143306D650000000000000000
text:Wel1C0me
输入"
Wel1C0me"通过,提示"Currect,Flag_Format_Is_Input1+Input2"
那我们提交的flag就是"20101001X1Y0uN3tG00dHaCkWel1C0me"
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
赞赏
他的文章
看原图