bomb 예제 1 - 제일 쉬운 페이즈

bomb이 주어지는데, 그걸 objdump -d ./bomb 등의 명령어로 풀면 어셈블리 코드가 나옵니다. 실제 수업에서는 사람마다 다른 API key를 받아서 다 다르게 나오는데, 대충 아래와 비슷하게 생겼습니다. 게임처럼 phase가 여러 개이고 모든 phase에 대해 적절한 입력값을 주면 되는데, 깰 때마다 통과했다는 flag가 나오고 그걸 제출하면 됩니다.

0804936a <phase_strcmp>:
 804936a:       55                      push   ebp
 804936b:       89 e5                   mov    ebp,esp
 804936d:       83 ec 18                sub    esp,0x18
 8049370:       c7 45 f4 a8 a6 04 08    mov    DWORD PTR [ebp-0xc],0x804a6a8
 8049377:       83 ec 08                sub    esp,0x8
 804937a:       ff 75 f4                push   DWORD PTR [ebp-0xc]
 804937d:       ff 75 08                push   DWORD PTR [ebp+0x8]
 8049380:       e8 84 fa ff ff          call   8048e09 <strings_not_equal>
 8049385:       83 c4 10                add    esp,0x10
 8049388:       85 c0                   test   eax,eax
 804938a:       74 05                   je     8049391 <phase_strcmp+0x27>
 804938c:       e8 c1 fd ff ff          call   8049152 <explode_bomb>
 8049391:       83 ec 0c                sub    esp,0xc
 8049394:       ff 75 08                push   DWORD PTR [ebp+0x8]
 8049397:       e8 ad fe ff ff          call   8049249 <print_key>
 804939c:       83 c4 10                add    esp,0x10
 804939f:       90                      nop
 80493a0:       c9                      leave
 80493a1:       c3                      ret

위 코드에서 0x804a6a8 이라는 주소가 눈에 띄는데, gdb를 통해 실행 중 해당 주소의 값을 x/s *0x804a6a8 등으로 확인해보면 어떤 문자열이 나옵니다. 이 phase는 첫 번째 phase라 쉬운데, 저 주소에 있는 문자열을 그대로 넣으면 됩니다.

bomb 예제 2 - 어려웠던 페이즈

풀다가 아리까리해서 어셈블리 보면서 //로 주석 달면서 했습니다. 입력값으로는 정수 두 개를 받고, 내부에서 func4 라는 함수를 호출합니다. 저 func4라는 함수가 대체 뭔지 알아내는 데에 엄청 시간을 썼는데, 어셈블리어를 블록 단위로 나눠도 보고 하면서 봤습니다. 알고 보니 페이즈 이름에 힌트가 있었습니다. binary search를 합니다. 이걸 알고 나서 구글링을 했는데 똑같이 써 있어서 그냥 구글링 먼저 할걸… 하는 생각이 들었습니다.

080495f0 <phase_binary>:
 80495f0:       55                      push   ebp
 80495f1:       89 e5                   mov    ebp,esp
 80495f3:       83 ec 28                sub    esp,0x28
 80495f6:       8d 45 e4                lea    eax,[ebp-0x1c] // second input
 80495f9:       50                      push   eax
 80495fa:       8d 45 e8                lea    eax,[ebp-0x18] // first input
 80495fd:       50                      push   eax
 80495fe:       68 0a a7 04 08          push   0x804a70a // "%d %d"
 8049603:       ff 75 08                push   DWORD PTR [ebp+0x8]
 8049606:       e8 f5 f1 ff ff          call   8048800 <__isoc99_sscanf@plt>
 804960b:       83 c4 10                add    esp,0x10
 804960e:       89 45 f4                mov    DWORD PTR [ebp-0xc],eax
 8049611:       83 7d f4 02             cmp    DWORD PTR [ebp-0xc],0x2
 8049615:       75 0f                   jne    8049626 <phase_binary+0x36> // jump not equal - to 8049626
 8049617:       8b 45 e8                mov    eax,DWORD PTR [ebp-0x18]
 804961a:       85 c0                   test   eax,eax
 804961c:       78 08                   js     8049626 <phase_binary+0x36> // jump signed
 804961e:       8b 45 e8                mov    eax,DWORD PTR [ebp-0x18]
 8049621:       83 f8 0e                cmp    eax,0xe                     // 14 in decimal
 8049624:       7e 05                   jle    804962b <phase_binary+0x3b> // jump less or equal
 8049626:       e8 27 fb ff ff          call   8049152 <explode_bomb>
 804962b:       c7 45 f0 0b 00 00 00    mov    DWORD PTR [ebp-0x10],0xb    // 11 in decimal
 8049632:       8b 45 e8                mov    eax,DWORD PTR [ebp-0x18]    // 

 8049635:       83 ec 04                sub    esp,0x4
 8049638:       6a 0e                   push   0xe
 804963a:       6a 00                   push   0x0
 804963c:       50                      push   eax
 804963d:       e8 38 ff ff ff          call   804957a <func4>
 8049642:       83 c4 10                add    esp,0x10

 8049645:       89 45 ec                mov    DWORD PTR [ebp-0x14],eax
 8049648:       8b 45 ec                mov    eax,DWORD PTR [ebp-0x14]
 804964b:       3b 45 f0                cmp    eax,DWORD PTR [ebp-0x10]
 804964e:       75 08                   jne    8049658 <phase_binary+0x68> // jump not equal - to 8049658
 8049650:       8b 45 e4                mov    eax,DWORD PTR [ebp-0x1c]
 8049653:       39 45 f0                cmp    DWORD PTR [ebp-0x10],eax    // second input = 11
 8049656:       74 05                   je     804965d <phase_binary+0x6d> // jump equal
 8049658:       e8 f5 fa ff ff          call   8049152 <explode_bomb>
 804965d:       83 ec 0c                sub    esp,0xc
 8049660:       ff 75 08                push   DWORD PTR [ebp+0x8]
 8049663:       e8 e1 fb ff ff          call   8049249 <print_key>
 8049668:       83 c4 10                add    esp,0x10
 804966b:       90                      nop
 804966c:       c9                      leave
 804966d:       c3                      ret
