00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 //
00004 // This program is free software; you can redistribute it and/or modify it
00005 // under the terms of the GNU General Public License Version 2 as published
00006 // by the Free Software Foundation. You may not use, modify or distribute
00007 // this program under any other version of the GNU General Public License.
00008 //
00009 // This program is distributed in the hope that it will be useful, but
00010 // WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program; if not, write to the Free Software Foundation, Inc.,
00016 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 //--------------------------------------------------------------------------
00018 // wizard.cc author Russ Combs <rucombs@cisco.com>
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include "config.h"
00022 #endif
00023
00024 #include "host_tracker/host_cache.h"
00025 #include "flow/flow.h"
00026 #include "log/messages.h"
00027 #include "profiler/profiler.h"
00028 #include "protocols/packet.h"
00029 #include "stream/stream_splitter.h"
00030
00031 #include "main/snort_debug.h"
00032
00033 #include "curses.h"
00034 #include "magic.h"
00035 #include "wiz_module.h"
00036
00037 using namespace std;
00038
00039 THREAD_LOCAL ProfileStats wizPerfStats;
00040
00041 struct WizStats
00042 {
00043 PegCount tcp_scans;
00044 PegCount tcp_hits;
00045 PegCount udp_scans;
00046 PegCount udp_hits;
00047 PegCount user_scans;
00048 PegCount user_hits;
00049 };
00050
00051 const PegInfo wiz_pegs[] =
00052 {
00053 { CountType::SUM, "tcp_scans", "tcp payload scans" },
00054 { CountType::SUM, "tcp_hits", "tcp identifications" },
00055 { CountType::SUM, "udp_scans", "udp payload scans" },
00056 { CountType::SUM, "udp_hits", "udp identifications" },
00057 { CountType::SUM, "user_scans", "user payload scans" },
00058 { CountType::SUM, "user_hits", "user identifications" },
00059 { CountType::END, nullptr, nullptr }
00060 };
00061
00062 THREAD_LOCAL WizStats tstats;
00063
00064 //-------------------------------------------------------------------------
00065 // configuration
00066 //-------------------------------------------------------------------------
00067
00068 struct CurseServiceTracker
00069 {
00070 const CurseDetails* curse;
00071 CurseTracker* tracker;
00072 };
00073
00074 struct Wand
00075 {
00076 const MagicPage* hex;
00077 const MagicPage* spell;
00078 vector<CurseServiceTracker> curse_tracker;
00079 };
00080
00081 class Wizard;
00082
00083 class MagicSplitter : public StreamSplitter
00084 {
00085 public:
00086 MagicSplitter(bool, class Wizard*);
00087 ~MagicSplitter() override;
00088
00089 Status scan(Flow*, const uint8_t* data, uint32_t len,
00090 uint32_t flags, uint32_t* fp) override;
00091
00092 bool is_paf() override { return true; }
00093
00094 private:
00095 Wizard* wizard;
00096 Wand wand;
00097 };
00098
00099 class Wizard : public Inspector
00100 {
00101 public:
00102 Wizard(WizardModule*);
00103 ~Wizard() override;
00104
00105 void show(SnortConfig*) override
00106 { LogMessage("Wizard\n"); }
00107
00108 void eval(Packet*) override;
00109
00110 StreamSplitter* get_splitter(bool) override;
00111
00112 void reset(Wand&, bool tcp, bool c2s);
00113 bool cast_spell(Wand&, Flow*, const uint8_t*, unsigned);
00114 bool spellbind(const MagicPage*&, Flow*, const uint8_t*, unsigned);
00115 bool cursebind(vector<CurseServiceTracker>&, Flow*, const uint8_t*, unsigned);
00116
00117 public:
00118 MagicBook* c2s_hexes;
00119 MagicBook* s2c_hexes;
00120
00121 MagicBook* c2s_spells;
00122 MagicBook* s2c_spells;
00123
00124 CurseBook* curses;
00125 };
00126
00127 //-------------------------------------------------------------------------
00128 // splitter - this doesn't actually split the stream but it applies
00129 // basic magic type logic to determine the appropriate inspector that
00130 // will split the stream.
00131 //-------------------------------------------------------------------------
00132
00133 MagicSplitter::MagicSplitter(bool c2s, class Wizard* w) :
00134 StreamSplitter(c2s)
00135 {
00136 wizard = w;
00137 w->add_ref();
00138 w->reset(wand, true, c2s);
00139 }
00140
00141 MagicSplitter::~MagicSplitter()
00142 {
00143 wizard->rem_ref();
00144
00145 // release trackers
00146 for (unsigned i=0; i<wand.curse_tracker.size(); i++)
00147 delete wand.curse_tracker[i].tracker;
00148 }
00149
00150 // FIXIT-M stop search on hit and failure (no possible match)
00151 StreamSplitter::Status MagicSplitter::scan(
00152 Flow* f, const uint8_t* data, uint32_t len,
00153 uint32_t, uint32_t*)
00154 {
00155 ++tstats.tcp_scans;
00156
00157 if ( wizard->cast_spell(wand, f, data, len) )
00158 ++tstats.tcp_hits;
00159
00160 return SEARCH;
00161 }
00162
00163 //-------------------------------------------------------------------------
00164 // class stuff
00165 //-------------------------------------------------------------------------
00166
00167 Wizard::Wizard(WizardModule* m)
00168 {
00169 c2s_hexes = m->get_book(true, true);
00170 s2c_hexes = m->get_book(false, true);
00171
00172 c2s_spells = m->get_book(true, false);
00173 s2c_spells = m->get_book(false, false);
00174
00175 curses = m->get_curse_book();
00176 }
00177
00178 Wizard::~Wizard()
00179 {
00180 delete c2s_hexes;
00181 delete s2c_hexes;
00182
00183 delete c2s_spells;
00184 delete s2c_spells;
00185
00186 delete curses;
00187 }
00188
00189 void Wizard::reset(Wand& w, bool tcp, bool c2s)
00190 {
00191 if ( c2s )
00192 {
00193 w.hex = c2s_hexes->page1();
00194 w.spell = c2s_spells->page1();
00195 }
00196 else
00197 {
00198 w.hex = s2c_hexes->page1();
00199 w.spell = s2c_spells->page1();
00200 }
00201
00202 if (w.curse_tracker.empty())
00203 {
00204 vector<const CurseDetails*> pages = curses->get_curses(tcp);
00205 for ( const CurseDetails* curse : pages )
00206 {
00207 if (tcp)
00208 w.curse_tracker.push_back({ curse, new CurseTracker });
00209 else
00210 w.curse_tracker.push_back({ curse, nullptr });
00211 }
00212 }
00213 }
00214
00215 void Wizard::eval(Packet* p)
00216 {
00217 if ( !p->is_udp() )
00218 return;
00219
00220 if ( !p->data || !p->dsize )
00221 return;
00222
00223 Wand wand;
00224 reset(wand, false, p->is_from_client());
00225
00226 new_invoked_inspector(30, p, 0);
00227
00228 if ( cast_spell(wand, p->flow, p->data, p->dsize) )
00229 ++tstats.udp_hits;
00230
00231 ++tstats.udp_scans;
00232 }
00233
00234 StreamSplitter* Wizard::get_splitter(bool c2s)
00235 {
00236 return new MagicSplitter(c2s, this);
00237 }
00238
00239 bool Wizard::spellbind(
00240 const MagicPage*& m, Flow* f, const uint8_t* data, unsigned len)
00241 {
00242 f->service = m->book.find_spell(data, len, m);
00243
00244 if (f->service != nullptr)
00245 {
00246 // FIXIT-H need to make sure Flow's ipproto and service
00247 // correspond to HostApplicationEntry's ipproto and service
00248 host_cache_add_service(f->server_ip, f->ip_proto, f->server_port, f->service);
00249 return true;
00250 }
00251
00252 return false;
00253 }
00254
00255 bool Wizard::cursebind(vector<CurseServiceTracker>& curse_tracker, Flow* f,
00256 const uint8_t* data, unsigned len)
00257 {
00258 for (const CurseServiceTracker& cst : curse_tracker)
00259 {
00260 if (cst.curse->alg(data, len, cst.tracker))
00261 {
00262 f->service = cst.curse->service.c_str();
00263 // FIXIT-H need to make sure Flow's ipproto and service
00264 // correspond to HostApplicationEntry's ipproto and service
00265 host_cache_add_service(f->server_ip, f->ip_proto, f->server_port, f->service);
00266 return true;
00267 }
00268 }
00269
00270 return false;
00271 }
00272
00273 bool Wizard::cast_spell(
00274 Wand& w, Flow* f, const uint8_t* data, unsigned len)
00275 {
00276 if ( w.hex && spellbind(w.hex, f, data, len) )
00277 return true;
00278
00279 if ( w.spell && spellbind(w.spell, f, data, len) )
00280 return true;
00281
00282 if (cursebind(w.curse_tracker, f, data, len))
00283 return true;
00284
00285 return false;
00286 }
00287
00288 //-------------------------------------------------------------------------
00289 // api stuff
00290 //-------------------------------------------------------------------------
00291
00292 static Module* mod_ctor()
00293 { return new WizardModule; }
00294
00295 static void mod_dtor(Module* m)
00296 { delete m; }
00297
00298 static Inspector* wiz_ctor(Module* m)
00299 {
00300 WizardModule* mod = (WizardModule*)m;
00301 assert(mod);
00302 return new Wizard(mod);
00303 }
00304
00305 static void wiz_dtor(Inspector* p)
00306 {
00307 delete p;
00308 }
00309
00310 static const InspectApi wiz_api =
00311 {
00312 {
00313 PT_INSPECTOR,
00314 sizeof(InspectApi),
00315 INSAPI_VERSION,
00316 0,
00317 API_RESERVED,
00318 API_OPTIONS,
00319 WIZ_NAME,
00320 WIZ_HELP,
00321 mod_ctor,
00322 mod_dtor
00323 },
00324 IT_WIZARD,
00325 (uint16_t)PktType::TCP | (uint16_t)PktType::UDP | (uint16_t)PktType::PDU,
00326 nullptr, // buffers
00327 nullptr, // service
00328 nullptr, // init
00329 nullptr, // term
00330 nullptr, // tinit
00331 nullptr, // tterm
00332 wiz_ctor,
00333 wiz_dtor,
00334 nullptr, // ssn
00335 nullptr // reset
00336 };
00337
00338 #ifdef BUILDING_SO
00339 SO_PUBLIC const BaseApi* snort_plugins[] =
00340 {
00341 &wiz_api.base,
00342 nullptr
00343 };
00344 #else
00345 const BaseApi* sin_wizard = &wiz_api.base;
00346 #endif
00347
END OF CODE