
D-Link 880 펌웨어용 CVE-2017-14948
이 작은 글에서 D-Link 제품에서 발견한 몇 가지 버그를 살펴보겠습니다. D-Link는 다양한 라우터 모델을 포함한 광범위한 제품을 제공하며, 각기 다른 펌웨어 버전을 탑재하고 있습니다. 이 문서에서는 다음 펌웨어 버전을 다룹니다: DIR-880L, DIR-868L, DIR-890L, DIR-885L 및 DIR-895L. 더 이상 지체하지 않고 시작하겠습니다.
D-Link 라우터를 소유하지 않았고, D-Link에서 펌웨어에 대한 무료 액세스를 제공하기 때문에, 저는 정적 분석에만 의존하여 버그를 찾기로 결정했습니다. 참고로, 이 섹션에서는 DIR-880L 펌웨어를 언급할 것이며, 다른 펌웨어도 유사한 구조를 가지고 있습니다.
DIR-880L 펌웨어를 다운로드하고 압축을 푼 후, 해당 펌웨어에 약 2160개의 파일을 포함하는 전체 squashFS 파일 시스템이 포함되어 있음을 발견했습니다. 각 파일을 개별적으로 검토하고 싶지 않았기 때문에, 사용자 입력을 처리하는 파일을 찾기 시작했습니다.
구성 파일을 분석하고 알려진 HTTP 헤더를 찾은 후, 마침내 세 개의 바이너리로 범위를 좁혔고, 최종적으로 하나인 fileaccess.cgi에 집중했습니다.
다음은 취약한 함수의 디스어셈블리입니다:
signed int __fastcall content_type(char *a1)
{
char *dest; // [sp+4h] [bp-10h]@1
const char *haystack; // [sp+Ch] [bp-8h]@1
char *haystacka; // [sp+Ch] [bp-8h]@3
dest = a1;
haystack = getenv("CONTENT_TYPE");
if ( !haystack )
return -22;
haystacka = strstr(haystack, "boundary=");
if ( !haystacka )
return -22;
strcpy(dest, haystacka + 9);
return 0;
}
위 코드에서 변수 'CONTENT_TYPE' 의 내용(변수 haystack이 가리키는)은 사용자(HTTP 요청의 헤더를 통해)에 의해 제어됩니다. 'boundary' 키워드 이후의 내용은 haystacka의 길이를 확인하지 않고 dest 버퍼로 복사됩니다. 호출 함수(주소 0x1CE6C)를 살펴보면 dest의 크기가 256바이트임을 추론할 수 있습니다. 공격자는 CONTENT_TYPE의 내용을 제어할 수 있으므로, 'boundary=' 문자열 뒤에 최소 257자 이상을 보내 버퍼 오버플로우를 유발할 수 있습니다.
같은 펌웨어 샘플에서 HTTP 쿠키와 관련된 유사한 버그 두 가지가 더 발견되었습니다. 그 중 하나는 아래와 같습니다:
v10 = getenv("HTTP_COOKIE");
if ( v10 )
{
strcpy((char *)&v5, &v10[v11]);
v17 = strlen((const char *)&v5);
}
여기서 변수 v10은 사용자 쿠키를 가리키며, 이 쿠키는 최대 4k 바이트일 수 있습니다(RFC2109에 따르면). 그러나 변수 v5는 1024바이트 크기입니다(함수의 스택 프레임에서 추론할 수 있듯이). 이로 인해 버퍼 오버플로우가 발생할 수 있습니다.
이러한 버그는 D-Link에 보고되었고 확인되었습니다.
이 펌웨어 샘플들은 DIR-880L과 유사한 구조를 가지며, 동일한 HTTP 필드와 관련된 동일한 버그를 가지고 있습니다.