1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2005-2013 Sourcefire, Inc.
4 // Copyright (C) 1998-2005 Martin Roesch <roesch@sourcefire.com>
5 //
6 // This program is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU General Public License Version 2 as published
8 // by the Free Software Foundation. You may not use, modify or distribute
9 // this program under any other version of the GNU General Public License.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 //--------------------------------------------------------------------------
20
21 /* bo
22 *
23 * Purpose: Detects Back Orifice traffic by brute forcing the weak encryption
24 * of the program's network protocol and detects the magic cookie
25 * that it's servers and clients require to communicate with each
26 * other.
27 *
28 * Effect: Analyzes UDP traffic for the BO magic cookie, reports if it finds
29 * traffic matching the profile.
30 *
31 */
32
33 /*
34 * The following text describes a couple of ways in which the Back Orifice
35 * signature is calculated. The snort runtime generated an array of 65K
36 * possible signatures, of which two are described here. Refer back to
37 * this simplified algorithm when evaluating the snort code below.
38 *
39 * Back Orifice magic cookie is "*!*QWTY?", which is located in the first
40 * eight bytes of the packet. But it is encrypted using an XOR. Here we'll
41 * generate a sequence of eight bytes which will decrypt (XOR) into the
42 * magic cookie. This test uses the NON-DEFAULT KEY to initialize (seed) the
43 * "random" number generator. The default seed results in the following
44 * sequence of bytes: E4 42 FB 83 41 B3 4A F0. When XOR'd against the
45 * magic cookie, we have our packet data which looks like a Back Orifice
46 * signature:
47 *
48 * Cookie: 2A 21 2A 51 57 54 59 3F
49 * Random: E4 42 FB 83 41 B3 4A F0
50 * ------- -- -- -- -- -- -- -- --
51 * Result: CE 63 D1 D2 16 E7 13 CF (XOR'd result)
52 *
53 * For demonstration purposes:
54 *
55 * static long holdrand = 1L;
56 * static int LocalBoRand()
57 * {
58 * return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
59 * }
60 * ...
61 *
62 * int BoRandValues_NonDefaultKey[8];
63 * holdrand = BO_DEFAULT_KEY; (seed value)
64 * BoRandValues_NonDefaultKey[0] = LocalBoRand() % 256; --> 228 (0xe4)
65 * BoRandValues_NonDefaultKey[1] = LocalBoRand() % 256; --> 66 (0x42)
66 * BoRandValues_NonDefaultKey[2] = LocalBoRand() % 256; --> 251 (0xfb)
67 * BoRandValues_NonDefaultKey[3] = LocalBoRand() % 256; --> 131 (0x83)
68 * BoRandValues_NonDefaultKey[4] = LocalBoRand() % 256; --> 65 (0x41)
69 * BoRandValues_NonDefaultKey[5] = LocalBoRand() % 256; --> 179 (0xb3)
70 * BoRandValues_NonDefaultKey[6] = LocalBoRand() % 256; --> 74 (0x4a)
71 * BoRandValues_NonDefaultKey[7] = LocalBoRand() % 256; --> 240 (0xf0)
72 *
73 *
74 * The following test uses the DEFAULT KEY to initialize (seed) the
75 * "random" number generator. The default seed results in the following
76 * sequence of bytes: 26 27 F6 85 97 15 AD 1D. When XOR'd against the
77 * magic cookie, we have our packet data which looks like a Back Orifice
78 * signature:
79 *
80 * Cookie: 2A 21 2A 51 57 54 59 3F
81 * Random: 26 27 F6 85 97 15 AD 1D
82 * ------- -- -- -- -- -- -- -- --
83 * Result: 0C 06 DC D4 C0 41 F4 22 (XOR'd result)
84 *
85 * For demonstration purposes:
86 *
87 * int BoRandValues_DefaultKey[8];
88 * holdrand = 0; (seed value)
89 * BoRandValues_DefaultKey[0] = LocalBoRand() % 256; --> 38 (0x26)
90 * BoRandValues_DefaultKey[1] = LocalBoRand() % 256; --> 39 (0x27)
91 * BoRandValues_DefaultKey[2] = LocalBoRand() % 256; --> 246 (0xf6)
92 * BoRandValues_DefaultKey[3] = LocalBoRand() % 256; --> 133 (0x85)
93 * BoRandValues_DefaultKey[4] = LocalBoRand() % 256; --> 151 (0x97)
94 * BoRandValues_DefaultKey[5] = LocalBoRand() % 256; --> 21 (0x15)
95 * BoRandValues_DefaultKey[6] = LocalBoRand() % 256; --> 173 (0xad)
96 * BoRandValues_DefaultKey[7] = LocalBoRand() % 256; --> 29 (0x1d)
97 *
98 * Notes:
99 *
100 * 10/13/2005 marc norton - This has a lot of changes to the runtime
101 * decoding and testing. The '% 256' op was removed,
102 * the xor op is bit wise so modulo is not needed,
103 * the char casting truncates to one byte,
104 * and len testing has been modified as was the xor decode copy and
105 * final PONG test.
106 */
107
108 #ifdef HAVE_CONFIG_H
109 #include "config.h"
110 #endif
111
112 #include "detection/detection_engine.h"
113 #include "events/event_queue.h"
114 #include "framework/inspector.h"
115 #include "framework/module.h"
116 #include "log/messages.h"
117 #include "profiler/profiler.h"
118 #include "protocols/packet.h"
119
120 #define BO_DEFAULT_KEY 31337
121 #define BO_MAGIC_SIZE 8
122 #define BO_MIN_SIZE 18
123 #define BO_DEFAULT_PORT 31337
124
125 #define BO_TYPE_PING 1
126 #define BO_FROM_UNKNOWN 0
127 #define BO_FROM_CLIENT 1
128 #define BO_FROM_SERVER 2
129
130 #define BO_BUF_SIZE 8
131 #define BO_BUF_ATTACK_SIZE 1024
132
133 #define s_name "back_orifice"
134
135 #define s_help \
136 "back orifice detection"
137
138 using namespace snort;
139
140 /* global keyvalue for the BoRand() function */
141 static THREAD_LOCAL uint64_t holdrand = 1;
142
143 // these are const during runtime
144 static uint16_t lookup1[65536][3];
145 static uint16_t lookup2[65536];
146
147 static THREAD_LOCAL ProfileStats boPerfStats;
148 static THREAD_LOCAL SimpleStats bostats;
149
150 //-------------------------------------------------------------------------
151 // bo module
152 //-------------------------------------------------------------------------
153
154 #define GID_BO 105
155
156 #define BO_TRAFFIC_DETECT 1
157 #define BO_CLIENT_TRAFFIC_DETECT 2
158 #define BO_SERVER_TRAFFIC_DETECT 3
159 #define BO_SNORT_BUFFER_ATTACK 4
160
161 #define BO_TRAFFIC_DETECT_STR \
162 "Back orifice traffic detected, unknown direction"
163 #define BO_CLIENT_TRAFFIC_DETECT_STR \
164 "Back orifice client traffic detected"
165 #define BO_SERVER_TRAFFIC_DETECT_STR \
166 "Back orifice server traffic detected"
167 #define BO_SNORT_BUFFER_ATTACK_STR \
168 "Back orifice length field >= 1024 bytes"
169
170 static const RuleMap bo_rules[] =
171 {
172 { BO_TRAFFIC_DETECT, BO_TRAFFIC_DETECT_STR },
173 { BO_CLIENT_TRAFFIC_DETECT, BO_CLIENT_TRAFFIC_DETECT_STR },
174 { BO_SERVER_TRAFFIC_DETECT, BO_SERVER_TRAFFIC_DETECT_STR },
175 { BO_SNORT_BUFFER_ATTACK, BO_SNORT_BUFFER_ATTACK_STR },
176
177 { 0, nullptr }
178 };
179
180 class BoModule : public Module
181 {
182 public:
BoModule()183 BoModule() : Module(s_name, s_help)
184 { }
185
get_rules() const186 const RuleMap* get_rules() const override
187 { return bo_rules; }
188
get_gid() const189 unsigned get_gid() const override
190 { return GID_BO; }
191
192 const PegInfo* get_pegs() const override;
193 PegCount* get_counts() const override;
194 ProfileStats* get_profile() const override;
195
get_usage() const196 Usage get_usage() const override
197 { return INSPECT; }
198
is_bindable() const199 bool is_bindable() const override
200 { return true; }
201 };
202
get_pegs() const203 const PegInfo* BoModule::get_pegs() const
204 { return simple_pegs; }
205
get_counts() const206 PegCount* BoModule::get_counts() const
207 { return (PegCount*)&bostats; }
208
get_profile() const209 ProfileStats* BoModule::get_profile() const
210 { return &boPerfStats; }
211
212 //-------------------------------------------------------------------------
213 // bo implementation
214 //-------------------------------------------------------------------------
215
216 /*
217 * Function: BoRand()
218 *
219 * Purpose: Back Orifice "encryption" algorithm
220 *
221 * Arguments: None.
222 *
223 * Returns: key to XOR with current char to be "encrypted"
224 */
BoRand()225 static char BoRand()
226 {
227 holdrand = holdrand * 214013 + 2531011;
228 return (char)((holdrand >> 16) & 0xFF);
229 }
230
231 /*
232 * Precalculate the known cyphertext into a prefix and suffix lookup table
233 * to recover the key. Using this in the bo_eval() function below is much
234 * faster than the old brute force method
235 */
PrecalcPrefix()236 static void PrecalcPrefix()
237 {
238 uint8_t cookie_cyphertext[BO_MAGIC_SIZE];
239 const char* cookie_plaintext = "*!*QWTY?";
240
241 memset(lookup1, 0, sizeof(lookup1));
242 memset(lookup2, 0, sizeof(lookup2));
243
244 for (int key=0; key<65536; key++)
245 {
246 /* setup to generate cyphertext for this key */
247 holdrand = key;
248 const char* cp_ptr = cookie_plaintext;
249
250 /* convert the plaintext cookie to cyphertext for this key */
251 for (int cookie_index=0; cookie_index<BO_MAGIC_SIZE; cookie_index++)
252 {
253 cookie_cyphertext[cookie_index] =(uint8_t)(*cp_ptr^(BoRand()));
254 cp_ptr++;
255 }
256
257 /*
258 * generate the key lookup mechanism from the first 2 characters of
259 * the cyphertext
260 */
261 uint16_t cyphertext_referent;
262 cyphertext_referent = (uint16_t)(cookie_cyphertext[0] << 8) & 0xFF00;
263 cyphertext_referent |= (uint16_t)(cookie_cyphertext[1]) & 0x00FF;
264
265 /* if there are any keyspace collisions that's going to suck */
266 if (lookup1[cyphertext_referent][0] != 0)
267 {
268 if (lookup1[cyphertext_referent][1] != 0)
269 {
270 lookup1[cyphertext_referent][2] = (uint16_t)key;
271 }
272 else
273 {
274 lookup1[cyphertext_referent][1] = (uint16_t)key;
275 }
276 }
277 else
278 {
279 lookup1[cyphertext_referent][0] = (uint16_t)key;
280 }
281
282 /*
283 * generate the second lookup from the last two characters of
284 * the cyphertext
285 */
286 cyphertext_referent = (uint16_t)(cookie_cyphertext[6] << 8) & 0xFF00;
287 cyphertext_referent |= (uint16_t)(cookie_cyphertext[7]) & 0x00FF;
288
289 /*
290 * set the second lookup with the current key
291 */
292 lookup2[key] = cyphertext_referent;
293 }
294 }
295
296 /*
297 * Purpose: Attempt to guess the direction this packet is going in.
298 *
299 * Arguments: p => pointer to the current packet data struct
300 * pkt_data => pointer to data after magic cookie
301 *
302 * Returns: BO_FROM_UNKNOWN if direction unknown
303 * BO_FROM_CLIENT if direction from client to server
304 * BO_FROM_SERVER if direction from server to client
305 *
306 * Reference: http://www.magnux.org/~flaviovs/boproto.html
307 * BO header structure:
308 * Mnemonic Size in bytes
309 * -------------------------
310 * MAGIC 8
311 * LEN 4
312 * ID 4
313 * T 1
314 * DATA variable
315 * CRC 1
316 *
317 */
BoGetDirection(Packet * p,const char * pkt_data)318 static int BoGetDirection(Packet* p, const char* pkt_data)
319 {
320 uint32_t len = 0;
321 uint32_t id = 0;
322 uint32_t l, i;
323 char type;
324 char plaintext;
325
326 /* Check for the default port on either side */
327 if ( p->ptrs.dp == BO_DEFAULT_PORT )
328 {
329 return BO_FROM_CLIENT;
330 }
331 else if ( p->ptrs.sp == BO_DEFAULT_PORT )
332 {
333 return BO_FROM_SERVER;
334 }
335
336 /* Didn't find default port, so look for ping packet */
337
338 /* Get length from BO header - 32 bit int */
339 for ( i = 0; i < 4; i++ )
340 {
341 plaintext = (char)(*pkt_data ^ BoRand());
342 l = (uint32_t)plaintext;
343 len += l << (8*i);
344 pkt_data++;
345 }
346
347 /* Get ID from BO header - 32 bit int */
348 for ( i = 0; i < 4; i++ )
349 {
350 plaintext = (char)(*pkt_data ^ BoRand() );
351 l = ((uint32_t)plaintext) & 0x000000FF;
352 id += l << (8*i);
353 pkt_data++;
354 }
355
356 /* Do more len checking */
357
358 if ( len >= BO_BUF_ATTACK_SIZE )
359 {
360 DetectionEngine::queue_event(GID_BO, BO_SNORT_BUFFER_ATTACK);
361 return BO_FROM_UNKNOWN;
362 }
363
364 /* Adjust for BO packet header length */
365 if (len <= BO_MIN_SIZE)
366 {
367 /* Need some data, or we can't figure out client or server */
368 return BO_FROM_UNKNOWN;
369 }
370 else
371 {
372 len -= BO_MIN_SIZE;
373 }
374
375 if ( len > 7 )
376 {
377 len = 7; /* we need no more than 7 variable chars */
378 }
379
380 /* Continue parsing BO header */
381 type = (char)(*pkt_data ^ BoRand());
382 pkt_data++;
383
384 /* check to make sure we don't run off end of packet */
385 if ((uint32_t)(p->dsize - ((const uint8_t*)pkt_data - p->data)) < len)
386 {
387 /* We don't have enough data to inspect */
388 return BO_FROM_UNKNOWN;
389 }
390
391 /* Extract type of BO packet */
392 type = type & 0x3F;
393
394 /* Only examine data if this is a ping request or response */
395 if ( type == BO_TYPE_PING )
396 {
397 if ( len < 7 )
398 {
399 return BO_FROM_CLIENT;
400 }
401 char buf1[BO_BUF_SIZE];
402
403 for (i=0; i<len; i++ ) /* start at 0 to advance the BoRand() function properly */
404 {
405 buf1[i] = (char)(pkt_data[i] ^ BoRand());
406
407 if ( buf1[i] == 0 )
408 return BO_FROM_UNKNOWN;
409 }
410
411 if ( ( buf1[3] == 'P' || buf1[3] == 'p' ) &&
412 ( buf1[4] == 'O' || buf1[4] == 'o' ) &&
413 ( buf1[5] == 'N' || buf1[5] == 'n' ) &&
414 ( buf1[6] == 'G' || buf1[6] == 'g' ) )
415 {
416 return BO_FROM_SERVER;
417 }
418 else
419 {
420 return BO_FROM_CLIENT;
421 }
422 }
423
424 return BO_FROM_UNKNOWN;
425 }
426
427 //-------------------------------------------------------------------------
428 // class stuff
429 //-------------------------------------------------------------------------
430
431 class BackOrifice : public Inspector
432 {
433 public:
434 BackOrifice() = default;
435
436 void eval(Packet*) override;
437 };
438
eval(Packet * p)439 void BackOrifice::eval(Packet* p)
440 {
441 Profile profile(boPerfStats);
442
443 const char* const magic_cookie = "*!*QWTY?";
444
445 // preconditions - what we registered for
446 assert(p->is_udp());
447
448 // make sure it's at least 19 bytes long
449 if (p->dsize < BO_MIN_SIZE)
450 return;
451
452 ++bostats.total_packets;
453
454 // take the first two characters of the packet and generate the
455 // first reference that gives us a reference key
456 uint16_t cyphertext_referent = (uint16_t)(p->data[0] << 8) & 0xFF00;
457 cyphertext_referent |= (uint16_t)(p->data[1]) & 0x00FF;
458
459 // generate the second referent from the last two characters
460 // of the cyphertext
461 uint16_t cyphertext_suffix = (uint16_t)(p->data[6] << 8) & 0xFF00;
462 cyphertext_suffix |= (uint16_t)(p->data[7]) & 0x00FF;
463
464 for ( int i = 0; i < 3; ++i )
465 {
466 // get the key from the cyphertext
467 uint16_t key = lookup1[cyphertext_referent][i];
468
469 // if the lookup from the proposed key matches the cyphertext reference
470 // then we've probably go the right key and can proceed to full
471 // decryption using the key
472 // moral of the story: don't use a lame keyspace
473 if ( lookup2[key] == cyphertext_suffix )
474 {
475 auto pkt_data = reinterpret_cast<const char*>(p->data);
476 auto end = pkt_data + BO_MAGIC_SIZE;
477 const char* magic_data = magic_cookie;
478
479 holdrand = key;
480
481 while ( pkt_data < end )
482 {
483 char plaintext = *pkt_data ^ BoRand();
484
485 if ( *magic_data != plaintext )
486 return;
487
488 ++magic_data;
489 ++pkt_data;
490 }
491
492 // if we fall thru there's a detect
493 int bo_direction = BoGetDirection(p, pkt_data);
494 if ( bo_direction == BO_FROM_CLIENT )
495 DetectionEngine::queue_event(GID_BO, BO_CLIENT_TRAFFIC_DETECT);
496 else if ( bo_direction == BO_FROM_SERVER )
497 DetectionEngine::queue_event(GID_BO, BO_SERVER_TRAFFIC_DETECT);
498 else
499 DetectionEngine::queue_event(GID_BO, BO_TRAFFIC_DETECT);
500 }
501 }
502 }
503
504 //-------------------------------------------------------------------------
505 // api stuff
506 //-------------------------------------------------------------------------
507
mod_ctor()508 static Module* mod_ctor()
509 { return new BoModule; }
510
mod_dtor(Module * m)511 static void mod_dtor(Module* m)
512 { delete m; }
513
bo_init()514 static void bo_init()
515 {
516 PrecalcPrefix();
517 }
518
bo_ctor(Module *)519 static Inspector* bo_ctor(Module*)
520 {
521 return new BackOrifice;
522 }
523
bo_dtor(Inspector * p)524 static void bo_dtor(Inspector* p)
525 {
526 delete p;
527 }
528
529 static const InspectApi bo_api =
530 {
531 {
532 PT_INSPECTOR,
533 sizeof(InspectApi),
534 INSAPI_VERSION,
535 0,
536 API_RESERVED,
537 API_OPTIONS,
538 s_name,
539 s_help,
540 mod_ctor,
541 mod_dtor
542 },
543 IT_NETWORK,
544 PROTO_BIT__UDP,
545 nullptr, // buffers
546 nullptr, // service
547 bo_init,
548 nullptr, // pterm
549 nullptr, // tinit
550 nullptr, // tterm
551 bo_ctor,
552 bo_dtor,
553 nullptr, // ssn
554 nullptr // reset
555 };
556
557 #ifdef BUILDING_SO
558 SO_PUBLIC const BaseApi* snort_plugins[] =
559 {
560 &bo_api.base,
561 nullptr
562 };
563 #else
564 const BaseApi* sin_bo = &bo_api.base;
565 #endif
566
567