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