rosieblue
article thumbnail
728x90

Poison NULL Byte

이 공격은 인접한 청크의 메타 데이터를 조작하는 방법으로 size의 하위 1바이트를 overwrite하는 기법이다. 

데이터 영역과 다음 청크 size의 flag부분은 바로 붙어있으므로 입력한 값이 조금만 넘쳐도 overwrite하게 된다.

이를 통해 다른 공격과 연계할 수 있다. 이 버그를 트리거하는 함수로는 readdata,strncat,fgets 등이 있다. 꼭 힙이 아니더라도 Off-by-one 등 다른 공격으로도 이어질 수 있다.

// gcc -o null1 null1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int readdata(char *buf, int len){
        read(0, buf, len);
        *(char *)(buf + len) = '\x00';
}

int main(){
        char* buf1;
        char* buf2;
        buf1 = malloc(0x28);
        buf2 = malloc(0xf0);
        readdata(buf1, 0x28);
        return 0;
}

위 코드에서는 readdata라는 함수를 정의했다.(이처럼 함수를 직접 정의해서 하는 방법도 생각해보기!) 

readdata는 메모리 릭을 막기 위해 맨뒤에 NULL byte을 자동으로 추가한다. 따라서 모든 바이트를 채웠을 경우 NULL 바이트가 뒤에 붙어서 다른 메모리 공간을 침범할 수 있게 된다. 

 

따라서 청크의 데이터 영역 끝과 다음 청크의 size는 바로 붙어있으므로 인접한 청크의 prev_inuse byte를 NULL로 overwrite할 수 있겠다!!

 

위에서 buf1은 데이터 영역의 사이즈가 0x28이므로 딱 다음 청크 사이즈랑 맞닿아있다. 이때 위에서 정의한 readdata 함수를 이용하여 0x28을 다 데이터로 채우면 다음 바이트를 NULL로 채워서 prev_inuse 바이트를 0으로 세팅할 수 있을 것이다. (리틀 엔디안으로 저장되므로 플래그는 가장 맨 앞에 있음)

 

0x555555559290이 buf1이고 노란색으로 구분된 부분까지 청크가 끝난다.

 

또한 101이 위에서보면 저렇게 오른쪽 끝에 있지만, 바이트로 뽑아보면 맨 왼쪽에 있는 것을 확인할 수 있다.

리틀엔디언이므로 맨 왼쪽에 되어있다.

그래서 0x5555555592c8의 첫바이트를 덮으면 성공한다.

 

readdata에 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (a 0x28개) 를 보내주었다. 역시 0x5555555592c0의 맨마지막 바이트가 NULL로 덮인것을 볼 수 있다. 그래서 prev_inuse 비트가 0이 되어 위 청크가 Free로 처리되게 된다.

 

밑에 청크의 prev_inuse 비트가 0이 되어 0x555555559290 청크의 status가 freed로 변한 것을 볼 수 있다. 그리고 0x5555555592c0청크의 size도 0x101에서 0x100으로 바뀌었다.

 

이런식으로 Posion NULL Byte를 통해 다른 청크의 사이즈 등의 첫 바이트를 overwrite하면 unsafe unlink 공격에도 연계해 사용할 수 있다.

profile

rosieblue

@Rosieblue

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!