0804957a <func4>:
 804957a:       55                      push   ebp
 804957b:       89 e5                   mov    ebp,esp
 804957d:       83 ec 18                sub    esp,0x18
 8049580:       8b 45 10                mov    eax,DWORD PTR [ebp+0x10]
 8049583:       2b 45 0c                sub    eax,DWORD PTR [ebp+0xc]
 8049586:       89 c2                   mov    edx,eax
 8049588:       c1 ea 1f                shr    edx,0x1f
 804958b:       01 d0                   add    eax,edx
 804958d:       d1 f8                   sar    eax,1
 804958f:       89 c2                   mov    edx,eax
 8049591:       8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 8049594:       01 d0                   add    eax,edx
 8049596:       89 45 f4                mov    DWORD PTR [ebp-0xc],eax
 8049599:       8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 804959c:       3b 45 08                cmp    eax,DWORD PTR [ebp+0x8]
 804959f:       7e 21                   jle    80495c2 <func4+0x48>
 
 80495a1:       8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80495a4:       83 e8 01                sub    eax,0x1
 80495a7:       83 ec 04                sub    esp,0x4
 80495aa:       50                      push   eax
 80495ab:       ff 75 0c                push   DWORD PTR [ebp+0xc]
 80495ae:       ff 75 08                push   DWORD PTR [ebp+0x8]
 80495b1:       e8 c4 ff ff ff          call   804957a <func4>
 80495b6:       83 c4 10                add    esp,0x10
 80495b9:       89 c2                   mov    edx,eax
 80495bb:       8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80495be:       01 d0                   add    eax,edx
 80495c0:       eb 2c                   jmp    80495ee <func4+0x74>

 80495c2:       8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80495c5:       3b 45 08                cmp    eax,DWORD PTR [ebp+0x8]
 80495c8:       7d 21                   jge    80495eb <func4+0x71>

 80495ca:       8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80495cd:       83 c0 01                add    eax,0x1
 80495d0:       83 ec 04                sub    esp,0x4
 80495d3:       ff 75 10                push   DWORD PTR [ebp+0x10]
 80495d6:       50                      push   eax
 80495d7:       ff 75 08                push   DWORD PTR [ebp+0x8]
 80495da:       e8 9b ff ff ff          call   804957a <func4>
 80495df:       83 c4 10                add    esp,0x10
 80495e2:       89 c2                   mov    edx,eax
 80495e4:       8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80495e7:       01 d0                   add    eax,edx
 80495e9:       eb 03                   jmp    80495ee <func4+0x74>
 80495eb:       8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80495ee:       c9                      leave
 80495ef:       c3                      ret

bomb 예제 3 - 몹시 어려웠던 페이즈

컴퓨터보안 시간에 나왔는데, gdb를 못 쓰는 대신 ghidra를 쓰게 하는 bomb이 있었습니다. 함수 이름의 힌트 같은 건 없고 코드를 보고 알아차려야 하는데, 모든 실행 코드가 .text에 합쳐져 있습니다. ghidra가 있어서 C언어로 대충 번역되는데 그걸로 대강 눈치를 챌 수는 있습니다. 그래도 어렵습니다.

