Poison null byte
https://github.com/umbum/pwn/blob/master/how2heap/poison_null_byte.c
malloc’ed region에 off-by-one error가 발생할 때, next chunk size의 LSB를 0
으로 만들어 size를 속이는 방법. 결과적으로 d chunk 내부에 b2 chunk가 위치하게 되므로 d chunk에 접근해 b2 chunk를 변경할 수 있다.
null byte off-by-one error는 종종 발생하기 때문에 많은 경우에 사용할 수 있는 테크닉이라는 점은 장점.
b2 chunk는 heap에만 존재할 수 있기 때문에 b2 chunk가 function pointer 등 유용한 데이터를 저장하고 있을 경우나, overlap을 이용한 leak이 필요할 경우 말고는 그다지 쓸모가 없다는 것이 단점.
1.
a | prev_size | 0x111 |
b | prev_size | 0x211 |
0x200 | ||
c | 0x210 | 0x111 |
0x210 & 0xff00 했으므로 0x200
2. free(b) AND off-by-one overflow
a | prev_size | 0x111 |
b | prev_size | 0x200 |
0x200 | ||
c | 0x210 | 0x110 |
free(b) 했으므로 0x110
b->size
의 LSB는 0x01
이면 안된다. c->prev\_size
가 업데이트 되지 않도록, 그 이전에 c fake\_next->prev\_size
를 두어 이게 대신 업데이트 되도록 해야 하는데 0x01
이면 그냥 c->prev_size
가 업데이트 돼버린다.
3. b1 = malloc(0x100) , b2 = malloc(0x80)
a | prev_size | 0x111 |
b1 | prev_size | 0x111 |
b2 | prev_size | 0x91 |
0xf0 → 0x60 | ||
c | 0x210 | 0x110 |
4. free(b1) , free(c)
free(b1)
하지 않으면 [unlink ] corrupted double-linked list Error가 발생한다. PREV\_INUSE
flag가 없는 상태에서 free(c)
하게 되므로 prev_size
를 따라가 prev chunk를unlink 하기 위해 fd / bk
를 검사하기 때문. free’d area가 할당되어 둘로 나뉘어 질 때, 할당되지 않은 영역에 자동으로 fd / bk
가 잡히며 nextchunk.prev_size
가 자동으로 나뉘어진 chunk를 가리키도록 업데이트 되기 때문에 정상이라면 이 check를 통과할 수 있다. 그러나 off-by-one overflow로 b.size
를 변경했기 때문에 nexchuck
가 &c - 0x10
에 있는 것으로 잡혀 c.prev_size
는 계속 0x210
으로, 업데이트 되지 않는다. 따라서 c - 0x210
위치의 chunk에 fd / bk
를 설정해야 하기 때문에 free(b1)
로 이를 설정해 주고, free(c)
한다.
a | prev_size | 0x111 |
b1 | prev_size | 0x20ef1(top) |
fd | bk | |
b2 | prev_size | 0x91 |
0xf0 → 0x60 | ||
c | 0x210 | 0x110 |
이제 system은 b2 chunk의 존재를 잊어버린다.
4. d = malloc(0x300)
a | prev_size | 0x111 | |
b1 | d | prev_size | 0x311 |
b2 | prev_size | 0x91 | |
0xf0 → 0x60 | |||
c | 0x210 | 0x110 | |
d chunk에 접근해서 b2 chunk를 변경할 수 있다.