/src/fuzzpcap/fuzz_pcap.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2021 Catena cyber |
2 | | // Author Philippe Antoine <p.antoine@catenacyber.fr> |
3 | | |
4 | | #define _GNU_SOURCE |
5 | | #include <stdint.h> |
6 | | #include <stddef.h> |
7 | | #include <string.h> |
8 | | #include <stdlib.h> |
9 | | |
10 | | #include <pcap/pcap.h> |
11 | | |
12 | | #include "fuzz_pcap.h" |
13 | | |
14 | 70.1k | int FPC_IsFuzzPacketCapture(const uint8_t *Data, size_t Size) { |
15 | 70.1k | if (Size < FPC0_HEADER_LEN) { |
16 | 11 | return 0; |
17 | 11 | } |
18 | 70.1k | if (memcmp(Data, FPC0_MAGIC, FPC0_MAGIC_LEN - 1) != 0) { |
19 | 62 | return 0; |
20 | 62 | } |
21 | 70.1k | if (FPC_datalink_to(Data[FPC0_MAGIC_LEN-1] & 0x7F) == FPC_DATALINK_ERROR) { |
22 | 4 | return 0; |
23 | 4 | } |
24 | 70.0k | return 1; |
25 | 70.1k | } |
26 | | |
27 | 140k | uint32_t FPC_datalink_to(uint8_t in) { |
28 | 140k | if (in == DLT_NULL || in == DLT_EN10MB) { |
29 | 140k | return in; |
30 | 140k | } |
31 | 4 | return (uint32_t) FPC_DATALINK_ERROR; |
32 | 140k | } |
33 | | |
34 | 0 | uint8_t FPC_datalink_from(uint32_t in) { |
35 | 0 | if (in == DLT_NULL || in == DLT_EN10MB) { |
36 | 0 | return in; |
37 | 0 | } |
38 | 0 | return FPC_DATALINK_ERROR; |
39 | 0 | } |
40 | | |
41 | 70.1k | int FPC_init(FPC_buffer_t *r, const uint8_t *Data, size_t Size) { |
42 | 70.1k | if (!FPC_IsFuzzPacketCapture(Data, Size)) { |
43 | 77 | return -1; |
44 | 77 | } |
45 | 70.0k | r->Data = Data; |
46 | 70.0k | r->Size = Size; |
47 | 70.0k | r->datalink = FPC_datalink_to(Data[FPC0_MAGIC_LEN-1] & 0x7F); |
48 | 70.0k | r->tcpSingleStream = (Data[FPC0_MAGIC_LEN-1] & 0x80); |
49 | 70.0k | if (r->tcpSingleStream) { |
50 | 36.3k | r->offset = FPC0_HEADER_LEN; |
51 | 36.3k | } else { |
52 | 33.7k | r->offset = FPC0_MAGIC_LEN; |
53 | 33.7k | } |
54 | 70.0k | memset(r->pkt, 0, FPC_SNAPLEN); |
55 | 70.0k | r->tcpState = FPC_TCP_STATE_START; |
56 | 70.0k | r->seqCliAckSrv = 0x10000000; |
57 | 70.0k | r->seqSrvAckCli = 0x20000000; |
58 | 70.0k | r->nb = 0; |
59 | 70.0k | return 0; |
60 | 70.1k | } |
61 | | |
62 | 72.4k | #define FPC_TCP_FLAG_SYN 0x02 |
63 | 7.53M | #define FPC_TCP_FLAG_ACK 0x10 |
64 | 108k | #define FPC_TCP_FLAGS_NEG_OFFSET 7 |
65 | | |
66 | 7.51M | #define FPC_NULL_HEADER "\x02\x00\x00\x00" |
67 | 15.0M | #define FPC_NULL_HEADER_LEN 4 |
68 | | |
69 | 22.0k | #define FPC_ETH_HEADER "\x00\x01\x02\x03\x04\x05\x00\x01\x02\x03\x04\x05\x08\x00" |
70 | 44.1k | #define FPC_ETH_HEADER_LEN 14 |
71 | | |
72 | 7.53M | #define FPC_IP4_HEADER "\x45\x00\xff\xff\x00\x00\x40\x00\x40\x06\x00\x00\x7f\x00\x00\x01" \ |
73 | 7.53M | "\x7f\x00\x00\x01" |
74 | 30.1M | #define FPC_IP4_HEADER_LEN 20 |
75 | | |
76 | 7.53M | #define FPC_TCP_HEADER_END "\xFF\xFF\x00\x00\x00\x00" |
77 | 15.0M | #define FPC_TCP_HEADER_END_LEN 6 |
78 | | |
79 | 7.53M | static bpf_u_int32 buildTCPpacket(FPC_buffer_t *pkts, bool s2c, size_t plen) { |
80 | 7.53M | bpf_u_int32 r = 0; |
81 | 7.53M | if (pkts->datalink == DLT_NULL) { |
82 | 7.51M | memcpy(pkts->pkt, FPC_NULL_HEADER, FPC_NULL_HEADER_LEN); |
83 | 7.51M | r = FPC_NULL_HEADER_LEN; |
84 | 7.51M | } else if (pkts->datalink == DLT_EN10MB) { |
85 | 22.0k | memcpy(pkts->pkt, FPC_ETH_HEADER, FPC_ETH_HEADER_LEN); |
86 | 22.0k | r = FPC_ETH_HEADER_LEN; |
87 | 22.0k | } else { |
88 | | //unreachable |
89 | 0 | abort(); |
90 | 0 | } |
91 | 7.53M | memcpy(pkts->pkt+r, FPC_IP4_HEADER, FPC_IP4_HEADER_LEN); |
92 | 7.53M | pkts->pkt[r+2] = (plen + FPC_IP4_HEADER_LEN + 20) >> 8; |
93 | 7.53M | pkts->pkt[r+3] = (plen + FPC_IP4_HEADER_LEN+ 20); |
94 | 7.53M | r += FPC_IP4_HEADER_LEN; |
95 | | //ports |
96 | 7.53M | if (s2c) { |
97 | 3.61M | memcpy(pkts->pkt+r, pkts->Data+FPC0_MAGIC_LEN, 2); |
98 | 3.61M | memcpy(pkts->pkt+r+2, pkts->Data+FPC0_MAGIC_LEN+2, 2); |
99 | 3.61M | pkts->pkt[r+4] = pkts->seqSrvAckCli >> 24; |
100 | 3.61M | pkts->pkt[r+5] = pkts->seqSrvAckCli >> 16; |
101 | 3.61M | pkts->pkt[r+6] = pkts->seqSrvAckCli >> 8; |
102 | 3.61M | pkts->pkt[r+7] = pkts->seqSrvAckCli; |
103 | 3.61M | pkts->pkt[r+8] = pkts->seqCliAckSrv >> 24; |
104 | 3.61M | pkts->pkt[r+9] = pkts->seqCliAckSrv >> 16; |
105 | 3.61M | pkts->pkt[r+10] = pkts->seqCliAckSrv >> 8; |
106 | 3.61M | pkts->pkt[r+11] = pkts->seqCliAckSrv; |
107 | 3.92M | } else { |
108 | 3.92M | memcpy(pkts->pkt+r, pkts->Data+FPC0_MAGIC_LEN+2, 2); |
109 | 3.92M | memcpy(pkts->pkt+r+2, pkts->Data+FPC0_MAGIC_LEN, 2); |
110 | 3.92M | pkts->pkt[r+4] = pkts->seqCliAckSrv >> 24; |
111 | 3.92M | pkts->pkt[r+5] = pkts->seqCliAckSrv >> 16; |
112 | 3.92M | pkts->pkt[r+6] = pkts->seqCliAckSrv >> 8; |
113 | 3.92M | pkts->pkt[r+7] = pkts->seqCliAckSrv; |
114 | 3.92M | if (pkts->tcpState != FPC_TCP_STATE_SYN) { |
115 | 3.88M | pkts->pkt[r+8] = pkts->seqSrvAckCli >> 24; |
116 | 3.88M | pkts->pkt[r+9] = pkts->seqSrvAckCli >> 16; |
117 | 3.88M | pkts->pkt[r+10] = pkts->seqSrvAckCli >> 8; |
118 | 3.88M | pkts->pkt[r+11] = pkts->seqSrvAckCli; |
119 | 3.88M | } |
120 | 3.92M | } |
121 | 7.53M | r += 12; |
122 | 7.53M | pkts->pkt[r] = 0x50; // TCP length |
123 | 7.53M | if (pkts->tcpState == FPC_TCP_STATE_ESTABLISHED) { |
124 | 7.46M | pkts->pkt[r+1] = FPC_TCP_FLAG_ACK; // flags |
125 | 7.46M | } else { |
126 | 72.4k | pkts->pkt[r+1] = 0; // flags |
127 | 72.4k | } |
128 | 7.53M | r+=2; |
129 | 7.53M | memcpy(pkts->pkt+r, FPC_TCP_HEADER_END, FPC_TCP_HEADER_END_LEN); |
130 | 7.53M | r+=FPC_TCP_HEADER_END_LEN; |
131 | 7.53M | return r; |
132 | 7.53M | } |
133 | | |
134 | 7.53M | #define FCP_BASE_TIME 0x601cf51a |
135 | | |
136 | 9.24M | int FPC_next_pcap(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) { |
137 | 9.24M | *pkt = pkts->Data + pkts->offset + FPC_TS_MAXSIZE; |
138 | 9.24M | const uint8_t *next = memmem(pkts->Data + pkts->offset, pkts->Size - pkts->offset, FPC0_MAGIC, FPC0_MAGIC_LEN); |
139 | 9.24M | if (next == NULL) { |
140 | 26.8k | next = pkts->Data + pkts->Size; |
141 | 26.8k | } |
142 | 9.24M | if (next < *pkt) { |
143 | | //wrong input |
144 | 4.09k | return -1; |
145 | 4.09k | } |
146 | | |
147 | 9.24M | memset(header, 0, sizeof(struct pcap_pkthdr)); |
148 | 9.24M | header->ts.tv_sec = *((time_t *) (pkts->Data + pkts->offset)); |
149 | 9.24M | if (header->ts.tv_sec < 0) { |
150 | 963k | header->ts.tv_sec = 0; |
151 | 963k | } |
152 | 9.24M | header->ts.tv_usec = *((suseconds_t *) (pkts->Data + pkts->offset + FPC_TS_MAXSIZE/2)); |
153 | | // Limit microseconds to 1 million |
154 | 9.24M | header->ts.tv_usec = ((header->ts.tv_usec % 1000000) + 1000000) % 1000000; |
155 | 9.24M | header->caplen = next - (*pkt); |
156 | 9.24M | pkts->offset += header->caplen + FPC_TS_MAXSIZE + FPC0_MAGIC_LEN; |
157 | 9.24M | header->len = header->caplen; |
158 | 9.24M | return 1; |
159 | 9.24M | } |
160 | | |
161 | 7.53M | int FPC_next_tcp(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) { |
162 | 7.53M | *pkt = pkts->Data + pkts->offset; |
163 | 7.53M | const uint8_t *next = memmem(pkts->Data + pkts->offset, pkts->Size - pkts->offset, FPC0_MAGIC, FPC0_MAGIC_LEN); |
164 | 7.53M | if (next == NULL) { |
165 | 42.1k | next = pkts->Data + pkts->Size; |
166 | 42.1k | } |
167 | 7.53M | if (next < *pkt) { |
168 | | //wrong input |
169 | 0 | return -1; |
170 | 0 | } |
171 | | |
172 | 7.53M | memset(header, 0, sizeof(struct pcap_pkthdr)); |
173 | 7.53M | header->ts.tv_sec = FCP_BASE_TIME; |
174 | 7.53M | header->ts.tv_usec = pkts->nb; |
175 | 7.53M | pkts->nb++; |
176 | 7.53M | header->caplen = next - (*pkt); |
177 | | |
178 | 7.53M | if (pkts->tcpState > FPC_TCP_STATE_SYNACK) { |
179 | 7.42M | pkts->offset += header->caplen + FPC0_MAGIC_LEN; |
180 | 7.42M | } |
181 | 7.53M | switch (pkts->tcpState) { |
182 | 36.2k | case FPC_TCP_STATE_START: |
183 | 36.2k | pkts->tcpState = FPC_TCP_STATE_SYN; |
184 | 36.2k | header->caplen = buildTCPpacket(pkts, false, 0); |
185 | 36.2k | *pkt = pkts->pkt; |
186 | 36.2k | pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_SYN; |
187 | 36.2k | pkts->seqCliAckSrv++; |
188 | 36.2k | break; |
189 | | |
190 | 36.2k | case FPC_TCP_STATE_SYN: |
191 | 36.2k | pkts->tcpState = FPC_TCP_STATE_SYNACK; |
192 | 36.2k | header->caplen = buildTCPpacket(pkts, true, 0); |
193 | 36.2k | *pkt = pkts->pkt; |
194 | 36.2k | pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_SYN | FPC_TCP_FLAG_ACK; |
195 | 36.2k | pkts->seqSrvAckCli++; |
196 | 36.2k | break; |
197 | | |
198 | 36.2k | case FPC_TCP_STATE_SYNACK: |
199 | 36.2k | pkts->tcpState = FPC_TCP_STATE_ESTABLISHED; |
200 | 36.2k | header->caplen = buildTCPpacket(pkts, false, 0); |
201 | 36.2k | *pkt = pkts->pkt; |
202 | 36.2k | pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_ACK; |
203 | 36.2k | break; |
204 | | |
205 | 7.42M | case FPC_TCP_STATE_ESTABLISHED: |
206 | 7.42M | if (header->caplen < 1) { |
207 | 106 | return -1; |
208 | 106 | } |
209 | 7.42M | header->caplen--; |
210 | 7.42M | bool s2c = (*pkt[0]) & 1; |
211 | 7.42M | header->len = buildTCPpacket(pkts, s2c, header->caplen); |
212 | 7.42M | if (header->caplen + header->len > FPC_SNAPLEN) { |
213 | 762 | header->caplen = FPC_SNAPLEN - header->len; |
214 | 762 | } |
215 | 7.42M | memcpy(pkts->pkt+header->len, *pkt+1, header->caplen); |
216 | 7.42M | if (s2c) { |
217 | 3.57M | pkts->seqSrvAckCli += header->caplen; |
218 | 3.85M | } else { |
219 | 3.85M | pkts->seqCliAckSrv += header->caplen; |
220 | 3.85M | } |
221 | 7.42M | header->caplen += header->len; |
222 | 7.42M | *pkt = pkts->pkt; |
223 | 7.42M | break; |
224 | 7.53M | } |
225 | 7.53M | header->len = header->caplen; |
226 | 7.53M | return 1; |
227 | 7.53M | } |
228 | | |
229 | 16.8M | int FPC_next(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) { |
230 | 16.8M | if (pkts->offset >= pkts->Size) { |
231 | 61.3k | return 0; |
232 | 61.3k | } |
233 | | |
234 | 16.7M | if (pkts->tcpSingleStream) { |
235 | 7.53M | return FPC_next_tcp(pkts, header, pkt); |
236 | 7.53M | } //else |
237 | 9.24M | return FPC_next_pcap(pkts, header, pkt); |
238 | 16.7M | } |