Excute
먼저 문제로 주어지는 파일을 실행시키면 아래와 같이 나타난다.
먼저 특정 주소값을 Leak해주고 메시지의 길이와 메시지를 입력 받고 입력 받은 문자열이 출력 된 후 프로그램이 종료 된다.
Analyze
먼저 gdb-peda에 문제 파일을 올려 보호기법을 먼저 확인해본다.
CANRY, NXbit등 거의 모든 보호기법이 적용 되어있는 것을 확인할 수 있다. 따라서 일단은 IDA-pro를 사용해 코드를 살펴보자.
IDA-pro를 통해 hex-ray를 사용하여 디컴파일 시켜 준 결과이다. 프로그램의 전체적인 구조를 파악해보면 다음과 같다.
- 14번 line을 보면 v3변수에 0x4000만큼 malloc을 이용해 할당해준다. 또한 15번 line에서 아까 할당한 v3에 1을 대입해준다.
- 16번 line에서 malloc을 통해 할당했던 v3의 변수를 leak시켜준다. 앞서 파일 실행 시 확인되었던 leak address가 v3의 address임을 알 수 있다.
- 20번 line에서 19번 line에서 입력 받은 size 만큼 v5를 malloc을 통해 할당 시켜준다.
- 24번 line에서 v5의 마지막 인덱스를 0으로 만들어준다.
- 26,27 line에서 v3변수가 0일 경우에 flag를 출력 시켜준다.
정확한 동작을 파악하기 위해 challenge 파일을 gdb에 올려 main 함수를 디스어셈블해본다. 하지만 어떤 이유에서인지 main 함수가 디스어셈블 되지 않는다.
따라서 구글링을 통해 이유를 알아보던중 디버깅 심볼을 포함하지 않고 컴파일된 파일이라 main함수가 바로 디스어셈블 되지 않는다. 따라서 다른 방법을 통해 main 함수의 주소를 직접적으로 찾아주어야한다.
https://umbum.tistory.com/103?category=711929 이 주소에서 해당 내용에 대한 자세한 설명을 찾아 볼 수 있었다. 해당 내용을 요약해보면 아래와 같다.
먼저main 함수의 호출 방법은 _start --> __libc_start_main --> main이다. 따라서 main의 상위 frame은 __libc_start_main이고__libc_start_main은 첫번째 인자로 main함수의 pointer를 받는다.
gdb에서 프로그램을 실행시키고 __libc_start_main에 bp를 걸어준다.
__libc_start_main에서 첫번째 인자로 main 함수의 address를 넘겨주는 것을 확인 할 수 있다. 따라서 main함수의 address는 0x555555554920 인 것을 확인 할 수 있다. main함수의 address를 알았으니 기존의 BP를 제거하고 새롭게 BP를 걸어준다.
새롭게 BP를 건 곳에서 프로그램이 멈추고 main 함수 전체 내용을 확인하기 위해 x/56i 0x555555554920을 입력해준다.
앞서 IDA-pro로 확인한 내용과 같은 것을 확인할 수 있다. mov BYTE PTR [rbp+rdx*1-0x1],0x0 명령과 cmp QWORD PTR [rbx],0x1 명령에서 rbp,rdx,rbx가 무엇인지 핵심적으로 rbx가 0이 되어야 flag를 획득 할 수 있다.
rbp, rdx, rbx를 파악하기 위해 mov BYTE PTR [rbp+rdx*1-0x1],0x0 명령에 break point를 결어준다. 프로그램을 실행시키고 입력 값으로 메시지 길이를 5 입력 문자열을 aaaaa를 입력하고 레지스터의 상태를 파악한다.
rbp는 내가 입력한 문자열이고 rdx는 문자열의 길이 임을 알 수 있다. rbx에는 초기 hex-ray에서 확인한 v3변수의 주소(leak)가 들어가 있고 해당 주소에 1이 대입된 것을 알 수 있다. 즉 사용자가 입력한 값의 마지막 겂을 0x0으로 바꾸고 rbx의 값과 0x0을 비교하는 형태로 프로그램이 진행된다.
결과적으로 flag를 획득하기 위해서는 rbp(입력 문자열)에 아무값을 넣지 않고 rdx(문자열의 길이)에 leak주소+0x1 을 입력해주게 되면 mov BYTE PTR [rbp+rdx*1-0x1],0x0 명령이 mov BYTE PTR [0x0+leak*1+0x1-0x1],0x0 형태로 변하는 결과를 가지고 온다. 따라서 mov BYTE PTR [leak],0x0 과 동일해진다. 그러면 초기 v3변수에 대입되었던 0x1을 0x0으로 바꿀수 있기 때문에 조건문을 통과하여 flag를 획득할 수 있다.
Solve
여기까지 얻은 결론을 가지고 파이썬을 이용해 exploit을 작성해보면 아래와 같다.
Flag를 정상적으로 획득한 것을 확인할 수 있다.
'Wargmae > Pwnable.xyz' 카테고리의 다른 글
[Pwnable.xyz – Punch it] (0) | 2021.01.17 |
---|---|
[Pwnable.xyz - PvP] (0) | 2021.01.13 |
[Pwnable.xyz - J-U-M-P] (4) | 2021.01.07 |
[Pwnable.xyz - TLSv00] (0) | 2021.01.02 |