level15로 로그인한 후 hint 파일을 확인하면 level14의 힌트 코드와 비슷한 코드가 나온다. 다른 점은 0xdeadbeef와 비교하는 대상이 check의 값이 아닌 포인터를 써줘서 check의 값이 가리키는 주소의 값이다. 마찬가지로 buf의 크기는 20이지만 fgets 함수를 통해 45byte만큼 입력을 받기 때문에 25byte overflow 된다.
원래는 hint 파일의 소스 코드를 복사해 tmp 폴더에서 새 파일을 빌드하고 디버깅했지만, 이번 문제의 경우 주소가 굉장히 중요하므로 똑같은 환경에서 분석하기 위해 cp 명령어로 문제 파일을 tmp 폴더에 복사했다. (처음에는 멋모르고 복사해서 새로 빌드했다가 주소 값이 안 맞아 exploit에 난항을 겪었다)
gdb를 통해 buf와 check 변수의 주소를 확인했다.
buf: 0xbffff4a0
check : 0xbffff4c8
두 변수 사이의 거리는 40byte인 것을 알 수 있다. 따라서 입력 값으로 40byte의 더미 값을 채운다면 남은 5byte로 check 변수에 접근해 값을 변조할 수 있다.
shell을 얻으려면 check의 값이 가리키는 주소가 0xdeadbeef이어야한다. 랜덤 스택이 적용돼 buf의 주소 값을 확실하게 알 수 없는 상황, 처음에는 brute force를 통해 exploit을 할까도 고려해봤지만 생각해보니 "cmp DWORD PTR [eax],0xdeadbeef" 명령어를 통해 eax(ebp-16, check)와 0xdeadbeef를 비교한다는 것은 0xdeadbeef가 명령어 opcode에 포함돼 있다는 것이다.
aslr이 걸려있지 않아 명령어의 주소는 일정하다. 따라서 비교문에 포함된 0xdeadbeef의 주소로 check 변수를 overwrite한다면 쉘을 얻을 수 있을 것이다. 위는 x/wx 명령어를 통해 0x080484b0(cmp DWORD PTR [eax],0xdeadbeef 명령어의 주소)의 16진수 값을 확인해본 모습이다.
1씩 늘려가며 확인해본 결과 0x080484b2로 check의 값을 변조해준다면 0xdeadbeef 값의 주소를 가리키게 된다.
더미 값 'A' 40byte + 0x080484b2의 주소를 little endian으로 바꿔서 입력 값으로 주니 쉘을 얻은 것을 볼 수 있다.
'Wargame > FTZ' 카테고리의 다른 글
[FTZ] level 17 (0) | 2021.06.06 |
---|---|
[FTZ] level 16 (0) | 2021.06.06 |
[FTZ] level 14 (0) | 2021.06.04 |
[FTZ] level 13 (0) | 2021.06.04 |
[FTZ] Level 12 (0) | 2021.05.29 |