[HackCTF] :rev: static

두비니

·

2021. 3. 25. 16:10

 

 

 

 

 

아이다로 디컴파일링했을때는 아무것도 보이지 않습니다.

 

 

뭔가 해서 봤더니, stripped되어있어서 아무것도 볼 수가 없습니다.

 

 

일단 프로그램을 실행시켜보면 "nope"와 함께 나가는 걸 기준으로, ghidra를 통해서 찾아봤습니다.

 

보니 해당 스트링과, 문제에서 쓰이는 것 같은 문자열들이 있네요.

따라서 거기에 해당하는 함수들을 찾아보았습니다.

 

/* WARNING: Removing unreachable block (ram,0x00100b11) */
/* WARNING: Removing unreachable block (ram,0x00100a56) */

undefined8 main(int param_1,long param_2)

{
  int iVar1;
  char *__s1;
  
  __s1 = getenv("team_name");
  if ((__s1 == (char *)0x0) || (iVar1 = strncmp(__s1,"bi0s",4), iVar1 != 0)) {
    printf("Nope.");
  }
  else {
    if (param_1 == 2) {
      iVar1 = FUN_0010087c(__s1,*(undefined8 *)(param_2 + 8),*(undefined8 *)(param_2 + 8));
      if (iVar1 == 1) {
        getflag(*(undefined8 *)(param_2 + 8));
      }
      else {
        printf("Better luck next time!");
      }
    }
    else {
      printf("usage: chall <input>");
    }
  }
  return 0;
}

 

 

보니깐 FUN_0010087c의 리턴값이 1인 경우에 플래그를 출력시켜주네요.

 

/* WARNING: Removing unreachable block (ram,0x00100849) */

void getflag(undefined8 param_1)

{
  printf("HackCTF{%s}",param_1);
  return;
}

우선 getflag같은 경우에는 플래그를 출력시켜주네요. (함수 이름은 제가 임의적으로 바꾼 것입니다.)

 

그리고 FUN_0010087c를 봅시다.

 

/* WARNING: Removing unreachable block (ram,0x001009c7) */
/* WARNING: Removing unreachable block (ram,0x00100a2c) */
/* WARNING: Removing unreachable block (ram,0x0010092b) */

undefined8 FUN_0010087c(char *param_1,char *param_2)

{
  size_t sVar1;
  ulong uVar2;
  undefined8 local_70;
  byte local_68 [32];
  undefined8 local_48;
  undefined8 local_40;
  undefined4 local_38;
  undefined2 local_34;
  undefined local_32;
  undefined4 local_30;
  undefined4 local_28;
  uint local_24;
  int local_20;
  int local_1c;
  
  local_20 = 0;
  local_24 = 0;
  local_48 = 0x3931383137313631;
  local_40 = 0x3731363138333632;
  local_38 = 0x31393139;
  local_34 = 0x3439;
  local_32 = 0;
  local_70 = param_1;
  sVar1 = strlen(param_2);
  if (sVar1 == 0x16) {
    local_1c = 0;
    while (uVar2 = SEXT48(local_1c), sVar1 = strlen(local_70), uVar2 < sVar1) {
      local_20 = local_20 + local_70[local_1c];
      local_1c = local_1c + 1;
    }
    local_30 = 0;
    local_20 = local_20 / 0x1e;
    while (local_24 != 0x16) {
      if ((local_24 & 1) == 0) {
        local_68[(int)local_24] = param_2[(int)local_24] + 4;
      }
      else {
        local_68[(int)local_24] = param_2[(int)local_24] - 4;
      }
      local_68[(int)local_24] = local_68[(int)local_24] ^ (byte)local_20;
      local_24 = local_24 + 1;
    }
    local_28 = 0;
    sVar1 = strlen((char *)local_68);
    local_1c = (int)sVar1;
    do {
      local_1c = local_1c + -1;
      if (local_1c < 0) {
        return 1;
      }
      sVar1 = strlen((char *)local_68);
    } while (local_68[(sVar1 - (long)local_1c) + -1] == *(byte *)((long)&local_48 +(long)local_1c))
    ;
  }
  return 0;
}

 

함수가 길어서 복잡해보이는데, 크게 3파트로 나뉘네요,

 

 if (sVar1 == 0x16) {
    local_1c = 0;
    while (uVar2 = SEXT48(local_1c), sVar1 = strlen(local_70), uVar2 < sVar1) {
      local_20 = local_20 + local_70[local_1c];
      local_1c = local_1c + 1;
    }
    local_30 = 0;
    local_20 = local_20 / 0x1e;

우선 param_2의 길이를 담고 있는 sVar1의 값이 0x16이여야합니다. 그리고, local_70은 "bi0s"입니다. 따라서 local_70의 문자열에 각각 담은 것임을 알 수 있습니다.

그리고 그 값들을 모두 더한 값은 0x16e이고, 0x1e로 나누면 local_20의 값은 결국 0xc입니다.

 

 while (local_24 != 0x16) {
      if ((local_24 & 1) == 0) {
        local_68[(int)local_24] = param_2[(int)local_24] + 4;
      }
      else {
        local_68[(int)local_24] = param_2[(int)local_24] - 4;
      }
      local_68[(int)local_24] = local_68[(int)local_24] ^ (byte)local_20;
      local_24 = local_24 + 1;
    }

입력값을 local_68에 옮겨서 짝수자리에 있는 값들은 4를 더한 뒤 local_20과 xor하고, 홀수의 경우에는 4를 뺀 뒤에 local_20과 xor하네요.

 

    local_28 = 0;
    sVar1 = strlen((char *)local_68);
    local_1c = (int)sVar1;
    do {
      local_1c = local_1c + -1;
      if (local_1c < 0) {
        return 1;
      }
      sVar1 = strlen((char *)local_68);
    } while (local_68[(sVar1 - (long)local_1c) + -1] == *(byte *)((long)&local_48 +(long)local_1c))
    ;
  }
  return 0;
}

 

미리 인코딩 되어있는 값과 내가 입력해서 인코딩 된 값을 비교합니다.

그럼 미리 인코딩 된 값만 찾으면 될 것 같아서 gdb로 열었습니다.

 

strip이 안된상황이라 getenv의 마지막에 브레이크포인트를 걸어놓고, 그 다음을 봐서 main의 어셈을 찾아냈습니다.

찾은 과정은 정말 삽질에 삽질이여서 첨부하면 더 헷갈릴 것 같아 생략합니다... 아무튼 삽질을 해서 gdb에서 rbp-0x40에 키가 존재한다는 걸 확인했고, 그걸 가지고 xor을 통해서 키를 구했습니다.

 

ans='4919197161836291817161'
res=''
key=0xc
for i in range(22):
        if i&1==0:
                res+=chr((ord(ans[i])^key)-4)
        else:
                res+=chr((ord(ans[i])^key)+4)
print(res)

 

 

힘드네여

 

'War Games > HackCTF' 카테고리의 다른 글

[HackCTF] :pwn: uaf  (0) 2021.03.30
[HackCTF] :pwn: pwning  (0) 2021.03.27
[HackCTF] :pwn: gift  (0) 2021.03.24
[HackCTF] :pwn: Look at me  (0) 2021.03.23
[HackCTF] :pwn: Beginner_Heap  (0) 2021.03.22