아래 문제는 어셈블리를 ghidra를 통해 C언어로 바꾼 건데, phase_minfuck은 원래 ghidra가 자동생성한 이름이었으나 수정했습니다. 이걸 봐도 모르겠었는데 답은 brainfuck 언어를 사용해 주어진 문자열을 정답 문자열로 바꾸는 것이었습니다.


void phase_minfuck(char *param_1)

{
  size_t sVar1;
  long lVar2;
  ulong uVar3;
  undefined4 *puVar4;
  byte *pbVar5;
  uint uVar6;
  long in_FS_OFFSET;
  undefined uVar7;
  undefined uVar8;
  byte bVar9;
  undefined4 local_88;
  undefined4 uStack132;
  uint uStack128;
  undefined4 uStack124;
  undefined4 local_78;
  undefined4 uStack116;
  undefined4 uStack112;
  undefined4 uStack108;
  undefined4 local_68;
  undefined4 uStack100;
  undefined4 uStack96;
  undefined4 uStack92;
  undefined4 local_58;
  undefined4 uStack84;
  undefined4 uStack80;
  undefined4 uStack76;
  undefined4 local_48;
  undefined4 uStack68;
  undefined4 uStack64;
  undefined4 uStack60;
  undefined4 local_38;
  undefined4 uStack52;
  undefined4 uStack48;
  undefined4 uStack44;
  undefined4 local_28;
  long local_20;
  
  bVar9 = 0;
  uVar3 = 0;
  uVar6 = 0;
  local_20 = *(long *)(in_FS_OFFSET + 0x28);
  local_88 = 0x61616161;
  uStack132 = 0x61616161;
  uStack128 = 0x61616161;
  uStack124 = 0x61616161;
  local_28 = 0x61616161;
  local_78 = 0x61616161;
  uStack116 = 0x61616161;
  uStack112 = 0x61616161;
  uStack108 = 0x61616161;
  local_68 = 0x61616161;
  uStack100 = 0x61616161;
  uStack96 = 0x61616161;
  uStack92 = 0x61616161;
  local_58 = 0x61616161;
  uStack84 = 0x61616161;
  uStack80 = 0x61616161;
  uStack76 = 0x61616161;
  local_48 = 0x61616161;
  uStack68 = 0x61616161;
  uStack64 = 0x61616161;
  uStack60 = 0x61616161;
  local_38 = 0x61616161;
  uStack52 = 0x61616161;
  uStack48 = 0x61616161;
  uStack44 = 0x61616161;
  sVar1 = strlen(param_1);
  if (sVar1 != 0) {
    do {
      if (99 < uVar6) {
        explode_bomb();
      }
      switch(param_1[uVar3]) {
      case '+':
        *(char *)((long)&local_88 + (long)(int)uVar6) =
             *(char *)((long)&local_88 + (long)(int)uVar6) + '\x01';
        break;
      default:
        explode_bomb();
        if (param_1[uVar3] == '.') goto switchD_0040194d_caseD_2e;
        break;
      case '-':
        *(char *)((long)&local_88 + (long)(int)uVar6) =
             *(char *)((long)&local_88 + (long)(int)uVar6) + -1;
        break;
      case '.':
        goto switchD_0040194d_caseD_2e;
      case '<':
        uVar6 = uVar6 - 1;
        break;
      case '>':
        uVar6 = uVar6 + 1;
      }
      uVar3 = uVar3 + 1;
      sVar1 = strlen(param_1);
    } while (uVar3 < sVar1);
  }
switchD_0040194d_caseD_2e:
  uVar7 = 0;
  uVar8 = 1;
  uStack128 = uStack128 & 0xff00ffff;
  __printf_chk(1,&DAT_004023b2,&local_88);
  lVar2 = 10;
  puVar4 = &local_88;
  pbVar5 = (byte *)"brainfxxx";
  do {
    if (lVar2 == 0) break;
    lVar2 = lVar2 + -1;
    uVar7 = *(byte *)puVar4 < *pbVar5;
    uVar8 = *(byte *)puVar4 == *pbVar5;
    puVar4 = (undefined4 *)((long)puVar4 + (ulong)bVar9 * -2 + 1);
    pbVar5 = pbVar5 + (ulong)bVar9 * -2 + 1;
  } while ((bool)uVar8);
  if ((!(bool)uVar7 && !(bool)uVar8) != (bool)uVar7) {
    explode_bomb();
  }
  FUN_004014e0("minfxxx");
  if (local_20 == *(long *)(in_FS_OFFSET + 0x28)) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}