[하루한줄] OpenBSD의 Heap Buffer Overflow 취약점

URL

Heap Overflow in OpenBSD’s slaacd via Router Advertisement

Target

  • OpenBSD 6.9, 7.0

Explain

OpenBSD의 IPv6 스택 중 라우터 요청 메시지를 보내고 수신된 라우터 알림 응답을 파싱하는 SLAAC(Stateless Address Autoconfiguration) 데몬인 slaacd 에서 Heap Buffer Overflow 취약점이 발견되었습니다.

Router Advertisement(RA)는 IPv6 프로토콜 스택 중 Neighbeor Discovery(ND) 프로토콜의 메시지 타입 중 하나이며 링크 및 인터넷 매개변수와 함께 라우터가 있음을 알리는 역할을 합니다. RA 패킷에는 DNS 검색 목록(DNSSL)이 포함되는데, 이 DNSSL을 파싱하는 sbin/slaacd/engine.cparse_dnssl 함수에서 취약점이 발견되었습니다.

char* parse_dnssl(char* data, int datalen) {
	int len, pos;     // [1]
	char *nssl, *nsslp;

	if((nssl = calloc(1, datalen + 1)) == NULL) {
		log_warn("malloc");
		return NULL;
  }
	nsslp = nssl;

	pos = 0;

	do {
		len = data[pos];  // [2]
		if (len > 63 || len + pos + 1 > datalen) {  //[3]
			free(nssl);
			log_warnx("invalid label in DNSSL");
			return NULL;
		}

		if (len == 0) {
			if (pos < datalen && data[pos + 1] != 0)
				*nsslp++ = ' '; /* seperator for next domain */
			else
				break;
		} else {
			if (pos != 0 && data[pos - 1] != 0) /* no . at front */
				*nsslp++ = '.';
				memcpy(nsslp, data + pos + 1, len);  // [4]
				nsslp += len;
			}
			pos += len + 1;
    } while(pos < datalen);

    if (len != 0) {
			free(nssl);
			log_warnx("invalid label in DNSSL");
			return NULL;
    }
    return nssl;
}

취약점은 레이블의 길이 필드를 읽을 때 signed 정수인 len을 사용해 발생합니다.

[1] : signed 정수 int len을 선언합니다.

[2]: 레이블에 음수가 포함되면 len이 음수가 됩니다.

[3]: 음수 len으로 인해 길이 검사를 우회할 수 있습니다.

[4]: memcpy()에 전달되는 세 번째 인수 포맷은 unsigned인 size_t이기 때문에 묵시적 형 변환으로 인해 INT_MAX 값이 전달되어 예상보다 큰 길이를 복사하게 되고, 이는 nsslp 버퍼의 heap buffer overflow로 이어집니다.