본문 바로가기
Wargame/pwnable.kr

pwnable.kr uaf

by morae23 2019. 2. 21.

[Toddler's Bottle] uaf


uaf.cpp 코드의 일부이다.



give_shell() 함수를 호출할 수 있으면 될 것으로 보인다.


아래는 main() 코드이다.



이 때, switch문의 case 2를 이용하면 uaf가 가능할 듯하다.


gdb로 보면 fastbin에 들어가는 것을 볼 수 있다.



따라서 argv[1]으로 같은 크기를 주고 실행한 뒤

3 -> 2 순으로 입력하여 free로 인해 반환된 메모리를 다시 할당받으면 된다.

이제 해당 메모리에 덮어쓸 데이터만 결정하면 된다.


이 때, 다시 uaf.cpp 코드를 보면 give_shell()과 introduce()가 virtual 함수인 것을 볼 수 있다.

free하기 이전의 힙 상태를 다시 보면 아래와 같다.



vtable의 주소가 담겨 있는 것을 볼 수 있다.

안에 give_shell()의 주소가 있다.


introduce()를 호출하는 부분을 보면, 여기에 0x8을 더해서 호출하게 된다.



따라서 0x8을 뺀 주소로 덮어쓴 뒤, introduce()를 호출하게 하면 give_shell()이 호출될 것이다.


정리하면, 

3 -> 2 -> 1 순으로 입력할 것이다.

그 이유는,

3: free

2: free된 메모리를 다시 할당 받아서 덮어쓰기

1: introduce() 호출 (실제로는 give_shell() 호출을 위해)


이 때, 우리가 덮어쓸 값은 파일에서 읽어오기 때문에 원하는 주소를 넣고 저장한다.



그 뒤, 실행할 때 argv[1]에는 size를 주고 argv[2]에는 파일 경로를 준다.

(free되는 메모리와 같은 크기를 입력해 준다.)


위에서 말한 것처럼 3 -> 2 -> 1 순으로 입력하면 되는데

2는 두 번 입력해 주어야한다.


main()을 보면, m->introduce()가 먼저 호출되기 때문이다.

(delete 순서가 m -> w 이기 때문에 fastbin에서 w가 먼저 나옴)



위와 같이 실행하면 플래그를 얻을 수 있다.



여기서 16대신 3 ~ 24 사이의 값을 입력해도 동작하는 것을 볼 수 있다.


우선 16 이하의 값을 입력해도 되는 이유는 64비트에서 heap header 크기가 16이고, 데이터 부분의 최소 사이즈가 16이므로

3 ~ 16까지의 값을 입력해도 동일한 크기로 할당되기 때문이다.


17 ~ 24까지의 값이 동작하는 이유는 heap header의 prev_size 부분때문이다.



위 그림은 24를 입력하고 A가 23개 입력된 파일의 경로를 주고 실행한 것이다.

( r 24 /tmp/morae/a )


24을 입력하였지만 size 부분을 보면 21인것을 볼 수 있다.

그리고 A가 prev_size 부분까지 쓰여진 것을 볼 수 있다.


이전 노드가 free되기 이전에는 prev_size 영역을 사용하지 않는다.

따라서 메모리를 할당할 때 이 것을 고려하여 16(헤더)+24인 40을 할당하지 않고 16(헤더)+16인 32를 할당해준 것이다.

즉 16(헤더)+16+8(prev_size) 부분을 사용하게 된다.

'Wargame > pwnable.kr' 카테고리의 다른 글

pwnable.kr unlink  (0) 2019.03.12
pwnable.kr horcruxes  (0) 2019.03.06
pwnable.kr memcpy  (0) 2019.02.13
pwnable.kr blukat  (0) 2019.02.11
pwnable.kr leg  (0) 2019.02.11

댓글