徹底從零開始的CTF之路 2020/11/22

HECTF 2020前端

參加的一場比賽,全程划水。算法

有好幾題有思路,可是沒不出來,(有的找到了半截flag,有的找到了算法卻提交錯誤)數組

 

記錄下幾道有點意思的題目app

 

題目:簽到函數

描述:登陸就送flagblog

 

 

 首先估計能注入,可是有個忘記密碼的超連接,不如先點進去看看。遊戲

 

 

 額,我先輸入本身的手機號碼點擊發送驗證碼。內存

等了半天屁短信都沒有。字符串

估計是個前端假按鈕了。input

 

看描述是4位驗證碼,很明顯是爆破嘛。

因而就開始爆破,可是10000數字跑完也沒爆破出來。

最後回到第一個界面的。查看審查元素才發現:

 

 

 原來人家是指定的一個手機號碼,

繼續burp爆破,獲得驗證碼是0233:

 

 

 隨便輸入一個完事。

 

 

 

密碼到手。

 

 

 

 

 

 

題目:game1

描述:1024分便可拿到flag

 

 

 

這是一個貪吃蛇遊戲,吃一個豆子加一分。

1024分就是長達1024的一條蛇。。。。

可尼瑪就400多個格子啊,因此想玩出1024純屬作夢。

直接ida反編譯吧。

 

 

 首先找到main函數:

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  int v4[4]; // [esp+28h] [ebp-20h]
  int v5; // [esp+38h] [ebp-10h]
  int i; // [esp+3Ch] [ebp-Ch]

  __main();
  v3 = time(0);
  srand(v3);
  init(&apple);
  initsnake();
  while ( 1 )
  {
    snakemove();
    input();
    Sleep(abs((signed int)(200.0 - (long double)score * 0.5)));
    if ( **(_DWORD **)snake == apple && *(_DWORD *)(*(_DWORD *)snake + 4) == dword_4C7018 )
    {
      for ( i = 0; i <= 3; ++i )
        v4[i] = v4[i + 1];
      ++score;
      mess();
      v5 = score;
      if ( score == 1024 )
        flag(v4);
    }
    if ( !*(_DWORD *)(*(_DWORD *)snake + 4)
      || *(_DWORD *)(*(_DWORD *)snake + 4) == 21
      || !**(_DWORD **)snake
      || **(_DWORD **)snake == 21 )
    {
      failed();
    }
  }
}

  觀察可知

 if ( score == 1024 )
        flag(v4);

  這句是獲得flag的語句。

運行了一個叫flag()的函數,傳入了一個叫v4的數組做爲參數。

查看flag():

int __cdecl flag(int *a1)
{
  int result; // eax
  signed int v2; // [esp+14h] [ebp-14h]
  signed int i; // [esp+18h] [ebp-10h]
  int v4; // [esp+1Ch] [ebp-Ch]

  v2 = strlen(_data_start__);
  for ( i = 0; i < v2; ++i )
  {
    if ( _data_start__[i] <= 96 || _data_start__[i] > 122 )
    {
      if ( _data_start__[i] <= 64 || _data_start__[i] > 90 )
        LOBYTE(v4) = _data_start__[i];
      else
        v4 = (_data_start__[i] - 65 + a1[i % 5]) % 26 + 97;
    }
    else
    {
      v4 = (_data_start__[i] - 97 + a1[i % 5]) % 26 + 65;
    }
    _data_start__[i] = v4;
  }
  gotoxy(24, 5);
  color(20);
  if ( _data_start__[0] != 72
    || _data_start__[1] != 69
    || _data_start__[2] != 67
    || _data_start__[3] != 84
    || _data_start__[4] != 70 )
  {
    result = printf("No! you're cheating!");
  }
  else
  {
    result = printf("You win! The flag is %s ", _data_start__);
  }
  return result;
}

 稍微化簡一下,寫成C語言版本:

int  flag(int *a1)
{
  
  char  ans[len];//這就是要輸出的答案的原數組,查看內存可知是bxukv{pW1SiFW_J0_jV}
  int temp;

  for ( int i = 0; i < len; ++i )
  {
     if (ans[i] >='a' && ans[i] <= 'z' )
           temp = (ans[i] - 97 + a1[i % 5]) % 26 + 65;
       if (ans[i] >= 'A' || ans[i] <= 'Z' )
          temp = (ans[i] - 65 + a1[i % 5]) % 26 + 97;
  }

  if ( ans[0]  == 72
    & ans[1] === 69
    & ans[2] == 67
    & ans3]  == 84
    & ans[4] == 70 )
 
printf("You win! The flag is %s ",ans);
  
}

首發現要處理的原數組ans[]的內容是:

   bxukv{pW1SiFW_J0_jV}

而最後要知足

if ( ans[0] == 72 & ans[1] === 69 & ans[2] == 67 & ans3] == 84 & ans[4] == 70 )
才能輸出flag(即ans[])


發現條件就是:
ans[0-5]=HECTF
前面5個字符就是本次比賽的名字。

OK,接下來看中間的處理過程:

 for ( int i = 0; i < len; ++i )
  {
     if (ans[i] >='a' && ans[i] <= 'z' )
           ans[i] = (ans[i] - 97 + a1[i % 5]) % 26 + 65;
       if (ans[i] >= 'A' || ans[i] <= 'Z' )
          ans[i] = (ans[i] - 65 + a1[i % 5]) % 26 + 97;
  }
  

 就是從第一個字符開始若是是小寫就執行:

ans[i] = (ans[i] - 97 + a1[i % 5]) % 26 + 65;

若是是大寫就執行:

ans[i] = (ans[i] - 65 + a1[i % 5]) % 26 + 97;

不然,ans[i]不變。

 

這個很容易推導bxukv{pW1SiFW_J0_jV}轉換後的字符串。

可是其中有一個變量a1不知道。

可是原字符串是bxukv{pW1SiFW_J0_jV},轉換後要以HECTF開頭,

根據這5個字符就能求出a1[0-5]的值。

 

好比ans[0]=b,執行ans[0] = (ans[0] - 97 + a1[0 % 5]) % 26 + 65='H'。

可知a1[0]=6。

同理可知a[0-5]=6,7,8,9,10。

 

再將bxukv{pW1SiFW_J0_jV}帶入上列規則運算就能獲得flag了。

相關文章
相關標籤/搜索