<Bomb Lab이란?>
https://studyforall.tistory.com/98
<위의 게시물에서 GuestOS 변경>
가상머신: virtualbox
GuestOS: Ubuntu 22.04 -> Kali Linux 2024.1
디버거: pwndbg 플러그인 설치한 gdb
먼저 disassemble phase_4 명령어를 입력하여 phase_4 함수를 어셈블리 코드로 출력해보았다.
<+24> 에서 sscanf 함수를 호출하고
<+29>에서 eax에 들어있는 함수의 반환값을 0x2와 비교한다.
같지 않으면 <+41>로 jump하여 explode_bomb 함수가 실행되므로
eax에 들어있는 함수의 반환값은 0x2와 같아야 한다.
sscanf 함수는 주로 eax에 입력받은 인자의 개수를 저장하므로 인자를 2개 전달해야 함을 알 수 있다.
이것이 첫번째 조건이다.
<+34>에서는 [rsp+0x8]에 있는 4바이트 크기의 데이터와 0xe (십진수로 14)를 비교한다.
<+39>의 jbe 명령어는 전자의 값이 후자의 값보다 작거나 같으면 jump하는 명령어이다.
jump하지 않으면 explode_bomb 함수가 실행되므로
[rsp+0x8]에 있는 데이터는 14보다 작거나 같아야 한다.
break *phase_4+34
명령어를 통해 <+34> 지점에 중단점을 걸고 해당 부분까지 실행시켜본다.
입력값은 임의로 5와 6으로 주었다.
중단점까지 실행된 상태에서
x/wx $rsp+0x8
명령어를 통해 [rsp+0x8]에 어떤 값이 들어있는지 확인한다.
내가 입력한 첫번째 숫자가 들어있다.
혹시나 해서 이후에 있는 데이터까지 출력해봤는데 이번에는 6이 출력되는 것을 보니
이것이 내가 입력한 5, 6인 것을 확신해도 될 것 같다.
그렇다면 <+34>는 내가 입력한 첫번째 인자와 14를 비교하는 명령어이므로
여기에서 첫번째 인자는 14보다 작거나 같아야 한다는 두번째 조건을 찾을 수 있다.
이어지는 코드는 <+46>부터 edx, esi, edi에 파라미터를 저장하고 func4 함수를 호출하는 코드이다.
func4 함수에서 돌아온 후 <+65>, <+67>에 eax값이 0이 아니면 explode_bomb 함수로 가는 명령어가 있다.
따라서 func4의 반환값은 반드시 0이어야 한다는 세번째 조건을 확인할 수 있다.
(그런데 풀고나서 보니 이 세번째 조건은 고려할 필요가 없었다.)
이후 <+74>에서 explode_bomb 함수를 건너뛰려면
<+69>에서 [rsp+0xc]의 값이 0이어야 함을 알 수 있다.
[rsp+0xc]에는 앞에서 출력해본 것에서 알 수 있듯 나의 두번째 입력값이 저장되어 있다.
따라서 두번째 입력값은 0이어야 한다는 네번째 조건을 확인할 수 있다.
disassemble func4
를 입력해서 func4의 코드를 살펴본다.
eax와 ecx를 이용해 연산을 하고 그 결과값에 따라 특정 조건으로 분기한다.
<+27>, <+48>을 보면 함수의 처음부분으로 돌아가는 명령어를 볼 수 있다.
이를 통해 func4함수는 재귀함수의 구조를 갖고 있다는 것을 알 수 있다.
eax, ecx를 이용한 연산을 훑어보면 이미 함수에 주어진 값으로만 연산하므로
재귀호출이 반복됨으로써 초기 결과와 다른 변화가 생기는 일은 없어보인다.
즉 한번 재귀호출이 발생하면 계속 무한 루프를 돈다는 뜻이다.
우리는 재귀호출이 일어나는 <+27>, <+48>을 피해갈 수 있는 흐름을 찾아야 한다.
<+22>에서 <+36>으로 jump하고
<+43>에서 <+57>로 jump하면 func4 함수를 빠져나올 수 있다.
eax, ecx를 이용한 연산이 이루어짐에 따라 해당 레지스터의 값이 어떻게 바뀌는지 표로 그려봤다.
오프셋 주소 | eax | ecx | 연산 |
<+4> | 14 | mov eax, edx | |
<+6> | 14 | sub eax, esi | |
<+8> | 14 | mov ecx, eax | |
<+10> | 0 | shr ecx, 0x1f | |
<+13> | 14 | add eax, ecx | |
<+15> | 7 | sar eax,1 | |
<+17> | 7 | lea ecx, [rax+rsi*1] |
<+17>에서 ecx값이 7이 확실한지 확인하기 위해
break *func4+17
로 중단점을 찍어 해당 시점에서의 레지스터 값을 확인해보았다.
rip가 가리키고 있는 <func4+17>줄을 보면
이 명령어를 실행했을 때 ECX에는 7이 저장되는 것을 확인할 수 있다.
<+20>,<+22>에서는 <+36>으로 jump하려면
ecx 값이 edi 값보다 작거나 같아야 함을 알 수 있고,
<+41>,<+43>에서는 <+57>로 jump하려면
ecx 값이 edi 값보다 크거나 같아야 함을 알 수 있다.
둘 사이에 ecx, edi의 값이 변하지 않으므로 ecx와 edi는 두가지 조건을 한번에 만족시킬 수 있는 값을 가져야 한다.
'작거나 같다'와 '크거나 같다'를 동시에 충족시킬 수 있는 조건은 '같다'이므로
ecx와 edi가 같은 값을 가져야 함을 알 수 있다.
이것이 다섯번째 조건이다.
ecx는 앞에서 살펴본 바와 같이 7이고
edi는 <phase_4+56>을 참고하면 나의 첫번째 입력값임을 알 수 있다.
즉 첫번째 입력값은 7이어야 한다.
7 0 을 입력하니 phase4 폭탄이 해제되었다.
'Bomb Lab' 카테고리의 다른 글
[Bomb Lab] Phase3 (0) | 2024.03.24 |
---|---|
[Bomb Lab] Phase2 (0) | 2024.03.24 |
[Bomb Lab] Phase1 (0) | 2024.03.24 |
[Bomb Lab]Bomb Lab이란? (1) | 2024.03.24 |