Hackquest 2018. Results & Writeups. Day 1-3

    Семь дней ежегодного хакквеста — семь заданий, которые нужно решить, чтобы получить бесплатные входные билеты на Zeronights. В этой статье мы предлагаем вам ознакомиться с решениями некоторых из них, а также узнать имена победителей. Для удобства публикацию мы разобьём на две части.



    Содержание





    Day1. Galois


    За помощь в подготовке задания благодарим REhints.
    «The challenge is as easy as following: download the binary (pass:infected), reverse engineer it and recover two secrets that the binary will accept. Each secret is an ASCII string. You would need to solve first stage first before attacking the second. Good luck and may Galois be with you!»

    Чтобы получить флаг, нужно последовательно ввести два секретных значения:

    image

    По строчкам выдаваемых сообщений попадаем в функцию:

    DialogFunc
    BOOL __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
    {
      HWND v5; // eax
      HWND v6; // eax
      HWND v7; // eax
      HWND v8; // eax
      HWND v9; // eax
      HWND v10; // eax
      CHAR v11; // [esp+0h] [ebp-5Ch]
      CHAR String[20]; // [esp+2Ch] [ebp-30h]
      struct tagRECT Rect; // [esp+40h] [ebp-1Ch]
      UINT v14; // [esp+50h] [ebp-Ch]
      HDC hdc; // [esp+54h] [ebp-8h]
      unsigned int i; // [esp+58h] [ebp-4h]
     
      v14 = a2;
      if ( a2 == 20 )
      {
        hdc = (HDC)a3;
        GetClientRect(hWnd, &Rect);
        SetMapMode(hdc, 8);
        SetWindowExtEx(hdc, 100, 100, 0);
        SetViewportExtEx(hdc, Rect.right, Rect.bottom, 0);
        FillRect(hdc, &Rect, hbr);
        return 1;
      }
      if ( v14 == 272 )
        return 1;
      if ( v14 != 273 || HIWORD(a3) )
        return 0;
      if ( (unsigned __int16)a3 == 1 )
      {
        EndDialog(hWnd, (unsigned __int16)a3);
        return 1;
      }
      if ( (unsigned __int16)a3 != 1002 )
      {
        if ( (unsigned __int16)a3 == 1004 )
        {
          sub_42E7C0(&v11, 0, 42);
          if ( GetDlgItemTextA(hWnd, 1005, &v11, 42) <= 0x27 && (unsigned __int8)sub_42CEF0(&v11) )
          {
            v9 = GetDlgItem(hWnd, 1004);
            EnableWindow(v9, 0);
            v10 = GetDlgItem(hWnd, 1005);
            EnableWindow(v10, 0);
            MessageBoxW(hWnd, L"Good job!", L"Success", 0);
            return 1;
          }
          MessageBoxW(hWnd, L"Keep trying!", L"Rejected", 0);
        }
        return 1;
      }
      if ( GetDlgItemTextA(hWnd, 1001, String, 18) != 16 || !(unsigned __int8)sub_4014E0(String) )
      {
        MessageBoxW(hWnd, L"Keep trying!", L"Rejected", 0);
        return 1;
      }
      v5 = GetDlgItem(hWnd, 1002);
      EnableWindow(v5, 0);
      v6 = GetDlgItem(hWnd, 1001);
      EnableWindow(v6, 0);
      v7 = GetDlgItem(hWnd, 1005);
      EnableWindow(v7, 1);
      v8 = GetDlgItem(hWnd, 1004);
      EnableWindow(v8, 1);
      for ( i = 0; i < 0x28; ++i )
        *((_BYTE *)&dword_442780 + i) ^= String[(signed int)i % 16];
      MessageBoxW(hWnd, L"Stage #2 unlocked!", L"Accepted", 0);
      return 1;
    }


    Чтобы достичь «Stage #2 unlocked!», необходимо пройти проверку в функции sub_4014E0 (длина строки — 16 символов). А до «Good job!» — ещё одну проверку в sub_42CEF0 (длина второй строки меньше 40 символов).

    Stage #1


    char __cdecl sub_4014E0(char *a1)
    {
      int v1; // ecx
      unsigned __int128 var_1018[256]; // [esp+0h] [ebp-1018h]
      unsigned __int128 var_18; // [esp+1000h] [ebp-18h]
      int v5; // [esp+1010h] [ebp-8h]
      char v6; // [esp+1017h] [ebp-1h]
     
      sub_438740(0x1018u, v1);
      sub_43A460(var_1018, xmmword_4427A8, 0x1000u);
      sub_4010E0(a1, var_1018);
      sub_401250(var_1018, &var_18);
      v5 = sub_438845(var_18, &xmmword_442770, 0x10u);
      if ( !v5 )
        v6 = 1;
      return v6;
    }

    Под отладчиком можно убедиться, что sub_43A460 копирует данные из:
    image

    А sub_438845 сравнивает значение с:
    .data:00442770 xmmword_442770 9698CA91EE29902C60D377C981589205h

    Данные представлены в виде 128-битных чисел, потому что так оказалось удобнее в ходе дальнейшего анализа.

    Функция sub_4010E0
    void __cdecl sub_4010E0(unsigned __int128 *a1, unsigned __int128 *a2)
    {
      signed int i; // [esp+4h] [ebp-8h]
      signed int j; // [esp+8h] [ebp-4h]
     
      for ( i = 0; i < 128; ++i )
      {
        for ( j = 0; j < 128; ++j )
        {
          if ( (*((_DWORD *)a1 + (j >> 5)) >> (j & 0x1F)) & 1 )
          {
            if ( !((*((_DWORD *)a1 + ((j + 1) % 128 >> 5)) >> ((j + 1) % 128 & 0x1F)) & 1) )
              *((_DWORD *)&a2[2 * i] + ((j + 128) >> 5)) &= ~(1 << ((j + -128) & 0x1F));
          }
          else
          {
            *((_DWORD *)&a2[2 * i] + (j >> 5)) &= ~(1 << (j & 0x1F));
            *((_DWORD *)&a2[2 * i] + ((j + 128) >> 5)) &= ~(1 << ((j + -128) & 0x1F));
          }
        }
      }
    }


    Эта же функция в несколько упрощённом виде
    void __cdecl sub_4010E0(unsigned __int128 *a1, unsigned __int128 *a2)
    {
      signed int i; // [esp+4h] [ebp-8h]
      signed int j; // [esp+8h] [ebp-4h]
      signed int j_1;
     
      for ( i = 0; i < 128; ++i )
      {
        for ( j = 0; j < 128; ++j )
        {
          j_1 = (j + 1) % 128;
          if ( (*((_DWORD *)a1 + j / 32) >> (j % 32)) & 1 )
          {
            if ( !((*((_DWORD *)a1 + j_1 / 32) >> (j_1 % 32)) & 1) )
              *((_DWORD *)&a2[2 * i] + 4 + j / 32) &= ~(1 << (j % 32));
          }
          else
          {
            *((_DWORD *)&a2[2 * i] + j / 32) &= ~(1 << (j % 32));
            *((_DWORD *)&a2[2 * i] + 4 + j / 32) &= ~(1 << (j % 32));
          }
        }
      }
    }


    Для каждой пары 128-битных чисел, адресуемых вторым аргументов, цикл пробегает по 128 битам введённой строки (первый аргумент) и, если бит равен 0, сбрасывает соответствующие биты (по сути выполняет операцию AND). Для второго числа из пары бит сбрасывается также, если следующий бит в последовательности равен 0.
    На питоне это выглядит примерно так:
    def sub_4010E0(a1, a2):
        for i in range(128):
            a2[2 * i] &= a1
            a2[2 * i + 1] &= a1 & (a1 >> 1)

    Функция sub_401250
    void __cdecl sub_401250(unsigned __int128 *a1, unsigned __int128 *a2)
    {
      signed int k; // [esp+4h] [ebp-Ch]
      signed int j; // [esp+8h] [ebp-8h]
      signed int i; // [esp+Ch] [ebp-4h]
     
      *(_QWORD *)a2 = 0i64;
      *((_QWORD *)a2 + 1) = 0i64;
      for ( i = 0; i < 128; ++i )
      {
        for ( j = 0; j < 4; ++j )
          *((_DWORD *)&a1[2 * i] + j) ^= *((_DWORD *)&a1[2 * i + 1] + j);
        for ( k = 0; k < 2; ++k )
          *((_DWORD *)&a1[2 * i] + k) ^= *((_DWORD *)&a1[2 * i] + k + 2);
        LODWORD(a1[2 * i]) ^= DWORD1(a1[2 * i]);
        LODWORD(a1[2 * i]) ^= LODWORD(a1[2 * i]) >> 16;
        LODWORD(a1[2 * i]) ^= LODWORD(a1[2 * i]) >> 8;
        LODWORD(a1[2 * i]) ^= LODWORD(a1[2 * i]) >> 4;
        LODWORD(a1[2 * i]) ^= LODWORD(a1[2 * i]) >> 2;
        LODWORD(a1[2 * i]) ^= LODWORD(a1[2 * i]) >> 1;
        if ( a1[2 * i] & 1 )
          *((_DWORD *)a2 + (i >> 5)) |= 1 << (i & 0x1F);
      }
    }


    Каждую получившуюся пару функция сворачивает в один бит, выполняя XOR между всеми битами. Полученные 128 бит и формируют число, сравниваемое с заданным.

    Для нахождения решения воспользуемся решателем z3.

    Несложными заменами в блокноте превращаем массив xmmword_4427A8 в систему (нули и единицы в левой части - это число xmmword_442770)
    from z3 import *
    init('../')
     
    def xor_bits(x):
        x = Extract(63, 0, x) ^ Extract(127, 64 ,x)
        x = Extract(31, 0, x) ^ Extract(63, 32, x)
        x = Extract(15, 0, x) ^ Extract(31, 16, x)
        x = Extract(7, 0, x) ^ Extract(15, 8, x)
        x = Extract(3, 0, x) ^ Extract(7, 4, x)
        x = Extract(1, 0, x) ^ Extract(3, 2, x)
        return Extract(0, 0, x) ^ Extract(1, 1, x)
     
    x = BitVec('x', 128)
    s = Solver()
     
    # 0x9698CA91EE29902C60D377C981589205
    s.add(1 == xor_bits(BitVecVal(0x23B617F87A29, 128) & x) ^ xor_bits(BitVecVal(0x19203F83800, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1091, 128) & x) ^ xor_bits(BitVecVal(0x0, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xC1C283565E, 128) & x) ^ xor_bits(BitVecVal(0xC001020E, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x2C1A78A0, 128) & x) ^ xor_bits(BitVecVal(0x4083800, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1B, 128) & x) ^ xor_bits(BitVecVal(0x1, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x2BD, 128) & x) ^ xor_bits(BitVecVal(0x1C, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x6434999B6302B0DBCA8123800BE, 128) & x) ^ xor_bits(BitVecVal(0x10088921001049C000018001E, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x613, 128) & x) ^ xor_bits(BitVecVal(0x1, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x16129091D4A1C4, 128) & x) ^ xor_bits(BitVecVal(0x2000000C000C0, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x91, 128) & x) ^ xor_bits(BitVecVal(0x0, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x76749651E3D6AD117C5AF, 128) & x) ^ xor_bits(BitVecVal(0x12300200E1C204003C087, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x42FED750966FE5, 128) & x) ^ xor_bits(BitVecVal(0x7E43000227E0, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x19D096E5D570B, 128) & x) ^ xor_bits(BitVecVal(0xC00260C0301, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x2BD67AA37EC064C89AF12D97, 128) & x) ^ xor_bits(BitVecVal(0x1C238013E40204008700483, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x3372FB29B7426152C739DB374312B, 128) & x) ^ xor_bits(BitVecVal(0x1307900930020004318C91301001, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x56D0FAF2FF, 128) & x) ^ xor_bits(BitVecVal(0x24078707F, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x5AAEFBCEFB063DB41635, 128) & x) ^ xor_bits(BitVecVal(0x80679C679021C900210, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x6388B6598BDD29D10862B2D9DC0B95, 128) & x) ^ xor_bits(BitVecVal(0x180120881CC00C000201048CC0180, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1BB63AF4CE98D27, 128) & x) ^ xor_bits(BitVecVal(0x19218704608403, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x5D4D30E2F6807C1D, 128) & x) ^ xor_bits(BitVecVal(0xC04106072003C0C, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x71AE40387FEFC85, 128) & x) ^ xor_bits(BitVecVal(0x108600183FE7C00, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1E320DC34999A60A93AE, 128) & x) ^ xor_bits(BitVecVal(0x61004C1008882000186, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x2F52, 128) & x) ^ xor_bits(BitVecVal(0x700, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xB9D4158F29C2CAEC9, 128) & x) ^ xor_bits(BitVecVal(0x18C0008700C040640, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x6347962CDB1BC, 128) & x) ^ xor_bits(BitVecVal(0x10382044909C, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xA2FF40, 128) & x) ^ xor_bits(BitVecVal(0x7F00, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x6, 128) & x) ^ xor_bits(BitVecVal(0x0, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x21FFD0D835722CFF409DD38B2E11, 128) & x) ^ xor_bits(BitVecVal(0xFFC0481030047F000CC1810600, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x466DC3, 128) & x) ^ xor_bits(BitVecVal(0x224C1, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x45D44FF2, 128) & x) ^ xor_bits(BitVecVal(0xC007F0, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x13ACE, 128) & x) ^ xor_bits(BitVecVal(0x1846, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x3FB1EAE727AD49CCA3, 128) & x) ^ xor_bits(BitVecVal(0xF90E063038400C401, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xB35AD528D, 128) & x) ^ xor_bits(BitVecVal(0x110840004, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x135AB5C363654340F464007DC58, 128) & x) ^ xor_bits(BitVecVal(0x10810C1212001007020003CC08, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x405E95920EEE57BE0E0A51677D05, 128) & x) ^ xor_bits(BitVecVal(0xE00800666039E060000233C00, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xB4DEE4643A9F3218C6, 128) & x) ^ xor_bits(BitVecVal(0x104E6020180F100842, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x678D930A747F3D1CCCC727B, 128) & x) ^ xor_bits(BitVecVal(0x3848100303F1C0C4443039, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x2DB2654501D47A394DC9A, 128) & x) ^ xor_bits(BitVecVal(0x490200000C0381804C08, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xE86CDA733EA, 128) & x) ^ xor_bits(BitVecVal(0x202448311E0, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x13124A8FCA2ADE475, 128) & x) ^ xor_bits(BitVecVal(0x1000007C0004E030, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x44F8BC5F2E3551A9F94F8B2221EF6F3, 128) & x) ^ xor_bits(BitVecVal(0x781C0F06100080F807810000E7271, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x27274, 128) & x) ^ xor_bits(BitVecVal(0x3030, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x3558FA658C2, 128) & x) ^ xor_bits(BitVecVal(0x87820840, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1C4CDE17C7DE9258195055E9265D221, 128) & x) ^ xor_bits(BitVecVal(0x4044E03C3CE0008080000E0020C000, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x760DB29068A310965, 128) & x) ^ xor_bits(BitVecVal(0x12049000200100020, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x5F6FB1F353B814B83DFAB039F, 128) & x) ^ xor_bits(BitVecVal(0xF2790F1019800181CF81018F, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xBC0919D732BD93E1E7977D3B7B, 128) & x) ^ xor_bits(BitVecVal(0x1C0008C3101C81E0E3833C1939, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x5D31D733E3387235ECC, 128) & x) ^ xor_bits(BitVecVal(0xC10C311E1183010E44, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x2F6A4694FA4052C180C72D95FF, 128) & x) ^ xor_bits(BitVecVal(0x72002007800004080430480FF, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xFFBC69460FD68BE9D350, 128) & x) ^ xor_bits(BitVecVal(0x3F9C200207C201E0C100, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x14BDFBEFE7, 128) & x) ^ xor_bits(BitVecVal(0x1CF9E7E3, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x253F95DEE35BCE76A0EA615EB11D698, 128) & x) ^ xor_bits(BitVecVal(0x1F80CE6109C6320060200E100C208, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x161B1831E960, 128) & x) ^ xor_bits(BitVecVal(0x2090810E020, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xE60, 128) & x) ^ xor_bits(BitVecVal(0x220, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x1, 128) & x) ^ xor_bits(BitVecVal(0x0, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x27A34B, 128) & x) ^ xor_bits(BitVecVal(0x38101, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x2A6578A4772D94E8, 128) & x) ^ xor_bits(BitVecVal(0x20380033048060, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x27D96036E73482CFEBC7, 128) & x) ^ xor_bits(BitVecVal(0x3C8201263100047E1C3, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xF7D2916E7B86CBC1EAA90C6D91CBD6D2, 128) & x) ^ xor_bits(BitVecVal(0x33C00026398241C0E000042480C1C240, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x7F5C045BF883B66C591E7D63, 128) & x) ^ xor_bits(BitVecVal(0x1F0C0009F8019224080E3C21, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x230C9D771C, 128) & x) ^ xor_bits(BitVecVal(0x1040C330C, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x65C3, 128) & x) ^ xor_bits(BitVecVal(0xC1, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xA0F976CAC739C6EA72493E20A84D29, 128) & x) ^ xor_bits(BitVecVal(0x7832404318C26030001E00000400, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x5C14054D9, 128) & x) ^ xor_bits(BitVecVal(0xC0000048, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xB36DDC2F, 128) & x) ^ xor_bits(BitVecVal(0x1124CC07, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x204B38A49FB9E97EFBE5E5, 128) & x) ^ xor_bits(BitVecVal(0x118000F98E03E79E0E0, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x2B98A6879C51C9A3FC98297AC62FAAE5, 128) & x) ^ xor_bits(BitVecVal(0x18802038C00C081FC08003842078060, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x102B85, 128) & x) ^ xor_bits(BitVecVal(0x180, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x13EEC3E9B7A62DE368BF9, 128) & x) ^ xor_bits(BitVecVal(0x1E641E0938204E1201F8, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x52225B78259, 128) & x) ^ xor_bits(BitVecVal(0x938008, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x16C9B2152C1AD870E0D19D979D3158F8, 128) & x) ^ xor_bits(BitVecVal(0x24090000408483060408C838C100878, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x3D6A84016CE76CDF9788C6CF07988A, 128) & x) ^ xor_bits(BitVecVal(0xC2000002463244F83804247038800, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x45B1FFF0C4B02E1605, 128) & x) ^ xor_bits(BitVecVal(0x90FFF04010060200, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x4A67A61, 128) & x) ^ xor_bits(BitVecVal(0x23820, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x6E, 128) & x) ^ xor_bits(BitVecVal(0x6, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1D6BB8D17902FB4A8F, 128) & x) ^ xor_bits(BitVecVal(0x42198403800790007, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x8FA1BC3BDBC15350, 128) & x) ^ xor_bits(BitVecVal(0x7809C19C9C00100, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x168, 128) & x) ^ xor_bits(BitVecVal(0x20, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xBBE7539D2F7076F4CE1FCC1EF3CA8EB, 128) & x) ^ xor_bits(BitVecVal(0x19E3018C07303270460FC40E71C0061, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x1DC9E17, 128) & x) ^ xor_bits(BitVecVal(0x4C0E03, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x8985169ABA2ED, 128) & x) ^ xor_bits(BitVecVal(0x80020818064, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xE1BBE1C0CD10, 128) & x) ^ xor_bits(BitVecVal(0x2099E0C04400, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x7D371F4E0F5F0BF3F03955, 128) & x) ^ xor_bits(BitVecVal(0x1C130F06070F01F1F01800, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x3C0E6DF6B620EE, 128) & x) ^ xor_bits(BitVecVal(0xC0624F2120066, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x856D694, 128) & x) ^ xor_bits(BitVecVal(0x24200, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xE, 128) & x) ^ xor_bits(BitVecVal(0x2, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1CF36E1E92DDA26711DF8173584D, 128) & x) ^ xor_bits(BitVecVal(0x471260E004C802300CF80310804, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x8CDA56927574B1719C6698849, 128) & x) ^ xor_bits(BitVecVal(0x4480200303010308C2208000, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x18F63280A9C35EAE, 128) & x) ^ xor_bits(BitVecVal(0x72100000C10E06, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x1B6D7D560CA2D83B5146C79, 128) & x) ^ xor_bits(BitVecVal(0x1243C02040048190002438, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x7D5EC3A7E8F086BD8C888FB73A7AA, 128) & x) ^ xor_bits(BitVecVal(0x1C0E4183E070021C8400079318380, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x3E, 128) & x) ^ xor_bits(BitVecVal(0xE, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x71C2EA7DD6721FBB31A755F7F0, 128) & x) ^ xor_bits(BitVecVal(0x10C0603CC2300F99108300F3F0, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x1D8006A2ECC30EC6E96060612484CB, 128) & x) ^ xor_bits(BitVecVal(0x48002006441064260202020000041, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x40D7BF53BD2B, 128) & x) ^ xor_bits(BitVecVal(0x439F019C01, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x31B9C7CE6BA08F87CBB, 128) & x) ^ xor_bits(BitVecVal(0x98C3C621800783C19, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x3, 128) & x) ^ xor_bits(BitVecVal(0x0, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x389D589A2F5D200CF, 128) & x) ^ xor_bits(BitVecVal(0x80C0808070C00047, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x66E1D, 128) & x) ^ xor_bits(BitVecVal(0x260C, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xAE40064FE2D6E6, 128) & x) ^ xor_bits(BitVecVal(0x6000207E04262, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0xB2F81EBF410D713BCBE, 128) & x) ^ xor_bits(BitVecVal(0x10780E1F00043019C1E, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xA487A1A738B137F6E5F0A12285E4, 128) & x) ^ xor_bits(BitVecVal(0x38083181013F260F0000000E0, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xEF2F92935FDEFCBF4D5822E, 128) & x) ^ xor_bits(BitVecVal(0x270780010FCE7C1F0408006, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x3A4B402B51711661FBC7B32BE93, 128) & x) ^ xor_bits(BitVecVal(0x801000100300220F9C39101E01, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x35DD6F859D74F, 128) & x) ^ xor_bits(BitVecVal(0xCC27808C307, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x21F407CE26E40E2, 128) & x) ^ xor_bits(BitVecVal(0xF003C60260060, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x375BF3A, 128) & x) ^ xor_bits(BitVecVal(0x309F18, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x181A253BC548D3FBC8AE18E23, 128) & x) ^ xor_bits(BitVecVal(0x80019C00041F9C00608601, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1F509272889043217CFC56, 128) & x) ^ xor_bits(BitVecVal(0x7000030000001003C7C02, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x22054C3647A1536F25EBA457C, 128) & x) ^ xor_bits(BitVecVal(0x4120380012700E18003C, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x153BFBDD, 128) & x) ^ xor_bits(BitVecVal(0x19F9CC, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x9D2B6EBF232E4A9, 128) & x) ^ xor_bits(BitVecVal(0xC01261F0106000, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xA52B, 128) & x) ^ xor_bits(BitVecVal(0x1, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x330D8F33869AED44B8A5255, 128) & x) ^ xor_bits(BitVecVal(0x1048711820864001800000, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x17CBFC73336, 128) & x) ^ xor_bits(BitVecVal(0x3C1FC31112, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x8D6AF39F592011E48AA7CB4B, 128) & x) ^ xor_bits(BitVecVal(0x420718F080000E00003C101, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x14A33B1D24F27764FB0656A8CF, 128) & x) ^ xor_bits(BitVecVal(0x1190C007033207902020047, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xED0C2, 128) & x) ^ xor_bits(BitVecVal(0x24040, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1480871DCFB0535517EBBFB28DCA6, 128) & x) ^ xor_bits(BitVecVal(0x30CC790010003E19F9004C02, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x56D11B00CAFA443E11C9393D655A2375, 128) & x) ^ xor_bits(BitVecVal(0x24009004078001E00C0181C20080130, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xD2CA4211947191AE2C9B9F70FE7, 128) & x) ^ xor_bits(BitVecVal(0x4000008030808604098F307E3, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x12EEF0835, 128) & x) ^ xor_bits(BitVecVal(0x6670010, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x297C1A8D8, 128) & x) ^ xor_bits(BitVecVal(0x3C08048, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xAF5FBBA6506348A9199FC, 128) & x) ^ xor_bits(BitVecVal(0x70F998200210000088FC, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x82FE3E666BB603B908E800, 128) & x) ^ xor_bits(BitVecVal(0x7E1E2221920198006000, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0xB72AF73E919A14C2273070ED5C1DC, 128) & x) ^ xor_bits(BitVecVal(0x1300731E00880040031030640C0CC, 128) & x & RotateRight(x,1)))
    s.add(0 == xor_bits(BitVecVal(0x1FBD2A505F0CA679799, 128) & x) ^ xor_bits(BitVecVal(0x79C00000F040238388, 128) & x & RotateRight(x,1)))
    s.add(1 == xor_bits(BitVecVal(0x1D0F097C310F92E3C2BF8D42, 128) & x) ^ xor_bits(BitVecVal(0x407003C10078061C01F8400, 128) & x & RotateRight(x,1)))
     
    print(s.check())
    model = s.model()
    print(model)


    Преобразовав найденные биты в строку, получаем первый ключ: ItWasJustAWarmUp.

    Stage #2


    bool __cdecl sub_42CEF0(char *a1)
    {
      bool result; // al
      __int64 v2; // [esp+0h] [ebp-3Ch]
      __int64 v3; // [esp+8h] [ebp-34h]
      __int64 v4; // [esp+10h] [ebp-2Ch]
      __int64 v5; // [esp+18h] [ebp-24h]
      __int64 v6; // [esp+20h] [ebp-1Ch]
      int v7; // [esp+28h] [ebp-14h]
      int v8; // [esp+2Ch] [ebp-10h]
      int v9; // [esp+30h] [ebp-Ch]
      int v10; // [esp+34h] [ebp-8h]
      int v11; // [esp+38h] [ebp-4h]
    
      v6 = *(_QWORD *)a1;
      v5 = *((_QWORD *)a1 + 1);
      v4 = *((_QWORD *)a1 + 2);
      v3 = *((_QWORD *)a1 + 3);
      v2 = *((_QWORD *)a1 + 4);
      (**off_444360)(off_444360, &v6, 0, off_44435C);
      (**off_444360)(off_444360, &v5, 0, off_44435C);
      (**off_444360)(off_444360, &v4, 0, off_44435C);
      (**off_444360)(off_444360, &v3, 0, off_44435C);
      (**off_444360)(off_444360, &v2, 0, off_44435C);
      v11 = 0;
      result = 0;
      if ( v6 == qword_442780 )
      {
        v10 = 8;
        if ( v5 == __PAIR__(*((_DWORD *)&qword_442780 + 3), *((_DWORD *)&qword_442780 + 2)) )
        {
          v9 = 16;
          if ( v4 == __PAIR__(*((_DWORD *)&qword_442780 + 5), *((_DWORD *)&qword_442780 + 4)) )
          {
            v8 = 24;
            if ( v3 == __PAIR__(*((_DWORD *)&qword_442780 + 7), *((_DWORD *)&qword_442780 + 6)) )
            {
              v7 = 32;
              if ( v2 == __PAIR__(*((_DWORD *)&qword_442780 + 9), *((_DWORD *)&qword_442780 + 8)) )
                result = 1;
            }
          }
        }
      }
      return result;
    }

    Введённая строка представляется в виде пяти 64-битных чисел, результат преобразования которых сравнивается с массивом.
    image
    Прогулявшись под отладчиком, видим такую последовательность вызова функций:

    Пока видно, что третий аргумент передаётся по цепочке вызовов, иногда складываясь по модулю 2 с единицей, иногда с очередным битом введённой строки (хотя некоторые биты, например, первый, пропускаются).

    Посмотрим, где происходит модификация преобразуемого числа, поставив точку останова на запись в соответствующие байты памяти:
    image
    Т.е. бит числа заменяется на значение третьего аргумента, его предыдущее значение передаётся дальше (иногда инвертированное). Можно предположить, что происходит следующее преобразование:
    a3 = xor_all_bits(input & x) ^ y;
    output = ((input << 1) ^ z) | a3;

    • x определяет биты, которые не были пропущены на первом этапе;
    • y зависит от того, сколько раз была добавлена единица (по модулю 2);
    • z соответствует битам, инвертированным на втором этапе.

    Чтобы определить неизвестные константы, получим преобразованные значения для нуля и чисел с одним установленным битом. Для этого определим счётчик
    extern i; i = 0;
    и в функции sub_428FD0 перед очередным раундом поставим точку останова с условием, которое будет печатать значение числа после вызова функции, выставлять очередное его значение и повторять вызов функции.
    print(Qword(Qword(ebp+8))), i=i+1, (i<64)?patch_qword(Qword(ebp+8), __int64(1) << i)^(eip=0x428FE0):0,0

    Получились такие значения:

    Откуда:
    • x = 0x11CE9E8E6CF2B888
    • y = 1
    • z = 0x8E2B550A6AEDD63A

    Итого на Python функция преобразования выглядит так:
    def xor_bits(x):
      a = 0
      while x != 0:
        a ^= x & 1
        x >>= 1
      return a
    
    def round(x):
        x = ((x << 1) & 0xFFFFFFFFFFFFFFFF) | xor_bits(x & 0x8e2b550a6aedd63a) ^ 1
        return x ^ 0x11CE9E8E6CF2B888
    
    def encrypt(x):
        for _ in range(64):
            x = round(x)
        return x

    И обратная ему:
    def rev_round(x):
        x ^= 0x11CE9E8E6CF2B888
        a = x & 1
        x >>= 1
        if xor_bits(x & 0x8e2b550a6aedd63a) ^ 1 != a:
            x |= 1 << 63
        return x
    
    def decrypt(x):
        for _ in range(64):
            x = rev_round(x)
        return x

    Применив преобразование к числам из массива qword_442780, получаем искомую строку: YourReversingSkillsAreImpressive_zN2018.

    Day2. Blackanwyte


    За помощь в подготовке задания благодарим Vlad Roskov из @leetmore.



    При переходе по ссылке видим следующее:



    Нас просят ввести некий промокод. Посмотрим, какие файлы загружаются при открытии страницы.



    Полистав whitebox.js находим функцию, проверяющую промокод:


    В переменную c считывается введённый текст; проверяется, соответствует ли он регулярному выражению "/\d+-\w+/", значит промокод должен быть вида «1234-ABCD». Далее число переводится в двоичный вид, нулям соответствует «N», а единицам — «Z». После перестановки по числам из массива f, в цикле от 4 букв из полученной строки берётся хэш md5, и его первые четыре символа сверяются с соответствующими символами из строки «7177a294cfa7b53371776be5cfa74ddf».

    Для получения правильного числа напишем небольшой скрипт.


    В результате получаем необходимое число, первую часть нашего промокода: 234082018.



    Первую часть проверки мы прошли. Перейдём ко второй:



    Видно, что возвращенное из функции blackbox_check значение проверяется, и если не произошло ошибки, и оно равно «elee757bc7fd00d5», то отправляется на сервер. Однако в файле whitebox.js нет упоминания blackbox_check, значит пора открыть blackbox.js.

    После того, как текстовый редактор справился с открытием длинного файла, видим в нём необходимую нам функцию blackbox_check, а в ней - интересную строчку (22).


    Погуглив, узнаём, что мы столкнулись с эмулятором, написанным на Javascript.
    В переменной code хранятся байты исполняемого файла, в строке 32 производится запись промокода в память, в 33 строке задаётся адрес стэка. Из строки 41 видно, что файл запускается, начиная с адреса «0x080485E0».

    Сохраним исполняемый файл и посмотрим что в нём с помощью IDA.


    Перейдём в blackbox_check. Здесь мы видим какую-то хэш-функцию. После нескольких неудачных попыток найти возможности для быстрого брута или другие уязвимости в алгоритме, замечаем, что буфер, в который копируется часть строки после тире, ограничен всего 256 символами.

    blackbox_check


    Проверяем с помощью checksec и видим, что стэк является исполняемым:
    Примечание — на скриншоте и в тексте автора врайтапа есть расхождения насчет того, является ли стек исполняемым. В действительности, код исполнить можно.


    Учитывая то, что мы уже знаем адрес в стэке, куда запишется наша строка, дело за малым — записать в нужный адрес байты из строки «e1ee757bc7fd00d5».



    Через консоль отправляем получившуюся строку и забираем флаг:

    Искомая строка



    Искомая строка: Bl4CK_0r_wYT3_It5_z3r0Ni6hT



    Day3. Pad me


    Hey, this group still use an old-style messaging system. We assume members are in their thirties and such is their crypto. Try finding flaws there. Their messaging system is at 51.15.79.170 And you know what? We could intercept a piece of their authentication request.
    You can make use of it ytW81KkHaGOnaqiG7Gr4AA==:XXnpfKJoUCufBm2ztTXGCN6wgqLeScU8+XlL7Co5oHg=


    1. I have received 403 error after post «ytW81KkHaGOnaqiG7Gr4AA==:XXnpfKJoUCufBm2ztTXGCN6wgqLeScU8+XlL7Co5oHg=” string. If change some letters – still receive 403 error, it change letter count – receive 500 error. After some investigations I realized that first part sould be 16 bytes long in base64-decoded form, and second part must contain some blocks 16 bytes long each. Seems first part is IV and second part – encoded data in CBC mode, and according to task name „pad” it is padding oracle attack.

    2. Lets change last byte in base64 decoded form of second part (01.php script, total 256 possibilities). For one case instead of “403” error I have received message „Sir, your message is incorrect or it is not 48 bytes long”

    01.php script
    <?php
    
      $s = "7177a294cfa7b53371776be5cfa74ddf";
      $r = "";
      for($i=0;$i<32;$i+=4)
      {
        for($j=0;$j<16;$j++)
        {
          $a = sprintf("%04b", $j);
          $a = str_replace("0", "Z", $a);
          $a = str_replace("1", "N", $a);
          if (substr(md5($a), 0, 4) == substr($s, $i, 4)) break;
        }
        if ($j == 16) die("Error 1: {$i}");
        $r .= $a;
        echo md5($r).": ".$r."\r\n";
      }
    
      $p = array(22,30,25,23,2,20,0,11,24,6,31,3,16,12,9,15,27,28,18,1,21,4,8,13,17,7,19,29,5,26,14,10);
      $s = str_repeat("_", 32);
      for($i=0;$i<32;$i++)
        $s[$p[$i]] = $r[$i];
      echo $s."\r\n";
    
      $a = 0;
      for($i=0;$i<32;$i++)
      {
        if ($s[$i] == 'Z') $a += (1<<$i);
      }
      echo $a."\r\n";


    3. Lets decrypt message from task using padding oracle attack (scripts 02.php and 02b.php) – I have received string “Never gonna give you up\nNever go”.

    02.php script
    <?php
    $a = „ytW81KkHaGOnaqiG7Gr4AA==:XXnpfKJoUCufBm2ztTXGCN6wgqLeScU8+XlL7Co5oHg=“;
    $a = explode(»:", $a);
    $a[0] = base64_decode($a[0]);
    $a[1] = base64_decode($a[1]);
    file_put_contents(«01.bin», $a[0].$a[1]);

    $s = $a[1];
    $known = "";
    for($i=1;$i<=16;$i++)
    {

    for($j=0;$j<256;$j++)
    {
    $iv = str_repeat(«A», 16-$i).((chr($j).$known) ^ str_repeat(chr($i), $i));
    if (($r = send($iv, substr($s, 0, 16))) !== false)
    {
    echo $r."\r\n";
    $known = chr($j).$known;
    echo bin2hex($known)." ".($known ^ substr($a[0], -$i))."\r\n";
    break;
    }
    }
    if ($j == 256) die(«Error 1: {$i}»);
    }

    function send($a, $b)
    {
    $data = base64_encode($a).":".base64_encode($b);

    $s = «POST / HTTP/1.0\r\n»;
    $s.= «Host: 51.15.79.170\r\n»;
    $s.= «Content-Length: ».strlen($data)."\r\n";
    $s.= «User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0\r\n»;
    $s.= "\r\n";
    $s.= $data;

    $r = "";
    do {$socket = fsockopen(«51.15.79.170», 80);} while(!$socket);
    fwrite($socket, $s);
    while(!@feof($socket)) $r .= fread($socket, 4096);
    fclose($socket);

    if (strpos($r, «500 INTERNAL SERVER ERROR»)) die(«Error 2: {$data}»);

    return (strpos($r, «403 FORBIDDEN») !== false)?false:$r;
    }


    Never gonna give you up
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:49:08 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    0f0cc904c9a68b038e65 gonna give
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:49:25 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    270f0cc904c9a68b038e65 gonna give
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:50:10 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    db270f0cc904c9a68b038e65 r gonna give
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:51:11 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    b1db270f0cc904c9a68b038e65 er gonna give
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:52:15 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    cab1db270f0cc904c9a68b038e65 ver gonna give
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:53:19 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    b0cab1db270f0cc904c9a68b038e65 ever gonna give
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:54:15 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    84b0cab1db270f0cc904c9a68b038e65 Never gonna give

    02b.php script
    <?php
      $a = "ytW81KkHaGOnaqiG7Gr4AA==:XXnpfKJoUCufBm2ztTXGCN6wgqLeScU8+XlL7Co5oHg=";
      $a = explode(":", $a);
      $a[0] = base64_decode($a[0]);
      $a[1] = base64_decode($a[1]);
      file_put_contents("01.bin", $a[0].$a[1]);
    
      $s = substr($a[1], 16);
      $iv2 = substr($a[1], 0, 16);
      $known = "";
      for($i=1;$i<=16;$i++)
      {
    
        for($j=0;$j<256;$j++)
        {
          $iv = str_repeat("A", 16-$i).((chr($j).$known) ^ str_repeat(chr($i), $i));
          if (($r = send($iv, substr($s, 0, 16))) !== false)
          {
            echo $r."\r\n";
            $known = chr($j).$known;
            echo bin2hex($known)." ".($known ^ substr($iv2, -$i))."\r\n";
            break;
          }
        }
        if ($j == 256) die("Error 1: {$i}");
      }
    
    
      function send($a, $b)
      {
        $data = base64_encode($a).":".base64_encode($b);
    
        $s = "POST / HTTP/1.0\r\n";
        $s.= "Host: 51.15.79.170\r\n";
        $s.= "Content-Length: ".strlen($data)."\r\n";            
        $s.= "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0\r\n";
        $s.= "\r\n";
        $s.= $data;
    
        $r = "";
        do  {$socket = @fsockopen("51.15.79.170", 80);} while(!$socket);
        fwrite($socket, $s);
        while(!@feof($socket)) $r .= fread($socket, 4096);
        fclose($socket);
    
        if (strpos($r, "500 INTERNAL SERVER ERROR")) die("Error 2: {$data}");
    
        return (strpos($r, "403 FORBIDDEN") !== false)?false:$r;
      }


    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:50:12 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    67 o
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:51:11 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    a167 go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:51:14 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    15a167 go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:52:30 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    c715a167 r go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:53:57 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    d6c715a167 er go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:54:15 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    1bd6c715a167 ver go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:54:28 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    631bd6c715a167 ever go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:55:21 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    d1631bd6c715a167 Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:55:43 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    21d1631bd6c715a167
    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:55:47 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    2021d1631bd6c715a167 p
    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:55:51 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    1d2021d1631bd6c715a167 up
    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:56:07 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    821d2021d1631bd6c715a167 up
    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:56:08 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    09821d2021d1631bd6c715a167 u up
    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:56:52 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    8609821d2021d1631bd6c715a167 ou up
    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:56:52 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    008609821d2021d1631bd6c715a167 you up
    Never go
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 21:57:10 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    7d008609821d2021d1631bd6c715a167 you up
    Never go

    4. Ok, seems the message was truncated (should be 48 bytes long). Using google I have found some song with full phase "Never gonna give you up\nNever gonna let you down”. Lets encrypt it using padding oracle attack from last block till first block and iv (scripts 05.php and 04_brute.php).

    04_brute.php script
    <?php
      $a = "ytW81KkHaGOnaqiG7Gr4AA==:XXnpfKJoUCufBm2ztTXGCN6wgqLeScU8+XlL7Co5oHg=";
      $a = explode(":", $a);
      $a[0] = base64_decode($a[0]);
      $a[1] = base64_decode($a[1]);
      file_put_contents("01.bin", $a[0].$a[1]);
    
      $s = hex2bin("ff4fba7f36536f04bd0a3f77b8b06dde");
      $known = "";
      for($i=1;$i<=16;$i++)
      {
    
        for($j=0;$j<256;$j++)
        {
          $iv = str_repeat("A", 16-$i).((chr($j).$known) ^ str_repeat(chr($i), $i));
          if (($r = send($iv, substr($s, 0, 16))) !== false)
          {
            echo $r."\r\n";
            $known = chr($j).$known;
            echo bin2hex($known)."\r\n";
            break;
          }
        }
        if ($j == 256) die("Error 1: {$i}");
      }
    
    
      function send($a, $b)
      {
        $data = base64_encode($a).":".base64_encode($b);
    
        $s = "POST / HTTP/1.0\r\n";
        $s.= "Host: 51.15.79.170\r\n";
        $s.= "Content-Length: ".strlen($data)."\r\n";            
        $s.= "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0\r\n";
        $s.= "\r\n";
        $s.= $data;
    
        $r = "";
        do  {$socket = @fsockopen("51.15.79.170", 80);} while(!$socket);
        fwrite($socket, $s);
        while(!@feof($socket)) $r .= fread($socket, 4096);
        fclose($socket);
    
        if (strpos($r, "500 INTERNAL SERVER ERROR")) die("Error 2: {$data}");
    
        return (strpos($r, "403 FORBIDDEN") !== false)?false:$r;
      }
    


    05.php
    <?php
    
      $a = "ytW81KkHaGOnaqiG7Gr4AA==:XXnpfKJoUCufBm2ztTXGCN6wgqLeScU8+XlL7Co5oHg=";
      $a = explode(":", $a);
      $a[0] = base64_decode($a[0]);
      $a[1] = base64_decode($a[1]);
    
      $Q = "Never gonna give you up\nNever gonna let you down".str_repeat("\x10", 0x10);
      echo strlen($Q)."\r\n";
    
      $e1 = substr($a[1], 0, 16);
      $d1 = $a[0] ^ "Never gonna give";
    
      $e2 = $d1 ^ substr($Q, 48, 16);
      echo bin2hex($e2)."\r\n";
      $d2 = hex2bin("9e3d4885d3be30498069cfc4992e73df");
    
      $e3 = $d2 ^ substr($Q, 32, 16);
      echo bin2hex($e3)."\r\n";
      $d3 = hex2bin("df36d50a16261f0ef36f4912ca900ab1");
    
      $e4 = $d3 ^ substr($Q, 16, 16);
      echo bin2hex($e4)."\r\n";
      $d4 = hex2bin("20c3540ec72fa0b486b5f0c868218360");
    
      $e5 = $d4 ^ substr($Q, 0, 16);
      echo bin2hex($e5)."\r\n";
    
      $a[0] = $e5;
      $a[1] = $e4.$e3.$e2.$e1;  
    
      $data = base64_encode($a[0]).":".base64_encode($a[1]);
      $s = "POST / HTTP/1.0\r\n";
      $s.= "Host: 51.15.79.170\r\n";
      $s.= "Content-Length: ".strlen($data)."\r\n";            
      $s.= "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0\r\n";
      //$s.= "Content-Type: application/x-www-form-urlencoded\r\n";
      $s.= "\r\n";
      $s.= $data;
    
    
      $socket = fsockopen("51.15.79.170", 80);
      fwrite($socket, $s);
      while(!@feof($socket)) echo fread($socket, 4096);
      fclose($socket);


    20c3540ec72fa0b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:51:49 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    60
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:52:05 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    8360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:52:15 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:52:52 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    68218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:53:56 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:55:08 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:56:09 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:57:05 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    86b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:58:03 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:58:59 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    a0b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Tue, 23 Oct 2018 23:59:05 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    2fa0b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Wed, 24 Oct 2018 00:00:08 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    c72fa0b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Wed, 24 Oct 2018 00:00:10 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    0ec72fa0b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Wed, 24 Oct 2018 00:00:21 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    540ec72fa0b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Wed, 24 Oct 2018 00:01:21 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    c3540ec72fa0b486b5f0c868218360
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Wed, 24 Oct 2018 00:01:34 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 57
    Connection: close

    Sir, your message is incorrect or it is not 48 bytes long
    20c3540ec72fa0b486b5f0c868218360

    Искомая строка
    64
    94a0daa1cb371f1cd914d9b69b139e75
    f05329a5bfdb4469f906bae4fd4104b1
    ff4fba7f36536f04bd0a3f77b8b06dde
    6ea6226bb50fc7dbe8db91e80f48f505
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Wed, 24 Oct 2018 00:01:51 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 73
    Connection: close

    Okey, I see you're from 80's, get in
    <Wh4t_1f_R1ck_A3tl3y_Sm0ke_Cannab1s>
    Digital Security
    214,00
    Безопасность как искусство
    Поделиться публикацией

    Похожие публикации

    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое