Home Tcache Poisoning
Post
Cancel

libc > 2.25 이후부터 적용된 heap 관리 방법이며, 2.29부터는 패치 되었다고 한다.


두번의 32 byte heap 영역 할당을 통해 아래와 같이 데이터가 들어있다고 가정하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
gef➤ heap chunks 
Chunk(addr=0x602010, size=0x290, flags=PREV_INUSE) 
	[0x0000000000602010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................] 
Chunk(addr=0x6022a0, size=0x30, flags=PREV_INUSE) 
	[0x00000000006022a0 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa] 
Chunk(addr=0x6022d0, size=0x30, flags=PREV_INUSE) 
	[0x00000000006022d0 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 bbbbbbbbbbbbbbbb] 
Chunk(addr=0x602300, size=0x20d10, flags=PREV_INUSE) 
	[0x0000000000602300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................] 
Chunk(addr=0x602300, size=0x20d10, flags=PREV_INUSE) ← top chunk 

gef➤ x/40gx 0x602010 
0x602010: 0x0000000000000000 0x0000000000000000 
... 
0x602290: 0x0000000000000000 0x0000000000000031 
0x6022a0: 0x6161616161616161 0x6161616161616161 
0x6022b0: 0x6161616161616161 0x0061616161616161 
0x6022c0: 0x0000000000000000 0x0000000000000031 
0x6022d0: 0x6262626262626262 0x6262626262626262 
0x6022e0: 0x6262626262626262 0x0062626262626262 
0x6022f0: 0x0000000000000000 0x0000000000020d11
  • 0x602010 : tcache
  • 0x6022a0 : 청크 1
  • 0x6022d0 : 청크 2

이후 가장 마지막 heap 영역을 free 하면 tcache에 fd 주소가 저장된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
gef➤  heap chunks
Chunk(addr=0x602010, size=0x290, flags=PREV_INUSE)
    [0x0000000000602010     00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00    ................]
Chunk(addr=0x6022a0, size=0x30, flags=PREV_INUSE)
    [0x00000000006022a0     61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61    aaaaaaaaaaaaaaaa]
