首页
社区
课程
招聘
[原创]2019看雪CTF 团队赛 第六题 RepwnWP
2019-3-21 15:24 2730

[原创]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虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回