Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

cdor1's lab

unsafe unlink 본문

Security/Pwnable

unsafe unlink

Cdor1 2016. 12. 7. 05:47

내가 한동안 풀었던 문제들 중 unsafe unlink 기법을 사용했던 문제가 3~4문제 가량 되는 것 같아서 이 기법에 대해 정리 해보려고 한다.


기초 지식은 unlink는 free가 연속적으로 진행될 때에 병합시키기 위해 호출하는 매크로라는 것이다.


먼저, malloc.c 소스를 보자


/* Take a chunk off a bin list */
#define unlink(P, BK, FD) {                                            \
  FD = P->fd;                                                          \
  BK = P->bk;                                                          \
  if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                \
    malloc_printerr (check_action, "corrupted double-linked list", P); \
  else {                                                               \
    FD->bk = BK;                                                       \
    BK->fd = FD;                                                       \
    if (!in_smallbin_range (P->size)				       \
	&& __builtin_expect (P->fd_nextsize != NULL, 0)) {	       \
      assert (P->fd_nextsize->bk_nextsize == P);		       \
      assert (P->bk_nextsize->fd_nextsize == P);		       \
      if (FD->fd_nextsize == NULL) {				       \
	if (P->fd_nextsize == P)				       \
	  FD->fd_nextsize = FD->bk_nextsize = FD;		       \
	else {							       \
	  FD->fd_nextsize = P->fd_nextsize;			       \
	  FD->bk_nextsize = P->bk_nextsize;			       \
	  P->fd_nextsize->bk_nextsize = FD;			       \
	  P->bk_nextsize->fd_nextsize = FD;			       \
	}							       \
      }	else {							       \
	P->fd_nextsize->bk_nextsize = P->bk_nextsize;		       \
	P->bk_nextsize->fd_nextsize = P->fd_nextsize;		       \
      }								       \
    }								       \
  }                                                                    \
}

내가 중점적으로 보려는 코드는 딱 4줄이다.

  if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                
    malloc_printerr (check_action, "corrupted double-linked list", P); 

  else {                                                               
    FD->bk = BK;                                                       
    BK->fd = FD;                                                       

이다.


위 코드는 FD->bk와 BK->fd가 똑바로된 malloc청크를 가르키고 있는지에 관한 체크이다.


이것도 최근 들어서의 이야기이지 이렇게 패치 되기 전의 unlink는 

저런 체크 없이 바로 병합을 진행해서 FD와 bk에 뭘 덮든 상관이 없었다.(매우 취약했다.)


아래 코드에 대한 해석이다.


/*         32BIT         */
FD = P->fd; -> FD = *P + 8;
BK = P->bk; -> BK = *P + 12;
FD->bk = BK; -> FD + 12 = BK;
BK->fd = FD; -> BK + 8 = FD;

/*         64BIT         */
FD = P->fd; -> FD = *P + 16;
BK = P->bk; -> BK = *P + 24;
FD->bk = BK; -> FD + 24 = BK;
BK->fd = FD; -> BK + 16 = FD;

32bit와 64bit는 메모리를 사용하는 범위가 다르니 이러한 차이점이 생긴다.

이것이 무엇을 의미하냐하면

내가 만약 FD와 BK 포인터를 조작 가능하게 된다면 

32BIT : FD+12위치를 BK로 덮어씀

64BIT : FD+24위치를 BK로 덮어씀

이게 가능해진다는 것이다.


EXPLOIT

자 unlink도 패치가 되었고 이젠 어떻게 엉덩이(HEAP)을 건드냐에 대한 의문점이 생긴다.

방법은 존재한다.

내가 풀어왔던 문제들은 모두 한가지 공통점이 있었다.

malloc pointer주소를 bss영역에 할당해놔서 분석하는 과정에서 주소가 다 보인다.

그래서 이 주소를 fd와 bk에 넣어 우회할 수 있다.

'Security > Pwnable' 카테고리의 다른 글

BCTF memo  (0) 2016.12.11
fastbin consolidate  (0) 2016.12.08
0ctf freenote  (0) 2016.12.06
HITCON 2016 SecretHolder  (0) 2016.12.01
pwnable 문제 주의할 것  (0) 2016.11.22
Comments