Chunk(addr=0x6022d0, size=0x30, flags=PREV_INUSE)
    [0x00000000006022d0     02 06 00 00 00 00 00 00 10 20 60 00 00 00 00 00    ......... `.....]
Chunk(addr=0x602300, size=0x20d10, flags=PREV_INUSE)
    [0x0000000000602300     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................]
Chunk(addr=0x602300, size=0x20d10, flags=PREV_INUSE)  ←  top chunk
gef➤  x/40gx 0x602010
0x602010:       0x0000000000010000      0x0000000000000000
...
0x602090:       0x0000000000000000      0x00000000006022d0
0x6020a0:       0x0000000000000000      0x0000000000000000
...
0x602290:       0x0000000000000000      0x0000000000000031
0x6022a0:       0x6161616161616161      0x6161616161616161
0x6022b0:       0x6161616161616161      0x0061616161616161
0x6022c0:       0x0000000000000000      0x0000000000000031
0x6022d0:       0x0000000000000602      0x0000000000602010
0x6022e0:       0x6262626262626262      0x0062626262626262
0x6022f0:       0x0000000000000000      0x0000000000020d11

tcache의 첫 8byte에는 free된 횟수가 입력되어 있고, 이후에는 free 된 청크(0x6022d0)의 주소가 들어있다.

그리고 해제된 청크 bk에는 tcache의 시작 주소가 입력되어 있다.

만약 heap 영역을 다시 할당받고 데이터를 넣으려고 하면 0x6022d0이 tcache에 있기 때문에 이 청크부터 할당 될 것이다. 즉, tcache는 다음 heap 영역 할당 시 사용될 청크 주소를 저장하는 곳인걸 알 수 있다.


tcache에서는 free시 double free를 확인하기 위해 tcache 영역에 저장된 해제된 청크 주소와 bk 값을 비교한다.

만일 bk 값을 변조가 가능하다면 어떻게 될까

아래와 같이 현재 bk 값인 0x602010에서 1byte만 변조하고

1
2
3
4
gef➤  x/40gx 0x602010
...
0x6022d0:       0x6363636363636363      0x000000000060200a
...

다시 free해보면 free가 가능한 것을 확인 할 수 있고, tcache 첫번째 8byte 내에 2가 입력되어 있는 것으로 청크 2개가 free된 것으로 인식하고 있는 것을 알 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
gef➤  x/40gx 0x602010
0x602010:       0x0000000000020000      0x0000000000000000
0x602020:       0x0000000000000000      0x0000000000000000
...
0x602080:       0x0000000000000000      0x0000000000000000
0x602090:       0x0000000000000000      0x00000000006022d0
0x6020a0:       0x0000000000000000      0x0000000000000000
...
0x602290:       0x0000000000000000      0x0000000000000031
0x6022a0:       0x6161616161616161      0x6161616161616161
0x6022b0:       0x6161616161616161      0x0061616161616161
0x6022c0:       0x0000000000000000      0x0000000000000031
0x6022d0:       0x00000000006024d2      0x0000000000602010
0x6022e0:       0x6262626262626262      0x0062626262626262
0x6022f0:       0x0000000000000000      0x0000000000020d11

만약 최초 free 및 bk 값 변경 후 다시 청크를 할당받고 값을 넣으려하면 어떻게 될까

32byte 청크 할당 및 데이터를 넣은 후 free 한 뒤 상태는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
gef➤  x/40gx 0x602010
0x602010:       0x0000000000010000      0x0000000000000000
...
0x602090:       0x0000000000000000      0x00000000006022a0
...
0x602290:       0x0000000000000000      0x0000000000000031
0x6022a0:       0x0000000000000602      0x0000000000602010
0x6022b0:       0x6161616161616161      0x0061616161616161
0x6022c0:       0x0000000000000000      0x0000000000020d41
...

이후 bk 영역의 값을 수정하고

1
2
3
4
0x602290:       0x0000000000000000      0x0000000000000031
0x6022a0:       0x6262626262626262      0x6363636363636363 #여기 8byte가 bk?
0x6022b0:       0x616161616161610a      0x0061616161616161
0x6022c0:       0x0000000000000000      0x0000000000020d41

다시 heap 할당을 해보면

1
2
3
4
5
6
7
8
9
gef➤  x/40gx 0x602010
0x602010:       0x0000000000000000      0x0000000000000000
...
0x602090:       0x0000000000000000      0x6262626262626460
...
0x602290:       0x0000000000000000      0x0000000000000031
0x6022a0:       0x6464646464646464      0x6464646464646464
0x6022b0:       0x6464646464646464      0x0064646464646464
0x6022c0:       0x0000000000000000      0x0000000000020d41

tcache에 청크의 값이 일부 삽입된 것을 볼 수 있으며 이는 다음에 heap 영역이 할당될 주소를 가지고 있음을 의미한다.


다만 위의 값에서는 tcache의 첫 8byte가 0이기에 tcache 내에 다음에 사용할 주소 값이 있어도 사용하지는 않는다.

만일 여기서 tcache 첫 8byte에 값이 1이상으로 남아있다면 어떻게 될까

heap 할당 -> free -> bk 변조 -> free -> bk 변조 후 heap 모양은 아래와 같다.

1
2
3
4
5
6
7
8
9
gef➤  x/40gx 0x602010
0x602010:       0x0000000000020000      0x0000000000000000
...
0x602090:       0x0000000000000000      0x00000000006022a0
...
0x602290:       0x0000000000000000      0x0000000000000031
0x6022a0:       0x6262626262626262      0x6262626262626262
0x6022b0:       0x6262626262626262      0x0062626262626262
0x6022c0:       0x0000000000000000      0x0000000000020d41

이후 heap 할당을 1회 하면 heap 모양은 아래와 같다.

1
2
3
4
5
6
7
8
9
gef➤  x/40gx 0x602010
0x602010:       0x0000000000010000      0x0000000000000000
...
0x602090:       0x0000000000000000      0x6262626262626460 #여긴가..?
...
0x602290:       0x0000000000000000      0x0000000000000031
0x6022a0:       0x6363636363636363      0x6363636363636363
0x6022b0:       0x6363636363636363      0x0063636363636363
0x6022c0:       0x0000000000000000      0x0000000000020d41

여기서 만약 heap 할당을 한번 더 하면, tcache에 값이 남아있기에 해당 주소에 값을 쓰게 된다.

This post is licensed under GNU AGPL by the author.