URI: 
       overhaul of the analysis view, addition of a type filter - warvox - VoIP based wardialing tool, forked from rapid7/warvox.
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
   DIR commit 953ea21a9aeace23a66b41311f6cb5e21c01137d
   DIR parent 72d086e74af1fc956e851c7a27e000685c52c17a
  HTML Author: HD Moore <hd_moore@rapid7.com>
       Date:   Tue, 26 May 2009 02:36:04 +0000
       
       overhaul of the analysis view, addition of a type filter
       
       
       Diffstat:
         M bin/warvox.agi                      |       3 ++-
         M docs/ChangeLog                      |       7 +++++++
         M etc/sigs/01.default.rb              |      25 -------------------------
         M etc/sigs/99.default.rb              |      20 ++++++++++++++++++--
         M lib/warvox.rb                       |       2 +-
         M web/app/controllers/analyze_contro… |      82 ++++++++++++++++++++++++++++---
         M web/app/controllers/dial_jobs_cont… |       5 +++++
         M web/app/helpers/application_helper… |      16 ++++++++++++++++
         M web/app/views/analyze/index.html.e… |       7 ++++---
         A web/app/views/analyze/show.html.erb |       9 +++++++++
         M web/app/views/analyze/view.html.erb |      44 ++++++++++++++++---------------
         M web/app/views/dial_results/index.h… |       2 +-
         M web/config/routes.rb                |       2 +-
       
       13 files changed, 161 insertions(+), 63 deletions(-)
       ---
   DIR diff --git a/bin/warvox.agi b/bin/warvox.agi
       @@ -4,7 +4,8 @@
        # This script can be used to redial an existing job through Asterix.
        # To use this script, add an entry to extensions.conf:
        #
       -# exten => _777.,1,agi,warvox.agi|/warvox/data/20
       +# exten => _777.,1,Answer()
       +# exten => _777.,2,agi,warvox.agi|/warvox/data/20
        #
        
        base = ARGV.shift
   DIR diff --git a/docs/ChangeLog b/docs/ChangeLog
       @@ -1,3 +1,10 @@
       +2009-05-25  H D Moore  <hdm[at]metasploit.com>
       + * switched MP3 quality to 32kbps from 8kpbs for better listening
       + * added bin/warvox.agi as an asterisk plugin to allow job re-dialing
       + * overhaul of the signature system (etc/sigs/*.rb)
       + * filter analysis results by line type
       + * overhaul of results view + show signatures
       +
        2009-05-10  H D Moore  <hdm[at]metasploit.com>
         
         * release of version 1.0.1
   DIR diff --git a/etc/sigs/01.default.rb b/etc/sigs/01.default.rb
       @@ -19,14 +19,6 @@ fcnt = data[:fcnt]
        maxf = data[:maxf]
        
        #
       -# Look for silence by checking the frequency signature
       -#
       -if(freq.map{|f| f.length}.inject(:+) == 0)
       -        @line_type = 'silence'
       -        break
       -end
       -
       -#
        # Look for silence by checking for a strong frequency in each sample
        #
        scnt = 0
       @@ -42,10 +34,6 @@ freq.each do |fsec|
                savg = sump / fsec.length
                ecnt += 1 if (savg < 100)
        end
       -if(ecnt == scnt)
       -        @line_type = 'silence'
       -        break
       -end
        
        # Store these into data for use later on
        data[:scnt] = scnt
       @@ -98,19 +86,6 @@ if(fcnt[440] > 1.0 and fcnt[350] > 1.0)
                break
        end
        
       -
       -#
       -# Look for voice mail by detecting the 1000hz BEEP
       -# If the call length was too short to catch the beep,
       -# this signature can fail. For non-US numbers, the beep
       -# is often a different frequency entirely.
       -#
       -if(fcnt[1000] >= 1.0)
       -        @line_type = 'voicemail'
       -        break                                
       -end
       -
       -
        #
        # To use additional signatures, add new scripts to this directory
        # named XX.myscript.rb, where XX is a two digit number less than
   DIR diff --git a/etc/sigs/99.default.rb b/etc/sigs/99.default.rb
       @@ -9,6 +9,9 @@
        freq = data[:freq]
        fcnt = data[:fcnt]
        maxf = data[:maxf]
       +ecnt = data[:ecnt]
       +scnt = data[:scnt]
       +
        
        # Look for voice mail by detecting the 1000hz BEEP
        # If the call length was too short to catch the beep,
       @@ -16,7 +19,7 @@ maxf = data[:maxf]
        # is often a different frequency entirely.
        if(fcnt[1000] >= 1.0)
                @line_type = 'voicemail'
       -        break                                
       +        break                
        end
        
        # Look for voicemail by detecting a peak frequency of
       @@ -24,7 +27,20 @@ end
        # the fallback script.
        if(maxf > 995 and maxf < 1005)
                @line_type = 'voicemail'
       -        break        
       +        break
       +end
       +
       +#
       +# Look for silence by checking the frequency signature
       +#
       +if(freq.map{|f| f.length}.inject(:+) == 0)
       +        @line_type = 'silence'
       +        break
       +end
       +
       +if(ecnt == scnt)
       +        @line_type = 'silence'
       +        break
        end
        
        #
   DIR diff --git a/lib/warvox.rb b/lib/warvox.rb
       @@ -11,7 +11,7 @@ require 'warvox/db'
        
        # Global configuration
        module WarVOX
       -        VERSION = '1.0.1'
       +        VERSION = '1.0.2'
                Base = File.expand_path(File.join(File.dirname(__FILE__), '..'))
                Conf = File.expand_path(File.join(Base, 'etc', 'warvox.conf'))
                JobManager = WarVOX::JobQueue.new
   DIR diff --git a/web/app/controllers/analyze_controller.rb b/web/app/controllers/analyze_controller.rb
       @@ -11,16 +11,56 @@ class AnalyzeController < ApplicationController
          end
        
          def view
       -          @job_id = params[:id]
       -        @results = DialResult.paginate_all_by_dial_job_id(
       -                @job_id,
       -                :page => params[:page], 
       -                :order => 'number ASC',
       -                :per_page => 10,
       -                :conditions => [ 'completed = ? and processed = ? and busy = ?', true, true, false ]
       -        )
       +          @job_id   = params[:id]
       +          @dial_job = DialJob.find(@job_id)
       +        @shown    = params[:show]
       +        
       +        @g1 = Ezgraphix::Graphic.new(:c_type => 'col3d', :div_name => 'calls_pie1')
       +        @g1.render_options(:caption => 'Detected Lines by Type', :y_name => 'Lines', :w => 700, :h => 300)
        
       +        ltypes = DialResult.find( :all, :select => 'DISTINCT line_type', :conditions => ["dial_job_id = ?", @job_id] ).map{|r| r.line_type}
       +        res_types = {}
        
       +        ltypes.each do |k|
       +                next if not k
       +                res_types[k.capitalize.to_sym] = DialResult.count(
       +                        :conditions => ['dial_job_id = ? and line_type = ?', @job_id, k]
       +                )
       +        end
       +        
       +        @g1.data = res_types
       +
       +        if(@shown and @shown != 'all')
       +                @results = DialResult.paginate_all_by_dial_job_id(
       +                        @job_id,
       +                        :page => params[:page], 
       +                        :order => 'number ASC',
       +                        :per_page => 10,
       +                        :conditions => [ 'completed = ? and processed = ? and busy = ? and line_type = ?', true, true, false, @shown ]
       +                )        
       +        else
       +                @results = DialResult.paginate_all_by_dial_job_id(
       +                        @job_id,
       +                        :page => params[:page], 
       +                        :order => 'number ASC',
       +                        :per_page => 10,
       +                        :conditions => [ 'completed = ? and processed = ? and busy = ?', true, true, false ]
       +                )
       +        end
       +        
       +        @filters = []
       +        @filters << { :scope => "all", :label => "All" }
       +        res_types.keys.each do |t|
       +                @filters << { :scope => t.to_s.downcase, :label => t.to_s }
       +        end
       +                
       +  end
       +
       + def show
       +          @job_id   = params[:id]
       +          @dial_job = DialJob.find(@job_id)
       +        @shown    = params[:show]
       +        
                @g1 = Ezgraphix::Graphic.new(:c_type => 'col3d', :div_name => 'calls_pie1')
                @g1.render_options(:caption => 'Detected Lines by Type', :y_name => 'Lines', :w => 700, :h => 300)
        
       @@ -35,8 +75,34 @@ class AnalyzeController < ApplicationController
                end
                
                @g1.data = res_types
       +
       +        if(@shown and @shown != 'all')
       +                @results = DialResult.paginate_all_by_dial_job_id(
       +                        @job_id,
       +                        :page => params[:page], 
       +                        :order => 'number ASC',
       +                        :per_page => 10,
       +                        :conditions => [ 'completed = ? and processed = ? and busy = ? and line_type = ?', true, true, false, @shown ]
       +                )        
       +        else
       +                @results = DialResult.paginate_all_by_dial_job_id(
       +                        @job_id,
       +                        :page => params[:page], 
       +                        :order => 'number ASC',
       +                        :per_page => 10,
       +                        :conditions => [ 'completed = ? and processed = ? and busy = ?', true, true, false ]
       +                )
       +        end
       +        
       +        @filters = []
       +        @filters << { :scope => "all", :label => "All" }
       +        res_types.keys.each do |t|
       +                @filters << { :scope => t.to_s.downcase, :label => t.to_s }
       +        end
       +                
          end
        
       +
          # GET /dial_results/1/resource?id=XXX&type=YYY
          def resource
                  ctype = 'text/html'
   DIR diff --git a/web/app/controllers/dial_jobs_controller.rb b/web/app/controllers/dial_jobs_controller.rb
       @@ -23,10 +23,13 @@ class DialJobsController < ApplicationController
            end
          end
        
       +=begin
          # GET /dial_jobs/1/edit
          def edit
            @dial_job = DialJob.find(params[:id])
          end
       +=end
       +  
        
          # GET /dial_jobs/1/run
          def run
       @@ -118,6 +121,7 @@ class DialJobsController < ApplicationController
            
          # PUT /dial_jobs/1
          # PUT /dial_jobs/1.xml
       +=begin  
          def update
            @dial_job = DialJob.find(params[:id])
            respond_to do |format|
       @@ -131,5 +135,6 @@ class DialJobsController < ApplicationController
              end
            end
          end
       +=end  
          
        end
   DIR diff --git a/web/app/helpers/application_helper.rb b/web/app/helpers/application_helper.rb
       @@ -49,4 +49,20 @@ module ApplicationHelper
                        end
                        html << "\n</ul></div>\n"
                end
       +        
       +        def select_tag_for_filter(nvpairs, params)
       +          _url = ( url_for :overwrite_params => { }).split('?')[0]
       +          _html = %{<label for="show">Filter: </label>}
       +          _html << %{<select name="show" id="show"}
       +          _html << %{onchange="window.location='#{_url}' + '?show=' + this.value">}
       +          nvpairs.each do |pair|
       +            _html << %{<option value="#{pair[:scope]}"}
       +            if params[:show] == pair[:scope] || ((params[:show].nil? || params[:show].empty?) && pair[:scope] == "all")
       +              _html << %{ selected="selected"}
       +            end
       +            _html << %{>#{pair[:label]}}
       +            _html << %{</option>}
       +          end
       +          _html << %{</select>}
       +        end        
        end
   DIR diff --git a/web/app/views/analyze/index.html.erb b/web/app/views/analyze/index.html.erb
       @@ -21,9 +21,10 @@
                        "/" + 
                        DialResult.count(:conditions => ['dial_job_id = ?', dial_job.id]).to_s 
                )%></td>
       -    <td><%=h dial_job.started_at.localtime.strftime("%Y-%m-%d %H:%M:%S %Z") %></td>
       -    <td><%= link_to 'View', view_analyze_path(dial_job) %></td>
       -        <td><%= link_to 'ReAnalyze', reanalyze_dial_result_path(dial_job), :confirm => 'Process this job again?' %></td>
       +    <td><%=h dial_job.started_at.localtime.strftime("%Y-%m-%d %H:%M:%S") %></td>
       +    <!-- <td><%= link_to 'Overview', show_analyze_path(dial_job) %></td> -->
       +    <td><%= link_to 'Browse', view_analyze_path(dial_job) %></td>
       +        <td><%= link_to 'ReAnalyze', reanalyze_dial_result_path(@dial_job), :confirm => 'Process this job again?' %></td>
          </tr>
        <% end %>
        </table>
   DIR diff --git a/web/app/views/analyze/show.html.erb b/web/app/views/analyze/show.html.erb
       @@ -0,0 +1,9 @@
       +<h1 class='title'>Overview of Job ID <%= @job_id %></h1>
       +
       +<table width='100%' align='center' border=0 cellspacing=0 cellpadding=6>
       +<tr>
       +        <td align='center'><%= render_ezgraphix @g1 %></td>
       +</tr>
       +</table>
       +
       +        
   DIR diff --git a/web/app/views/analyze/view.html.erb b/web/app/views/analyze/view.html.erb
       @@ -1,5 +1,7 @@
        <h1 class='title'>Analysis of Job ID <%= @job_id %></h1>
        
       +<%= select_tag_for_filter(@filters, params) %>
       +
        <table width='100%' align='center' border=0 cellspacing=0 cellpadding=6>
        <tr>
                <td align='center'><%= render_ezgraphix @g1 %></td>
       @@ -10,44 +12,44 @@
        
        <table class='table_scaffold' width='100%'>
          <tr>
       -    <th>ID</th>  
            <th>Number</th>
       -    <th>Type</th>
                  <th>Signal</th>
       -        <th>Spectrum</th>
       -    <th>CID</th>
       -    <th>Provider</th>
       -    <th>Time</th>
       -        <th>Ring</th>
          </tr>
        
        <%  @results.each do |dial_result| %>
          <tr>
       -    <td><%=h dial_result.id %></td>
       -        <td>
       -                <b><%= dial_result.number %></b><br/>
       +    <td align='center'>
       +        
                        <object
                                type="application/x-shockwave-flash"
                                data="/images/musicplayer.swf?song_url=<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/mp3" 
                                width="20"
                                height="17"
       +                        style="margin-bottom: -5px;"
                                >
                                <param name="movie" value="/musicplayer.swf?song_url=<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/mp3"></param>
                                <param name="wmode" value="transparent"></param>
       -                </object>         
       +                </object>
       +                <b><%= dial_result.number %></b>
       +                <hr width='100%' size='1'/>
       +                CallerID: <%= dial_result.cid%><br/>
       +                Provider: <%=h dial_result.provider.name %><br/>
       +                Audio: <%=h dial_result.seconds %> Seconds<br/>
       +                Ringer: <%=h dial_result.ringtime %> Seconds
       +                                        
                </td>
       -    <td><%=h dial_result.line_type.upcase %></td>        
       -          <td>
       +          <td align='center'>
       +                <b><%=h dial_result.line_type.upcase %></b><br/>
                        <a href="<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/big_sig_dots" rel="lightbox"><img src="<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/small_sig" /></a>
       +                <a href="<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/big_freq" rel="lightbox"><img src="<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/small_freq" /></a><br/>
       +                <% (dial_result.signatures||"").split("\n").each do |s| 
       +                        sid,mat,name = s.split(':', 3)
       +                        str = [mat.to_i * 6.4, 255].min
       +                        col = ("%.2x" % (255 - str)) * 3
       +                %>
       +                        <div style="color: #<%= col%>;"><%=h name%> (<%=h sid %>@<%=h mat %>)</div>
       +                <% end %>                        
                </td>
       -        <td>
       -                <a href="<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/big_freq" rel="lightbox"><img src="<%=resource_analyze_path(@job_id)%>/<%= dial_result.id %>/small_freq" /></a>
       -        </td>
       -
       -    <td><%=h dial_result.cid %></td>        
       -    <td><%=h dial_result.provider.name %></td>
       -    <td><%=h dial_result.seconds %></td>
       -    <td><%=h dial_result.ringtime %></td>
          </tr>
        <% end %>
        </table>
   DIR diff --git a/web/app/views/dial_results/index.html.erb b/web/app/views/dial_results/index.html.erb
       @@ -20,7 +20,7 @@
                        "/" + 
                        DialResult.count(:conditions => ['dial_job_id = ?', dial_job.id]).to_s 
                )%></td>
       -    <td><%=h dial_job.started_at.localtime.strftime("%Y-%m-%d %H:%M:%S %Z") %></td>
       +    <td><%=h dial_job.started_at.localtime.strftime("%Y-%m-%d %H:%M:%S") %></td>
            <td><%= link_to 'View', view_dial_result_path(dial_job) %></td>
                <% if(dial_job.processed) %>
                        <td><%= link_to 'View Analysis', analyze_dial_result_path(dial_job) %></td>
   DIR diff --git a/web/config/routes.rb b/web/config/routes.rb
       @@ -3,7 +3,7 @@ ActionController::Routing::Routes.draw do |map|
        
          map.resources :dial_jobs, :has_many => [ :dial_results ], :member => { :run => :get, :stop => :get }
        
       -  map.resources :analyze, :member => { :view => :get, :resource => :get }
       +  map.resources :analyze, :member => { :view => :get, :resource => :get, :show => :get }
          map.connect   'analyze/:id/resource/:result_id/:type', :controller => 'analyze', :action => 'resource'