unsafe_unlick.c 분석하기
이 글은 github에 있는 how2heap 시리즈 코드 중 unsafe_unlink.c를 분석해보고 heap 취약점인 unsafe unlink에 대해서 공부해 볼 것입니다.
1. unsafe_unlink.c 코드 분석하기
코드 첫 번째 부분입니다. 이 부분은 따로 자세하게 설명할 부분은 아닙니다. unsafe_unlink.c 코드에 대한 설명과 코드를 Ubuntu 14.04 또는 16.04에서 테스트해보라고 적혀 있고 unsafe_unlink가 발생하는 위치에 대해서도 간단하게 소개되어 있습니다. 그리고 malloc_size에 0x80을, header_size에 2를 저장해주고 전역변수인 chunk0_ptr에 0x80만큼 할당해주고 지역변수 chunk1_ptr에도 0x80만큼 동적 메모리를 할당해준 상태입니다. 그리고 마지막 두 줄은 할당 후 전역 변수의 위치와 공격할 메모리의 주소를 출력해주고 있습니다.
현재 위의 코드까지 실행했을 때 메모리 구조입니다. heap메모리의 주소는 ASLR로 인해 실행마다 바뀌기 때문에 주소는 다를 수 있습니다. 저는 위 코드 다음 getchar()을 넣어주고 컴파일하여 pwntools 간단히 받아 pwndbg로 디버깅하여 할당된 메모리들의 주소를 확인했습니다. 그리고 한 가지 특징은 chunk0_ptr은 전역변수 이기 때문에 아래부분처럼 heap메모리를 가르키고 있는 값이 따로 저장되어 있었습니다.
이 부분은 chunk0에 fake chunk를 만들어 주는 부분입니다. fastbin이 아닌 다른 bins에서는 연속된 메모리 영역이 free되었을 때 병합이 일어나게 됩니다. 이때 매크로 unlink를 사용하게 됩니다. unlink 매크로 부분의 코드 중 주목할 부분은 아래의 코드입니다.
병합시 메모리 구조는 위와 같습니다.
위의 unsafe_unlink.c 코드는 두 번째 루틴을 우회하기 위해 chunk0_ptr에 내부에 만든 fake chunk의 fd값과 bk값을 조작해준 부분입니다.
이 부분은 heap overflow를 통해 chunk1의 메타데이터인 prev_size와 size 부분의 prev_inuse 플래그를 조작하여 prev_size를 fake chunk의 size로 바꾸고 앞의 chunk가 free chunk인지 allocated chunk인지를 확인하는 prev_inuse플래그를 0으로 조작하여 앞서 조작한 fd와 bk에 적혀 있는 주소의 공간에 우리가 원하는 값을 쓸 수 있게 되는 것을 보여주는 코드였습니다.
2.unsafe unlink 공격 기법 정리
free된 chunk가 병합이 일어날 때 불러오는 unlink매크로의 취약점을 이용한 공격기법입니다.
이 기법은 heap overflow가 발생했을 때 사용가능합니다. 그 이유는 unlink의 검증 코드를 우회해야 하기 때문입니다.
free하고자 하는 chunk의 prev_inuse플래그를 확인하여 앞의 chunk가 free되었는지 확인하는 코드입니다.
위는 코드 분석에서도 설명 하였듯이 제대로 unlink가 되었는지 확인하기 위해 FD->bk와 BK->fd 포인터가 현재 포인터를 가르키고 있는지를 확인하는 코드입니다.
이 두 검증 코드를 우회해야만 우리가 원하는 곳에 값을 작성할 수 있는 환경이 만들어지게 됩니다. 그렇기 위해서 먼저 fake chunk의 fd,bk에 해당하는 부분을 우리가 원하는 주소로 바꿔주고, heap overflow를 통해 다음 chunk의 prev_size와 size부분의 prev_inuse 플래그의 값을 바꿔주어 free하게 되면 우리가 조작한 fake chunk와 다음 chunk가 병합되게 되고 그 다음 새로이 동적 메모리를 할당하게 되면 우리가 조작한 주소로 할당되어 그곳에 값을 쓸 수 있게 되는 것입니다.