[하루한줄] CVE-2024-42642: Micron MX500 SSD Series 컨트롤러의 여러 취약점

URL

https://github.com/VL4DR/CVE-2024-42642/tree/main

Target

  • SM2259 Firmware version M3CR046

Explain

유명 SSD 제조사 중 하나인 Micron의 MX500 SSD 컨트롤러에서 발견된 취약점의 세부 정보가 공개되었습니다.

MX500 시리즈는 Silicon-Motion사의 제품인 SM2259 컨트롤러는 ARC 아키텍쳐 기반의 4채널 SATA 6Gb/s 마이크로 컨트롤러를 탑재했습니다. 해당 컨트롤러에 탑재된 펌웨어 M3CR046 버전에서 세 가지 취약점이 발견되었는데, 세 취약점 모두 컨트롤러의 펌웨어 업데이트 메커니즘인 ATA PIO DOWNLOAD-MICROCODE (0x92) 에서 발생했습니다.

첫 번째 취약점은 ATA command Handler로 전송된 첫 번째 청크 크기가 섹터의 기본 크기인 0x200보다 큰 경우에 발생합니다.

if ((g_blocks_copied == 0) && (lower_bound_fw_offset <= __next_offset)) { 
	curr_bytes_to_copy = (__next_offset - lower_bound_fw_offset) * 0x200; 
	some_index = 0x200 - (__next_offset - lower_bound_fw_offset) & 0xffff; 
}

some_index를 계산할 때 다음 청크가 위치한 오프셋(첫 청크이므로 해당 청크의 크기)인 __next_offsetlower_bound_fw_offset 연산값을 섹터 크기인 0x200에서 빼는데, 이때 lower_bound_fw_offset 은 다운로드 된 펌웨어 이미지가 존재하는 오프셋을 의미하며 0으로 하드코딩되어 있습니다. 따라서 next_offset이 섹터 크기인 0x200보다 큰 경우 some_index에서 integer underflow가 발생해 최대 0xFFFF까지 더 큰 값이 될 수 있습니다.

if ((lower_bound_fw_offset <= __next_offset) && 
		(current_offset < higher_bound_fw_offset)) { 
		r_maybe_some_efficient_data_transfer 
							(1,some_index * 0x200 + Ox40000000, 
								&g_download_buffer + (uint)g_blocks_copied * Ox200, curr_bytes_to_copy,0,1 ); 
		g_blocks_copied = g_blocks_copied + (short)(curr_bytes_to_copy >> 9); 
}

이후 다운로드 버퍼로 전송하는 로직에서 예상보다 큰 some_index값을 이용해 src 주소를 계산하계 되어 예상치 못한 동작으로 이어질 수 있습니다.

두 번째 취약점은 펌웨어 이미지 크기 계산에서 발생합니다.

M3CR046 펌웨어 이미지의 크기는 0x242400 bytes(0x1212 sectors)이며, 해당 이미지 내부에는 펌웨어 업데이트 후 플래시 메모리에 기록되는 내부 펌웨어 이미지 3개가 각각 존재합니다. 각 이미지의 크기는 0xC0C00 bytes(0x606 sectors)이므로 0x606으로 하드코딩된 higher_bound_fw_offset으로 업데이트 로직에서 해당 크기를 초과하는지 검사하는 과정을 수행합니다.

if ((g_blocks_copied == 0) && (lower_bound_fw_offset <= __next_offset)) { 
	curr_bytes_to_copy = (__next_offset - lower_bound_fw_offset) * 0x200; 
	some_index = 0x200 - (__next_offset - lower_bound_fw_offset) & 0xffff; 
} 

else { 
	curr_bytes_to_copy = 0x40000; 
		/* Exactly 0x200 blocks */ 
	some_index = 0; 
}
if (higher_bound_fw_offset <= __next_offset) { 
	curr_bytes_to_copy = 
		curr_bytes_to_copy + (__next_offset - higher_bound_fw_offset) * -0x200; 
} 

첫 번째 취약점의 if 분기 실행 조건인 첫 번째 청크가 아닌 경우, else 분기를 실행합니다.

이는 첫 번째 청크가 아니면서 현재 청크의 크기가 섹터 크기인 0x200보다 큰 경우 실행된다는 의미이며, 복사할 크기를 0x200섹터 크기(0x40000)만큼 지정합니다.

이후 펌웨어 이미지의 전체 크기가 higher_bound_fw_offset(0x606)보다 큰 경우 0x606 * 0x200 bytes를 초과하는 바이트 수를 잘라내는 뺼셈 연산을 하는데, 이 과정에서 마지막으로 전달된 청크로 인해 __next_offset 값이 0x806보다 크면 integer underflow로 인해 curr_bytes_to_copy가 예상보다 큰 값이 됩니다.

이는 첫 번째 취약점과 마찬가지로 다운로드 버퍼로 전송할 바이트 수를 계산할 때 overflow로 이어질 수 있습니다.

세 번째 취약점 또한 펌웨어 이미지 크기 계산에서 발생합니다.

M3CR046의 펌웨어 이미지 크기는 앞서 언급했듯이 0x242400 bytes(0x1212 sectors)입니다. 이 역시 전송된 이미지의 총 크기가 0x1212 섹터를 초과하는지 검사하는 과정이 존재합니다.

			if ((current_offset != g_next_offset) || (__subcommand != g_last_subcommand)) {
			  g_next_offset = 0;
			  g_blocks_copied = 0;
			  DAT_ram_10005fe8 = 2;
			  current_offset = 2;
			  goto LAB_ram_80024b66;
			}
			__next_offset = g_blocks_to_transfer + current_offset & 0xffff; // (1) update __next_offset
			g_next_offset = (ushort)(g_blocks_to_transfer + current_offset);
    }
    g_last_subcommand = bVar1;
  }
  puVar4 = &g_next_offset;
  if (0x1212 < __next_offset) {   // (2) updated __next_offset is less than 0x1212
    g_next_offset = 0;
    DAT_ram_10005fe8 = 3;
    iVar3 = 3;
LAB_ram_80024e08:
    g_blocks_copied = 0;
    FUN_ram_00007b14(0x85,0,1,iVar3,0,0,0);
    FUN_ram_80023480(4);
    return;
  }

정상적인 펌웨어 업데이트의 경우 __next_offset이 0x1212보다 크면 (2)에서 상태코드를 재설정하고 오류를 반환합니다. 그러나 전송된 이미지의 총 크기가 0x1212 섹터를 초과하더라도, 다음에 처리할 ATA command가 충분히 큰 경우 __next_offset이 (1)에서 재설정되어 (2)의 검사를 우회하고 데이터 전송 로직을 수행하도록 할 수 있습니다. 결과적으로 다운로드 버퍼를 넘어 buffer overflow를 트리거할 수 있습니다.

이 취약점은 앞선 두 사례와 달리 컨트롤러를 즉시 충돌시키지 않아 악용 가능성이 더 높습니다.