old

Pwnable.kr / uaf

nopdata 2016. 7. 21. 16:38

# 1. UAF란?

UAF는 Use After Free의 약자로 malloc등으로 동적할당한 데이터 영역(Heap)을 free를 이용, 해제한 뒤에 사용을 할 경우 생기는 에러이다.

< Use After Free >

그림에서 처럼 Allocated, 할당되어 있는 데이터를 Use, 사용하면 문제가 없지만, 해당 영역을 Free를 한 후에 Use를 하면 Terminal이 된다는 의미이다.


# 2. Pwnable.kr uaf


● UAF 확인

문제의 소스는 아래와 같다.

각각 Use -> 출력, After -> 할당, Free -> 할당 해제를 의미한다.

# 1의 그림에서 처럼 에러를 터트려보면 다음과 같다.


< UAF error >

소스를 보면 알겠지만 처음에 기본적으로 할당되어있는 데이터가 있다.

이 데이터를 Use 메뉴를 이용, 출력을 하면 문제없이 출력이 된다.

하지만 Free를 한 후에 다시 Use를 이용하여 출력을 하면 Segmentation Falut가 발생한다.


● Heap 할당 주소 확인

< Woman Call after rax >


Woman Function을 Call한 이후 rax의 값을 확인해보면 0x252a090이 들어있다.

이는 Human* w = new Woman("Jill", 21);의 리턴으로 돌아온 동적할당된 Heap 주소이다.

당연히 Heap 영역이기 때문에 프로그램 실행마다 매번 바뀐다.

Woman할당 이후 0x25a090가 가리키는 값을 보면 Woman+16을 가리키고 이는 giveshell의 주소이다.

뒤에서 보겠지만 어찌되었건 여기서 확인을 할 수 있는 것은 Woman Function Call 리턴으로 오는 함수의 주소가 원래는 give shell을 가리키고 있었으나 free를 하면 초기화 된다는 것이다.



● Introduce 호출까지의 확인

< m->introduce( ) >

이 부분은 switch문에서 분기하여 use를 선택하였을 경우 m->introduce( ) 호출까지의 어셈블리어이다.

 mov -0x38(%rbp), %rax

-> 위에서 저장되었던 0x25a090이 rax로 저장된다.

 mov (%rax), %rax

-> rax(0x25a090)가 가리키고 있는 값, Woman+16을 rax에 저장한다.

 add $0x8, %rax

-> rax는 현재 Woman+16을 가리키고 있으며 +0x8을 하므로 Woman+24를 가리킨다. 이는 introduce()의 주소이다.

 mov (%rax), %rdx

-> rax가 가리키고 있는 introduce()의 주소를 rdx에 저장한다.

 ...

 *%rdx

-> introduce 함수를 호출한다.


introduce함수의 호출까지의 어셈블리어를 보면 원래 가리키고 있던 giveshell 주소에 +0x8을 한다.

따라서 giveshell을 호출하는 것이 아니라 introduce를 호출하게 된다.


● After 덮어쓰기 확인


< Free - After - Use >

0xbd8090은 위에서 rax, 0x25a090와 같다. 실행을 다시 시켜 주소가 바뀌었다.

보면 Free -> Allocated -> Use 순으로 진행을 하였다.

원래 0xbd8090에는 Woman+16(giveshell)의 주소가 있어야 정상이다.

하지만 여기서는 0x64636261이 저장되어있다. 이는 직접 입력한 abcd가 들어간 값이다.

After를 시행하면 Free를 한 역순으로 다시 할당이 된다.  즉, delete m -> delete w 순으로 하였으므로

먼저 w가 저장되어있던 Heap영역에 데이터가 할당되고 그 다음 m이 저장되어있던 Heap 영역이 할당된다.

결과적으로는 이 부분을 쉘을 띄울 수 있는 giveshell을 가리킬 수 있는 주소로 변경하면 된다.

단, 주의해야 할 점은 위에서 보았듯이 저장된 주소에 +0x8을 한다는 점이다. 따라서 giveshell을 가리키는 Woman+16의 주소에 -0x8을 한 주소를 넣어줘야 한다.

위에서 Woman의 giveshell의 주소는 0x401550이었으므로 여기서 -0x8을 한 0x401548을 넣어주면 된다.

introduce를 호출하는 방식이 m->introduce( ) >> w->introduce( )라는 것이다.

즉, After를 한번만 진행을 하게 되면 w가 저장되어있던 Heap 영역에는 giveshell주소가 저장되어 충분한 조건이 되었을 지라도, 먼저 호출이 되는 m영역은 아직 할당이 되지 않아 오류가 발생할 수 밖에 없다.

따라서 After는 두번 이상 진행을 해 주어야 한다.


● 최종 풀이

< shell 획득 >

위와 똑같이 하였다. 하지만 들어간 값이 0x401548, giveshell을 가리키는 주소 -0x8이다.

조건에 맞추어 두번을 Allocate 해 주고 Use를 해 보면 두 개의 쉘이 실행 된 것을 확인할 수 있다.

'old' 카테고리의 다른 글

Suninatas / Forensic 29 (디스크 이미지 분석)  (0) 2016.07.21
Suninatas / System 27 (바이너리 속 어셈블리어)  (0) 2016.07.21
포포포포렌식 #3  (0) 2016.07.12
System #1  (0) 2016.07.08
포포포포렌식 #3  (0) 2016.07.05