y0u_bat
[HITCON] Secret Holder 본문
unsafe_unlink 관련된 문제이다.
Menu introduce
메인함수에 3가지 메뉴가 있다.
keep();
wipe();
renew()
각 메뉴 기능에 대해서 간단하게 설명하자면,
keep() - 할당하는 함수.
wipe() - free 하는 함수
renew() - 청크 수정하는 함수.
Fake_Chunk
fake_chunk를 만들기 위해 huge_chunk(3)를 썻다.
1번과 3번이 같은 청크주소를 가르키고 있다. 그러나 1번은 free하면서
small_inuse = 0
이 되어서 재수정이 불가능하다.
wipe(1)
을 해준다. 3번이 해당청크주소를 가르키고 있으므로, free가 된다.
이때 wipe(3)
으로 free 해준것이 아니기 때문에, huge_inuse = 1
상태로 유지된다.
keep(1,"B")
을 해서 3번과 같은곳으로 1번을 할당을 받는다.
keep(2,"C")
을 해서 할당을 하고,
renew 메뉴를 이용해서 3번에 fake_chunk를 write 해준다.
renew에서는 inuse라는 변수가 0이 아닌 1로 되어 있어야지, write 할 수 있다.
renew를 통해서 3번에 write 해준다, 여기서 3번은 현재 1번이랑 같은 청크주소를 가지고 있다.
unlink에서 fd와 bk의 검증을 통과 시키기 위해서 청크포인터 huge_chunk 주소를 넣어줬다.
그리고 PREV_INUSE이 0인 청크를 만들어주어서, 이전 청크가 free 된것처럼 보이게 만들어주었다.
wipe(2)를 호출하게 되면 0x1da4040부분이 free 되는데, 현재 저부분은 우리가 만들어놓은 fake_chunk의 일부이다.
이전 청크가 free된것처럼 보이게 만들어서, 해당부분을 free하게 되면, 병합하기 위해 unlink 매크로가 호출된다.
FD->bk = BK;
와 BK->fd = FD
작업을 하게 된다.
fake_fd, fake_bk 인, 0x6020a8-24와 0x6020a8-16
0x6020a8-24 + 24 = 0x6020a8-16
0x6020a8-16 + 16 = 0x6020a8-24
즉 0x6020a8 주소에 0x602090 덮어지는것을 볼 수 있다.
이제 chunk가 병합되었기 때문에, 3번 청크주소가 0x602090로 바낀것을 볼수있다.
여기서 저 0x6020a8에 있는 0x602090를 조작 할 수 있게 되면, 원하는곳으로 청크주소를 돌릴수가 있다.
0x602090에서 write하면서 0x6020a8에 있는 주소를 free_got로 덮어 버린다.
그러면, huge_chunk(3번 청크)가 free_got를 가르키고 있을것이다.
renew 메뉴를 통해서, got overwrite 할 수 있다.
Libc Leak
Got Overwrite까지 가능한데, 시스템주소를 호출하기 위해, Libc 주소를 릭 해야 된다.
코드상으로는 Leak 할 수 있는 벡터가 없기 때문에, got overwrite를 통한 릭을 해야 된다.
청크에 unsorted bin 때문에, main_arena+88 주소가 들어 있다.
1번메뉴는 아직 해당청크를 가르키고 있기 때문에, renew로 "a"*16로 덮는다.
free를 puts로 got overwrite를 한다
wipe(1)를 하여, free(small_chunk) -> puts(small_chunk) 를 실행한다.
청크에 unsorted bin으로 인해, main_arena+88 주소가 박혀 있다.
1번메뉴는 아직 0x1da4010를 가르키고 있기때문에, renew 메뉴로 main_arena+88 전 주소까지 overwrite 할수있다.
free_got를 puts_plt로 덮어준다.
renew 메뉴를 이용하여, leak 할 수 있게, main_arena+88 주소 전까지 덮어준다.
wipe(1)를 통해 free(small_chunk), 즉 puts(small_chunk)를 한다.
이렇게, main_arena+88 주소를 leak 할 수 있다.
이문제는 libc 파일을 제공해준다. 그러므로 좀 더 쉽게 system_libc 주소를 구할수있다.
Exploit
아직 huge_chunk는 free_got를 가르키고 있다.
그러므로 renew를 통해서, 다시 got overwrite를 할 수 있다.
free_got를 system_libc로 덮어 버린다.
그리고 아까 미쳐 말 못했었는데, system(chunk)가 될테니,
릭하기 위해 small_chunk에 write할때 "/bin/sh;aaaaaaaa"를 write 했었다.
나중에 system(small_chunk) 하기 위해 /bin/sh; 를 넣어 두었다.
free_got를 system_libc로 덮고 wipe(1)을 하면, 쉘을 딸 수 있다.
'CTF' 카테고리의 다른 글
[Defcon 2014] Babyfirst heap (0) | 2017.01.09 |
---|---|
[HolyShield] diary - 400pt (0) | 2017.01.08 |
[BCTF] BCloud (0) | 2016.11.18 |
2016 Whitehat contest Malloc (5) | 2016.11.02 |
[2016] EKOPARTY PWN25 (0) | 2016.10.29 |