/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 | 14.7k | int FPC_IsFuzzPacketCapture(const uint8_t *Data, size_t Size) { |
15 | 14.7k | if (Size < FPC0_HEADER_LEN) { |
16 | 0 | return 0; |
17 | 0 | } |
18 | 14.7k | if (memcmp(Data, FPC0_MAGIC, FPC0_MAGIC_LEN - 1) != 0) { |
19 | 18 | return 0; |
20 | 18 | } |
21 | 14.7k | if (FPC_datalink_to(Data[FPC0_MAGIC_LEN-1] & 0x7F) == FPC_DATALINK_ERROR) { |
22 | 1 | return 0; |
23 | 1 | } |
24 | 14.7k | return 1; |
25 | 14.7k | } |
26 | | |
27 | 29.4k | uint32_t FPC_datalink_to(uint8_t in) { |
28 | 29.4k | if (in == DLT_NULL || in == DLT_EN10MB) { |
29 | 29.4k | return in; |
30 | 29.4k | } |
31 | 1 | return (uint32_t) FPC_DATALINK_ERROR; |
32 | 29.4k | } |
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 | 14.7k | int FPC_init(FPC_buffer_t *r, const uint8_t *Data, size_t Size) { |
42 | 14.7k | if (!FPC_IsFuzzPacketCapture(Data, Size)) { |
43 | 19 | return -1; |
44 | 19 | } |
45 | 14.7k | r->Data = Data; |
46 | 14.7k | r->Size = Size; |
47 | 14.7k | r->datalink = FPC_datalink_to(Data[FPC0_MAGIC_LEN-1] & 0x7F); |
48 | 14.7k | r->tcpSingleStream = (Data[FPC0_MAGIC_LEN-1] & 0x80); |
49 | 14.7k | if (r->tcpSingleStream) { |
50 | 2.13k | r->offset = FPC0_HEADER_LEN; |
51 | 12.5k | } else { |
52 | 12.5k | r->offset = FPC0_MAGIC_LEN; |
53 | 12.5k | } |
54 | 14.7k | memset(r->pkt, 0, FPC_SNAPLEN); |
55 | 14.7k | r->tcpState = FPC_TCP_STATE_START; |
56 | 14.7k | r->seqCliAckSrv = 0x10000000; |
57 | 14.7k | r->seqSrvAckCli = 0x20000000; |
58 | 14.7k | r->nb = 0; |
59 | 14.7k | return 0; |
60 | 14.7k | } |
61 | | |
62 | 4.27k | #define FPC_TCP_FLAG_SYN 0x02 |
63 | 390k | #define FPC_TCP_FLAG_ACK 0x10 |
64 | 6.40k | #define FPC_TCP_FLAGS_NEG_OFFSET 7 |
65 | | |
66 | 333k | #define FPC_NULL_HEADER "\x02\x00\x00\x00" |
67 | 666k | #define FPC_NULL_HEADER_LEN 4 |
68 | | |
69 | 57.5k | #define FPC_ETH_HEADER "\x00\x01\x02\x03\x04\x05\x00\x01\x02\x03\x04\x05\x08\x00" |
70 | 115k | #define FPC_ETH_HEADER_LEN 14 |
71 | | |
72 | 390k | #define FPC_IP4_HEADER "\x45\x00\xff\xff\x00\x00\x40\x00\x40\x06\x00\x00\x7f\x00\x00\x01" \ |
73 | 390k | "\x7f\x00\x00\x01" |
74 | 1.56M | #define FPC_IP4_HEADER_LEN 20 |
75 | | |
76 | 390k | #define FPC_TCP_HEADER_END "\xFF\xFF\x00\x00\x00\x00" |
77 | 781k | #define FPC_TCP_HEADER_END_LEN 6 |
78 | | |
79 | 390k | static bpf_u_int32 buildTCPpacket(FPC_buffer_t *pkts, bool s2c, size_t plen) { |
80 | 390k | bpf_u_int32 r = 0; |
81 | 390k | if (pkts->datalink == DLT_NULL) { |
82 | 333k | memcpy(pkts->pkt, FPC_NULL_HEADER, FPC_NULL_HEADER_LEN); |
83 | 333k | r = FPC_NULL_HEADER_LEN; |
84 | 333k | } else if (pkts->datalink == DLT_EN10MB) { |
85 | 57.5k | memcpy(pkts->pkt, FPC_ETH_HEADER, FPC_ETH_HEADER_LEN); |
86 | 57.5k | r = FPC_ETH_HEADER_LEN; |
87 | 57.5k | } else { |
88 | | //unreachable |
89 | 0 | abort(); |
90 | 0 | } |
91 | 390k | memcpy(pkts->pkt+r, FPC_IP4_HEADER, FPC_IP4_HEADER_LEN); |
92 | 390k | pkts->pkt[r+2] = (plen + FPC_IP4_HEADER_LEN + 20) >> 8; |
93 | 390k | pkts->pkt[r+3] = (plen + FPC_IP4_HEADER_LEN+ 20); |
94 | 390k | r += FPC_IP4_HEADER_LEN; |
95 | | //ports |
96 | 390k | if (s2c) { |
97 | 219k | memcpy(pkts->pkt+r, pkts->Data+FPC0_MAGIC_LEN, 2); |
98 | 219k | memcpy(pkts->pkt+r+2, pkts->Data+FPC0_MAGIC_LEN+2, 2); |
99 | 219k | pkts->pkt[r+4] = pkts->seqSrvAckCli >> 24; |
100 | 219k | pkts->pkt[r+5] = pkts->seqSrvAckCli >> 16; |
101 | 219k | pkts->pkt[r+6] = pkts->seqSrvAckCli >> 8; |
102 | 219k | pkts->pkt[r+7] = pkts->seqSrvAckCli; |
103 | 219k | pkts->pkt[r+8] = pkts->seqCliAckSrv >> 24; |
104 | 219k | pkts->pkt[r+9] = pkts->seqCliAckSrv >> 16; |
105 | 219k | pkts->pkt[r+10] = pkts->seqCliAckSrv >> 8; |
106 | 219k | pkts->pkt[r+11] = pkts->seqCliAckSrv; |
107 | 219k | } else { |
108 | 171k | memcpy(pkts->pkt+r, pkts->Data+FPC0_MAGIC_LEN+2, 2); |
109 | 171k | memcpy(pkts->pkt+r+2, pkts->Data+FPC0_MAGIC_LEN, 2); |
110 | 171k | pkts->pkt[r+4] = pkts->seqCliAckSrv >> 24; |
111 | 171k | pkts->pkt[r+5] = pkts->seqCliAckSrv >> 16; |
112 | 171k | pkts->pkt[r+6] = pkts->seqCliAckSrv >> 8; |
113 | 171k | pkts->pkt[r+7] = pkts->seqCliAckSrv; |
114 | 171k | if (pkts->tcpState != FPC_TCP_STATE_SYN) { |
115 | 168k | pkts->pkt[r+8] = pkts->seqSrvAckCli >> 24; |
116 | 168k | pkts->pkt[r+9] = pkts->seqSrvAckCli >> 16; |
117 | 168k | pkts->pkt[r+10] = pkts->seqSrvAckCli >> 8; |
118 | 168k | pkts->pkt[r+11] = pkts->seqSrvAckCli; |
119 | 168k | } |
120 | 171k | } |
121 | 390k | r += 12; |
122 | 390k | pkts->pkt[r] = 0x50; // TCP length |
123 | 390k | if (pkts->tcpState == FPC_TCP_STATE_ESTABLISHED) { |
124 | 386k | pkts->pkt[r+1] = FPC_TCP_FLAG_ACK; // flags |
125 | 386k | } else { |
126 | 4.27k | pkts->pkt[r+1] = 0; // flags |
127 | 4.27k | } |
128 | 390k | r+=2; |
129 | 390k | memcpy(pkts->pkt+r, FPC_TCP_HEADER_END, FPC_TCP_HEADER_END_LEN); |
130 | 390k | r+=FPC_TCP_HEADER_END_LEN; |
131 | 390k | return r; |
132 | 390k | } |
133 | | |
134 | 390k | #define FCP_BASE_TIME 0x601cf51a |
135 | | |
136 | 6.17M | int FPC_next_pcap(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) { |
137 | 6.17M | *pkt = pkts->Data + pkts->offset + FPC_TS_MAXSIZE; |
138 | 6.17M | const uint8_t *next = memmem(pkts->Data + pkts->offset, pkts->Size - pkts->offset, FPC0_MAGIC, FPC0_MAGIC_LEN); |
139 | 6.17M | if (next == NULL) { |
140 | 10.8k | next = pkts->Data + pkts->Size; |
141 | 10.8k | } |
142 | 6.17M | if (next < *pkt) { |
143 | | //wrong input |
144 | 1.87k | return -1; |
145 | 1.87k | } |
146 | | |
147 | 6.17M | memset(header, 0, sizeof(struct pcap_pkthdr)); |
148 | 6.17M | header->ts.tv_sec = *((time_t *) (pkts->Data + pkts->offset)); |
149 | 6.17M | if (header->ts.tv_sec < 0) { |
150 | 131k | header->ts.tv_sec = 0; |
151 | 131k | } |
152 | 6.17M | header->ts.tv_usec = *((suseconds_t *) (pkts->Data + pkts->offset + FPC_TS_MAXSIZE/2)); |
153 | 6.17M | header->caplen = next - (*pkt); |
154 | 6.17M | pkts->offset += header->caplen + FPC_TS_MAXSIZE + FPC0_MAGIC_LEN; |
155 | 6.17M | header->len = header->caplen; |
156 | 6.17M | return 1; |
157 | 6.17M | } |
158 | | |
159 | 390k | int FPC_next_tcp(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) { |
160 | 390k | *pkt = pkts->Data + pkts->offset; |
161 | 390k | const uint8_t *next = memmem(pkts->Data + pkts->offset, pkts->Size - pkts->offset, FPC0_MAGIC, FPC0_MAGIC_LEN); |
162 | 390k | if (next == NULL) { |
163 | 2.14k | next = pkts->Data + pkts->Size; |
164 | 2.14k | } |
165 | 390k | if (next < *pkt) { |
166 | | //wrong input |
167 | 0 | return -1; |
168 | 0 | } |
169 | | |
170 | 390k | memset(header, 0, sizeof(struct pcap_pkthdr)); |
171 | 390k | header->ts.tv_sec = FCP_BASE_TIME; |
172 | 390k | header->ts.tv_usec = pkts->nb; |
173 | 390k | pkts->nb++; |
174 | 390k | header->caplen = next - (*pkt); |
175 | | |
176 | 390k | if (pkts->tcpState > FPC_TCP_STATE_SYNACK) { |
177 | 384k | pkts->offset += header->caplen + FPC0_MAGIC_LEN; |
178 | 384k | } |
179 | 390k | switch (pkts->tcpState) { |
180 | 2.13k | case FPC_TCP_STATE_START: |
181 | 2.13k | pkts->tcpState = FPC_TCP_STATE_SYN; |
182 | 2.13k | header->caplen = buildTCPpacket(pkts, false, 0); |
183 | 2.13k | *pkt = pkts->pkt; |
184 | 2.13k | pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_SYN; |
185 | 2.13k | pkts->seqCliAckSrv++; |
186 | 2.13k | break; |
187 | | |
188 | 2.13k | case FPC_TCP_STATE_SYN: |
189 | 2.13k | pkts->tcpState = FPC_TCP_STATE_SYNACK; |
190 | 2.13k | header->caplen = buildTCPpacket(pkts, true, 0); |
191 | 2.13k | *pkt = pkts->pkt; |
192 | 2.13k | pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_SYN | FPC_TCP_FLAG_ACK; |
193 | 2.13k | pkts->seqSrvAckCli++; |
194 | 2.13k | break; |
195 | | |
196 | 2.13k | case FPC_TCP_STATE_SYNACK: |
197 | 2.13k | pkts->tcpState = FPC_TCP_STATE_ESTABLISHED; |
198 | 2.13k | header->caplen = buildTCPpacket(pkts, false, 0); |
199 | 2.13k | *pkt = pkts->pkt; |
200 | 2.13k | pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_ACK; |
201 | 2.13k | break; |
202 | | |
203 | 384k | case FPC_TCP_STATE_ESTABLISHED: |
204 | 384k | if (header->caplen < 1) { |
205 | 19 | return -1; |
206 | 19 | } |
207 | 384k | header->caplen--; |
208 | 384k | bool s2c = (*pkt[0]) & 1; |
209 | 384k | header->len = buildTCPpacket(pkts, s2c, header->caplen); |
210 | 384k | if (header->caplen + header->len > FPC_SNAPLEN) { |
211 | 11 | header->caplen = FPC_SNAPLEN - header->len; |
212 | 11 | } |
213 | 384k | memcpy(pkts->pkt+header->len, *pkt+1, header->caplen); |
214 | 384k | if (s2c) { |
215 | 217k | pkts->seqSrvAckCli += header->caplen; |
216 | 217k | } else { |
217 | 166k | pkts->seqCliAckSrv += header->caplen; |
218 | 166k | } |
219 | 384k | header->caplen += header->len; |
220 | 384k | *pkt = pkts->pkt; |
221 | 384k | break; |
222 | 390k | } |
223 | 390k | header->len = header->caplen; |
224 | 390k | return 1; |
225 | 390k | } |
226 | | |
227 | 6.57M | int FPC_next(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) { |
228 | 6.57M | if (pkts->offset >= pkts->Size) { |
229 | 12.8k | return 0; |
230 | 12.8k | } |
231 | | |
232 | 6.56M | if (pkts->tcpSingleStream) { |
233 | 390k | return FPC_next_tcp(pkts, header, pkt); |
234 | 390k | } //else |
235 | 6.17M | return FPC_next_pcap(pkts, header, pkt); |
236 | 6.56M | } |