Bomblab-2
by
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();
}
Subscribe via RSS