( GS + SafeSEH 우회 익스플로잇 : http://5kyc1ad.tistory.com/312 )
SEH Overwrite에 대한 기초적인 내용은 http://5kyc1ad.tistory.com/308 여기와 위 링크를 참고하시기 바랍니다.
SEHOP : Linked-List 형태인 SEH 체인을 참조하여 마지막 SEH에 SEHRecord->pNextSEHRecord에는 0xFFFFFFFF, SEHRecord->pExceptionHandler에는 Ntdll!FinalExceptionHandler 함수 주소가 지정되어 있는지 확인하는 보호 기법.
* 이하에서 익스플로잇에 사용한 프로그램에 스택 기반 BOF 및 SEH Overwrite 취약점이 존재하지만 NULL을 입력할 수 없는 문제가 있어 실습을 위해 메모리에 직접 수정을 가해서 입력되었다는 가정 하에 익스플로잇 실습을 진행했습니다. 해당 프로그램은 위 ‘GS + SafeSEH 우회 익스플로잇’에서 사용한 것과 동일합니다.
[정상적인 SEH 체인]
[비정상적인 SEH 체인]
기존에 SafeSEH를 피해 SEH Overwrite를 했던 기법을 그대로 사용하면 pNextSEHRecord가 Relative Short JMP의 OPCode로 변조되어버리기 때문에 SEH 체인이 끊기고 SEHOP에 탐지되어 정상적으로 Exploit이 실행되지 않습니다.
GS + DEP + SafeSEH + SEHOP가 적용되어 있고 ASLR이 있다고 가정할 경우 공격 방법은 다음과 같습니다.
[덮어쓸 SEHRecord 주소와 값 확인]
스택에서 덮어쓸 SEHRecord 주소와 pNextSEHRecord 값을 확인합니다. pNextSEHRecord는 0x18FA90이며 바로 밑에 다음 SEHRecord가 있는 것을 볼 수 있습니다. SEH 체인을 끝까지 다 따라가면서 덮어씌워주기는 힘드므로 저 두 번째 체인을 0xFFFFFFFF와 Ntdll!FinalExceptionHandler 함수 주소로 변조하여 정상적으로 보이는 SEH 체인을 만들어야 합니다.
[마지막 SEHRecord 값]
마지막 SEHRecord까지 계속 참조하여 Ntdll!FinalExceptinHandler 주소값이 0x772E7428인 것을 확인할 수 있습니다.
여기까지를 페이로드로 작성하면 다음과 같습니다.
Dummy(0x54) + 0x18FA90 + ???? + Dummy(4) + 0xFFFFFFFF + 0x772E7428
[익셉션 발생 직후 Handler 함수]
익셉션 발생으로 SEHRecord->pExceptionHandler가 호출된 직후의 ESP의 위치를 확인하기 위해 Handler 함수에 바로 BP를 걸고 강제로 익셉션을 발생시켜 ESP가 0x18F448에 위치하게 됨을 확인했습니다. 위에서 인위적으로 만든 종료 체인 이후 스택 주소가 0x18FA98 이므로 0x18FA98 - 0x18F448 = 0x650 이상 ESP를 POP 또는 ADD ESP로 옮긴 후 ret을 해야 원하는 대로 ROP 체인 구성이 가능합니다.
[Ollydbg Search for All Sequences]
해당하는 가젯을 찾기 위해 Ollydbg CPU 창에서 우클릭 -> Search for -> All Sequences 창을 열고 위와 같이 와일드카드 문자 CONST와 R32를 이용하여 가젯을 검색했습니다. (pop 없이 해봤더니 적당한 가젯이 나오지 않았습니다)
[발견한 가젯]
바이너리 내에서 해당 가젯을 찾아내었습니다. ADD ESP, 0x800에 POP 1번 후 ret을 하므로 총 0x804만큼 ESP가 움직이게 됩니다. 0x650 - 0x804 = -0x1b4 이므로 총 0x1b4개만큼 Dummy를 추가로 넣은 후 적당한 함수 주소를 넣어 주면 ROP가 가능할 것으로 보입니다.
여기까지 페이로드는 다음과 같습니다.
Dummy(0x54) + 0x18FA90 + 0x452336 + Dummy(4) + 0xFFFFFFFF + 0x772E7428 + Dummy(0x1b4) + ROP Chain
[익스플로잇 스택 구조도]
실제 스택 주소 기반으로 페이로드가 들어가 익스플로잇된 스택 구조를 그려봤습니다. 익셉션이 터지는 순간 익셉션 처리 과정에서 스택이 추가로 늘어나고 0x18F448에 ESP가 위치하게 됩니다. 이후 &Gadget이 pExceptionHandler 위치이므로 이 가젯을 실행하게 되는데 여기에는 ADD ESP, 0x800과 POP, ret이 있으므로 ROP Chain이 존재하는 0x18FC4C에서 ret을 하게 되고, ROP Chain이 실행되어 익스플로잇에 성공하게 될 것입니다. ROP Chain 위의 Dummy 부분은 어차피 말 그대로 Dummy이므로 그곳에 문자열을 넣고 간단히 MessageBox를 호출하도록 짜서 돌려봤습니다.
[Exploit 1]
익셉션 발생하기 직전의 샘플, EAX에 0x90909090이 들어 있는데 포인터 참조하여 익셉션이 발생하려고 하고 있고 pExceptionHandler는 이미 0x452336으로 변조된 상황입니다.
[Exploit 2]
익셉션이 발생하고 0x452336의 BP에서 멈춘 상태. ESP는 0x18F448까지 내려갔고, ADD ESP, 800과 Pop이후 ret이 실행되므로 0x18FC4C의 값이 ret 될 것으로 예상 가능합니다.
[Exploit 3]
정확히 0x18FC4C의 값을 ret하며, 그 밑에 두번째 인자로 0x1B4 크기의 Dummy에 넣은 문자열 “Exploited!!”가 들어가는 것을 볼 수 있습니다.
[Exploit 4]
해당 함수는 MessageBoxA 함수였으며, 넣은 값 그대로 출력 후 종료됩니다. POP~RET 가젯도 찾아두었으니 여기에 라이브러리 함수를 연결해서 돌리기만 하면 ROP 체인을 계속 연결해 나갈 수 있겠습니다.
ASLR이 걸려있지 않았기 때문에 주소값 넣는 데에 지장이 없었지만 ASLR까지 걸려있다면 주소를 Leak할 수 있는 취약점이 없는 이상 익스플로잇은 어려워 보입니다.
'Analysis > Technique' 카테고리의 다른 글
GetProcAddress 없이 API 주소 가져오기 (0) | 2018.10.24 |
---|---|
TIB, PEB를 이용해 로드된 DLL 정보 가져오기 (0) | 2018.10.22 |
CFG(Control Flow Guard) (0) | 2018.08.29 |
GS + SafeSEH 우회 SEH Overwrite Exploit (0) | 2018.07.11 |
SEH Overwrite (0) | 2018.05.29 |