Stack Cookie (GS aka. canary)

2018. 1. 23. 18:480x04 pwnable/윈도우즈 어플리케이션 취약점 분석

728x90

공부 한 내용을 복습하는 공간으로 삼으려고 한다. 


몇 년 전만 해도 익스플로잇 하는 것은 참 쉬웠다고 한다. 그 이유는 몇 가지가 존재하는데 그것부터 언급하고 시작하려 한다. 

공격에 쓸 만한 리턴주소와 pop/pop/ret 주소를 쉽게 발견할 수 있었고, 애플리케이션이 쉘 코드로 점프할 수 있도록 만드는 것이 가능했기 때문이다. 또한 우리는 해당 가젯들의 주소를 운영체제나 애플리케이션에서 사용하는 dll에서 아주 쉽게 찾을 수도 있었다고 한다. 뿐 만 아니라 이 주소들은 시스템이 재 부팅 되더라도 변하지 않기 때문에 공격 코드 제작을 더욱 용이하게 할 수 있었다. 계속해서 애플리케이션에 공격이 진행되니까 마이크로소프트 사는 보호 할 수 있는 정책을 만들 수 밖에 없었다. 


보호 매커니즘이라고도 표현할 수 있는데 크게 보면 스택쿠키(/GS 스위치쿠키), SafeSEH(/Safeseh 컴파일러 스위치), 데이터 실행방지(DEP:Data Excution Prevention), ASLR(Address Spacelayout Randomization)이 있다. 


지금부터 하나 하나 알아보고, 이 기법들을 보기 좋게 우회하는 시나리오 및 원리를 정리하면서 공부해보고자 한다.(공부라 쓰고, 복습이라 읽는다.)


글을 작성해보는 이유는 윈도우 시스템 해킹에 대해 일주일 간 동영상 강좌(인프런-윈도우즈 애플리케이션 취약점)를 보고 몇 개의 취약한 프로그램을 분석해 보았지만, 분석하는데 너무 많은 시간이 소요 되어 설명이 상세한 가이드라인(corelan)을 보고 한번 더 정리하면서 정확하게 개념숙지를 못한 부분을 보완해보기 위해서다. 전적으로 나의 공부를 위한 공간이다. 


첫 번째로 스택쿠키에 대해서 공부해보자.

'/GS 스위치' 해당 옵션이 생기게 된 계기부터 알아야 한다. Direct EIP Overwrite 기법을 진행하지 못하게 하기 위함이다. 조금 더 상세하게 들어가면 스택 기반 오버플로우 공격의 성공을 차단하기 위해 "함수의 시작과 끝 부분"에 약간의 코드를 삽입해두는 원리라고 할 수 있다. 

애플리케이션이 시작되면, 전역 마스터 쿠키(unsigned int)가 계산되고, 로드 된 모듈의 .data 섹션에 저장된다. 함수 시작부분에 전역 마스터 쿠기가 저장 된 EBP와 EIP 바로 전 스택에 복사된다. 보다 더 정확히는 지역변수와 리턴 주소 사이라고도 말할 수 있다.  아래에는 식별하기 쉬운 그림이 하나 있다. 



함수의 끝 부분에서 쿠키는 다시 전역 마스터 쿠키 값과 비교한다. 


Stack cookie를 어떻게 사용하는지 보기 위해 예시를 하나 만들었다.



해당 코드는 buf에서 정해둔 크기보다 더 큰 크기가 동적으로 입력되었을 때 스택 내부의 저장된 EBP와 저장 된 EIP를 덮으면서 OVERFLOW가 발생하는 기본적인 예시다. 


컴파일 한 후 Ollydbg에 Open하였다.

현재 GS 옵션과 ASLR을 켜둔 상태이다.


그림을 통해 보자.


아래의 그림을 보면 secuirty_cookie라는 용어가 보일 것이다.

