Bank Vault - author: overllama - rev

WriteUp: m1nds

The challenge aims at reversing a dynamically linked x86-64 binary.

file bank
bank: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=10134ec844feac04728fa961c1684b6570624034, for GNU/Linux 3.2.0, not stripped

Using Ghidra, we can see the decompilation of the main function. After careful analysis, we can determine that C.0.0 array is a boolean array. C.1.1 contains data. We can also see that the boolean array determine if a character is an important character, other characters are only noise. With this information, we can easily retrieve the flag.

undefined8 main(void)

{
  undefined4 uVar1;
  bool bVar2;
  undefined4 *puVar3;
  char *pcVar4;
  ulong uVar5;
  basic_ostream *pbVar6;
  ulong uVar7;
  undefined auVar8 [16];
  vector<> local_148 [48];
  basic_string local_118 [32];
  vector<> local_f8 [32];
  vector local_d8 [48];
  vector local_a8 [46];
  __new_allocator<bool> local_7a;
  __new_allocator<> local_79;
  undefined local_78 [16];
  undefined local_68 [16];
  undefined local_58 [16];
  __new_allocator<> *local_48;
  __new_allocator<bool> *local_40;
  undefined local_32;
  char local_31;
  int local_30;
  int local_2c;
  
  local_40 = &local_7a;
                    /* try { // try from 00101240 to 00101244 has its CatchHandler @ 001014e5 */
  std::vector<>::vector((initializer_list)local_a8,(allocator *)C.0.0);
  std::__new_allocator<bool>::~__new_allocator(&local_7a);
                    /* try { // try from 00101266 to 0010126a has its CatchHandler @ 00101558 */
  std::vector<>::vector(local_d8);
  local_48 = &local_79;
                    /* try { // try from 0010129c to 001012a0 has its CatchHandler @ 00101500 */
  std::vector<>::vector((initializer_list)local_f8,(allocator *)C.1.1);
  std::__new_allocator<>::~__new_allocator(&local_79);
  std::__cxx11::basic_string<>::basic_string();
                    /* try { // try from 001012d1 to 001012ee has its CatchHandler @ 00101526 */
  std::operator<<((basic_ostream *)std::cout,"What\'s the password to the bank vault? ");
  std::getline<>((basic_istream *)std::cin,local_118);
  local_2c = 0;
  std::vector<>::vector();
  local_31 = '\0';
  local_30 = 0;
  while( true ) {
    uVar7 = (ulong)local_30;
    uVar5 = std::vector<>::size();
    if (uVar5 <= uVar7) break;
    auVar8 = std::vector<>::back();
    local_78 = auVar8;
    local_31 = std::_Bit_reference::operator.cast.to.bool((_Bit_reference *)local_78);
                    /* try { // try from 0010134e to 0010148f has its CatchHandler @ 00101512 */
    puVar3 = (undefined4 *)std::vector<>::at(local_f8,(long)local_30);
    uVar1 = *puVar3;
    pcVar4 = (char *)std::__cxx11::basic_string<>::operator[]((ulong)local_118);
    local_32 = (char)((uint)uVar1 >> 0x10) == *pcVar4;
    if (local_31 != '\0') {
      local_2c = local_2c + 1;
    }
    std::vector<>::push_back(local_148,(bool)local_32);
    std::vector<>::pop_back();
    local_30 = local_30 + 1;
  }
  local_68 = std::vector<>::end();
  local_58 = std::vector<>::begin();
  std::reverse<>(local_58._0_8_,local_58._8_8_,local_68._0_8_,local_68._8_8_);
  bVar2 = std::operator==((vector *)local_148,local_a8);
  if (bVar2) {
    pbVar6 = std::operator<<((basic_ostream *)std::cout,"Access granted!");
    std::basic_ostream<>::operator<<((basic_ostream<> *)pbVar6,std::endl<>);
  }
  else {
    pbVar6 = std::operator<<((basic_ostream *)std::cout,"Access denied!");
    std::basic_ostream<>::operator<<((basic_ostream<> *)pbVar6,std::endl<>);
  }
  std::vector<>::~vector(local_148);
  std::__cxx11::basic_string<>::~basic_string((basic_string<> *)local_118);
  std::vector<>::~vector(local_f8);
  std::vector<>::~vector((vector<> *)local_d8);
  std::vector<>::~vector((vector<> *)local_a8);
  return 0;
}

Using a simple python scripts that retrieves characters where the index is True, we can retrieve the flag :

def reverse():
    mark = [
        False, False, False, False, False, True, True, True, True, False, False, False, False, True,
        False, True, True, False, False, False, False, True, False, True, True, False, True, False,
        False, True, True, False, True, True, False, False, False, False, True, False, False, True,
        False, True, False, True, False, False, True, False, False, True, False, False, True, False,
        True, False, False, True, True, False, False, False, False, True, False, True, False, False,
        False, True, True, True, False, True, False, True, True, True, True, False, True, True
    ]

    keys = [
        0xf16285bd, 0x4d79b336, 0x3607c041, 0x4f757c48, 0x63634432, 0x8474be64, 0x2f66bfed,
        0x8c8ba74b, 0xcb7bb04c, 0x29aa35bb, 0xdc33e9f9, 0xb37642ea, 0x1133f4df, 0x6819b1cf,
        0xac1b2111, 0x797e383b, 0xe46e41f5, 0x38e144f9, 0xaa5f25b7, 0x36e31d2b, 0x17cd4129,
        0xcf9276a9, 0x9675f6, 0xed76e994, 0x1e33fc99, 0x75157513, 0x996d3e0c, 0x5b633cab,
        0x60d22379, 0xfc740809, 0xcb43d953, 0xf9cfead5, 0xb1304006, 0xca841431, 0x2aece666,
        0xdb72fb63, 0x73862a0f, 0x21ff2a98, 0x3b73281b, 0x1322483e, 0x565f373a, 0xbf32aa3e,
        0x9d345021, 0xc003dd66, 0xfb08399c, 0x677070f7, 0x96d4f926, 0x5aad004, 0x465a312a,
        0xcea1f556, 0xa9706fd9, 0x31330bd6, 0x4241cfa0, 0xfc340a7a, 0x1724268, 0x41e06d3e,
        0xd9111112, 0x635f1af6, 0xeff71436, 0x82311dc8, 0xb56e65d1, 0x98e00125, 0xfe5faeb5,
        0x4d53dae2, 0x980bcea2, 0xb98118bd, 0x8421652d, 0xf76d1209, 0xa4339088, 0xb98085f8,
        0x6f6dea30, 0x2110d58e, 0x443b9947, 0x4529fd1d, 0xf0e27c3e, 0x8530b126, 0x8f72c719,
        0xca794f90, 0x3e7dbb1d, 0xe57c7778, 0x18f32f9e, 0x4d2a5666, 0xe8e18692, 0x9a987ce8
    ]

    mark2 = list(mark)
    input_bytes = []
    index = len(mark2) - 1

    for i in range(len(keys)):
        m = mark2[index]
        if m:
            char_byte = (keys[i] >> 16) & 0xff
            input_bytes.append(char_byte)
        index -= 1

    flag = ''.join(chr(b) for b in input_bytes)

    print(flag)


if __name__ == "__main__":
    reverse()
python3 solve.py
byuctf{3v3n_v3ct0rs_4pp34r_1n_m3m0ry}