이놈이 위의 그림에서 본 Stack Cookie 값이다. 이 값은 컴파일러에 /GS 옵션을 켜두게 되면 

crt 영역에서 만들어주는 것으로 알고 있다.

여담으로 [ _______  ] 라고 되어있는 것은 global value라고 볼 수 있다. 

이러한 global value는 label로도 인식을 할 수 있다고 생각한다. 그 이유는 아래 Follow in Dump를 보면 알 수 있다. 해당 다일러로그에 값을 입력하면 메모리 덤프에서 알아서 주소와 그에 해당하는 값을 찾아준다. 

잠시 기억해두자. 

01103000 >E7 AC 6B 60  // __security_cookie 



EAX에 __security_cookie의 값이 저장된다.


다음 명령어를 살펴보면 xor eax, ebp인데, eax안에는 __security_cookie 값이 들어있는 것을 우리는 알고있다. ebp와 xor 연산을 취해주게 되는데 ebp에 의해 쿠키 값이 변하게 하는 원리를 컴파일러가 만들어 둔 것이다. 


바뀐 값 : 01101065 (EAX)


해당 루틴에서 argv[0]을 탐색하게 된다. --> 긴급 수정!! 

코드에 argv[0]을 copy하는 걸로 잘 못 적어두어서 이러한 루틴이 생기게 되었습니다. 본래 argv[0]을 탐색하는건 main에 접근하기 전에 치루어야 합니다. 해당 바이너리가 오픈 되려면 컴퓨터 입장에서는 올바른 주소를 찾아가야 하니까요. 따지고 보면 절대경로 역시 하드디스크 안에 있는 특정 주소가 되겠죠? 바로 아래의 그림은 잊어주세요... 메인에서 이렇게 코딩 을 굳이 해보고 싶으면 argv[0]을 누군가가 변조했을 때 체크섬 으로  buf를 이용할 순 있을 것 같습니다. 


현재 argv[1] 즉, 매개변수를 넣지 않았기 때문에 더이상의 진행은 되지 않는다. 우선 스택쿠키가 올바르게 살아있는지 파악하기 위해서 버퍼를 덮지 않는 정상적인 크기만 삽입해본다.


Ollydbg로 매개변수 넣는 방법에 대해선 따로 언급하지 않겠다. 



10바이트를 입력하였다. 

재 시작했으니 __security_cookie 도 바뀔 것이다.


앗. 큰 실수를 하나 했다. 어쩐지 뭔가 이상했다. argv[1]을 복사해야 한다. 
코드 자체가 틀렸다. 

이왕 고치는 김에 코드를 다듬었다. 


후 본의 아니게 시간소요가 되었다. 라이브로 문서를 작성하면 이러한 불상사가 생긴다. 


10개의 인자 값 "A"를 삽입하였다.


바뀐 스택 쿠키 : 4FF76831


[ecx+eax]에 A*10개가 들어가있다.


EBP-20에 복사 되었다. 


화살표 흐름에 의식을 맡기면 자연스레 루틴을 이해할 수 있다.





나머지는 영상으로 대체하였다.


영상의 내용을 간추려보면 다음과 같다.


컴파일러가 생성해둔 security_cookie 즉, canary는 특정 버퍼의 크기가 스택에 세팅되었을 때 저장 된 EBP 앞의 영역에 EBP와 XOR를 취한 값이다. 

이 값은 버퍼에 사용자가 요구한 동적 데이터의 삽입이 완료되게 되면, security_cookie를 체크섬 한다. 이 때, 실제 버퍼가 요구하는 크기 이상으로 채우다 보면 security_cookie는 물론이고 ebp(sfp)와 retn 값 까지 덮게 되는데 비교 값을 통해 체크 하였을 때 바뀜이 있다면 스택이 오염된 것으로 간주 == 버퍼오버플로우 혹은 버퍼 오버런이 되었다고 판단하고 "프로그램을 비정상 종료" 시키게 된다.