Reupload after previous removal. - projectvoip - VoIP honeypot similar to ssh honeypot, using asterisk as the backend.
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
(DIR) commit 94772bd4e5c9fa0bb421346c9b8724a08706b972
(HTM) Author: Jay Scott <me@jay.scot>
Date: Wed, 5 May 2021 20:40:30 +0100
Reupload after previous removal.
Diffstat:
A README | 36 +++++++++++++++++++++++++++++++
A crontab | 3 +++
A extensions.conf | 24 ++++++++++++++++++++++++
A project-voip.rb | 242 +++++++++++++++++++++++++++++++
A sip.conf | 21 +++++++++++++++++++++
A voip.sql | 49 +++++++++++++++++++++++++++++++
6 files changed, 375 insertions(+), 0 deletions(-)
---
(DIR) diff --git a/README b/README
@@ -0,0 +1,36 @@
+
+ __ __ __ ___ __ ___ __ __
+|__) |__) / \ | |__ / ` | \ / / \ | |__)
+| | \ \__/ \__/ |___ \__, | \/ \__/ | |
+
+
+Project VOIP was meant to be a VOIP honeypot, but I haven't had much
+time to develop it, so I am uploading everything I have so far. Project
+VOIP is based on phorensix v1.0 by J. Oquendo / sil @ infiltrated dot
+net.
+
+Phorensix was scripted in bash and logged all information to a series of
+files. Project VOIP is coded in Ruby has been updated to work with the
+latest version of asterisk and also logs all information to a MySQL
+database.
+
+* Logs the following information to a mysql database:
+ * IP Address information
+ * Peer(s) AS Number
+ * Netblock AS Number
+ * Netblock Prefix
+ * AS Name
+ * AS Country
+ * AS Domain name
+ * ISP Name
+* Number called
+* SIP Agent
+* SIP channel used
+* Traceroute of the IP Address
+* Packet capture of the session (.cap file)
+* Recording of the call (.wav)
+
+usage:
+
+ $ apt-get install tshark rubygems mysql-client libmysqlclient-dev
+ $ gem install mysql
(DIR) diff --git a/crontab b/crontab
@@ -0,0 +1,3 @@
+# Dump the .cap and .wav every 18 mins - dirty hack
+
+*/18 * * * * /usr/bin/ruby -w /home/jay/project-voip.rb -d 1 2>&1
(DIR) diff --git a/extensions.conf b/extensions.conf
@@ -0,0 +1,24 @@
+[general]
+
+static=yes
+writeprotect=no
+clearglobalvars=yes
+autofallthrough=yes
+
+[project-voip]
+
+exten => _X.,1,Set(CTIME=${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)})
+exten => _X.,n,system(/usr/bin/ruby /home/jay/project-voip.rb -i ${SIPCHANINFO(peerip)} -w /opt/project-voip/wav/${CTIME}.wav -c ${CHANNEL} -e ${EXTEN} -u '${SIPCHANINFO(useragent)}' &)
+exten => _X.,n,Answer
+exten => _X.,n,Wait(1)
+exten => _X.,n,Playtones(ring)
+exten => _X.,n,Wait(5)
+exten => _X.,n,StopPlaytones
+exten => _X.,n,Playback(press-pound-to-login-star-to-hangup)
+exten => _X.,n,Record(/opt/project-voip/wav/${CTIME}:wav,,,qk)
+exten => _X.,n,Wait(1)
+exten => _X.,n,Hangup
+
+[default]
+
+include => project-voip
(DIR) diff --git a/project-voip.rb b/project-voip.rb
@@ -0,0 +1,242 @@
+#!/usr/bin/ruby
+
+=begin
+
+Project VOIP
+=============
+
+
+Project VOIP was meant to be a VOIP honeypot but I havent had much time to
+develop it so I am uploading everything I have so far here :-)
+
+Project VOIP is based on phorensix v.1 by J. Oquendo / sil @ infiltrated dot net.
+
+Phorensix was scripted in bash and logged all information to a series of files.
+Project VOIP is coded in Ruby has been updated to work with the latest version of
+asterisk and also logs all information to a MySQL database.
+
+Jay Scott <jay@jayscott.co.uk>
+
+
+What it does
+------------
+
+-> Logs the following information to a mysql database:
+ -> IP Address information
+ -> Peer(s) AS Number
+ -> Netblock AS Number
+ -> Netblock Prefix
+ -> AS Name
+ -> AS Country
+ -> AS Domain name
+ -> ISP Name
+ -> Number called
+ -> SIP Agent
+ -> SIP Channel used.
+ -> Traceroute of the IP Address
+ -> Packet capture of the session (.cap file)
+ -> Recording of the call (.wav)
+
+Installing
+----------
+
+Install Tshark and ruby gems if not installed already
+
+ - apt-get install tshark rubygems mysql-client libmysqlclient-dev
+
+Install the ruby gem files for mysql
+
+ gem install mysql
+
+Use the configs below as a template, changing the values as appropriate
+
+
+Make sure and update the Mysql information!.
+
+=end
+
+require 'rubygems'
+require 'optparse'
+require 'mysql'
+
+BASE_DATA = "/opt/project-voip/data"
+CRON_FILE = "/opt/project-voip/data/cron"
+MYSQL_HOST = ""
+MYSQL_USER = ""
+MYSQL_PASS = ""
+MYSQL_TABLE = ""
+HONEYPOT_ID = "1"
+
+options = {}
+
+op = OptionParser.new do|opts|
+
+ opts.banner = "Usage: ruby #{File.basename($0)} "
+ options[:ipaddress] = nil
+ options[:data] = nil
+ options[:useragent] = "Unknown"
+ options[:exten] = "Unknown"
+ options[:channel] = "Unknown"
+
+ opts.on( '-i', '--ipaddress [IPADDRESS]', 'IP Address' ) do|i|
+ options[:ipaddress] = i
+ end
+
+ opts.on( '-e', '--exten [EXTEN]', 'Phone number called ' ) do|e|
+ options[:exten] = e
+ end
+
+ opts.on( '-c', '--channel [CHANNEL]', 'Channel passed by Asterisk' ) do|c|
+ options[:channel] = c
+ end
+
+ opts.on( '-u', '--useragent [USERAGENT]', 'Callers user-agent' ) do|u|
+ options[:useragent] = u
+ end
+
+ opts.on( '-w', '--wav [WAV FILE]', 'WAV file location' ) do|w|
+ options[:wav] = w
+ end
+
+ opts.on( '-d', '--data', 'Upload Data Files to MySQL.' ) do
+ options[:data] = true
+ end
+
+ opts.on( '-h', '--help', 'Display this screen' ) do
+ puts opts
+ exit
+ end
+
+ opts.on("--version", "Show version") do
+ puts OptionParser::Version.join('.')
+ exit
+ end
+end
+
+op.parse!
+
+# Get the options passed
+ip_address = options[:ipaddress]
+data_update = options[:data]
+useragent = options[:useragent]
+called_exten = options[:exten]
+caller_channel = options[:channel]
+wav_file = options[:wav]
+
+# No IP.. somethings wrong, exit :p
+if !data_update.nil?
+
+ File.open("#{CRON_FILE}").each_line{ |s|
+ arrayData = s.split(':')
+ file_id = arrayData[0]
+ file_cap = arrayData[1].strip
+ file_wav = arrayData[2].strip
+
+ cf = File.new(file_cap, 'rb')
+ wf = File.new(file_wav, 'rb')
+
+ cap_data = Mysql.escape_string(cf.sysread(cf.stat.size))
+ wav_data = Mysql.escape_string(wf.sysread(wf.stat.size))
+
+ begin
+ con_info = Mysql.real_connect("#{MYSQL_HOST}", "#{MYSQL_USER}", "#{MYSQL_PASS}", "#{MYSQL_TABLE}")
+ rescue Mysql::Error => e
+ puts "Error code: #{e.errno}"
+ puts "Error message: #{e.error}"
+ puts "Error SQLSTATE: #{e.sqlstate}" if e.respond_to?("sqlstate")
+ end
+
+ con_info.query("UPDATE caller SET capture=\"#{cap_data}\", recording=\"#{wav_data}\" WHERE id='#{file_id}'")
+
+ con_info.close
+ }
+
+ puts "Updated"
+ File.delete("#{CRON_FILE}")
+ File.new("#{CRON_FILE}", "w")
+ exit(1)
+
+end
+
+# No IP.. somethings wrong, exit :p
+if ip_address.nil?
+ exit(-1)
+end
+
+# Set the dates we want
+date = Time.new
+current_date = date.strftime("%Y%m%d")
+current_time = date.strftime("%H%M%S")
+mysql_date = date.strftime("%H%M%S")
+
+cap_file = "#{BASE_DATA}/#{ip_address}-#{mysql_date}.cap"
+
+whois_info = Array.new
+whois_data = `whois -h whois.pwhois.org #{ip_address}`
+whois_info = whois_data.split("\n")
+
+# ip_address, origin_as, prefix, as_path, as_org_name, org_name, net_name, cache_date, lat, long, city, region, country
+whois_info = whois_info.map do |x|
+ x.split(':')[1].strip
+end
+
+traceroute_output = `traceroute -w 1 -m 25 -n #{ip_address} &`
+packet_capture = `tshark -q -R \"ip.addr == #{ip_address}\" -w #{cap_file} -a duration:20 &`
+
+# Connect to MySQL DB.
+begin
+ con_info = Mysql.real_connect("#{MYSQL_HOST}", "#{MYSQL_USER}", "#{MYSQL_PASS}", "#{MYSQL_TABLE}")
+rescue Mysql::Error => e
+ puts "Error code: #{e.errno}"
+ puts "Error message: #{e.error}"
+ puts "Error SQLSTATE: #{e.sqlstate}" if e.respond_to?("sqlstate")
+end
+
+rs_check = con_info.query("SELECT * from information WHERE ip_address='#{ip_address}'")
+
+# If the IP is unique then create a new record for it.
+if rs_check.num_rows == 0
+ con_info.query("INSERT INTO information
+ (ip_address, asn, prefix, as_path, as_org_name, org_name, net_name, lat, lon, city, region, country, traceroute)
+ VALUES
+ ('#{ip_address}', '#{whois_info[1]}', '#{whois_info[2]}', '#{whois_info[3]}', '#{whois_info[4]}', '#{whois_info[5]}', '#{whois_info[6]}', '#{whois_info[8]}', '#{whois_info[9]}', '#{whois_info[10]}', '#{whois_info[11]}', '#{whois_info[12]}', '#{traceroute_output}')")
+end
+
+d = DateTime.now
+
+# Insert the call information
+con_info.query("INSERT INTO caller
+ (uid, number, agent, channel, timestamp, honeypot)
+ VALUES
+ ('#{ip_address}','#{called_exten}','#{useragent}','#{caller_channel}', '#{d.to_s}', '#{HONEYPOT_ID}')")
+
+
+# This section dumps the wav and cap file information to a file to be read by
+# cron. We cant upload the wav and cap file at the same time because you dont
+# know if the call has finished so the wav and cap are still in progress.
+#
+# Asterisk cant reliably detect if a call has terminated, if it did we could
+# call function to kill tshark and then update the DB with the file data then.
+#
+# PROBLEM: The cron could run just after this information has been saved or not
+# finished processing and chop the data anyway
+#
+# meh.... need to ditch asterisk and just create my own sip server.
+
+# Get the ID of the record we just inserted.
+
+rs_id = con_info.query("SELECT MAX(id) AS MAXID FROM caller")
+
+while row = rs_id.fetch_row do
+ last_id = row[0]
+end
+
+con_info.close
+
+if !File::file?(CRON_FILE)
+ cronFile = File.new("#{CRON_FILE }", "w")
+end
+
+File.open("#{CRON_FILE}", "a") do |f|
+ f.puts "#{last_id}:#{cap_file}:#{wav_file}"
+end
(DIR) diff --git a/sip.conf b/sip.conf
@@ -0,0 +1,21 @@
+[general]
+context=project-voip ; Default context for incoming calls
+allowoverlap=no ; Disable overlap dialing support. (Default is yes)
+udpbindaddr=0.0.0.0 ; IP address to bind UDP listen socket to (0.0.0.0 binds to all)
+tcpenable=yes ; Enable server for incoming TCP connections (default is no)
+tcpbindaddr=0.0.0.0 ; IP address for TCP server to bind to (0.0.0.0 binds to all interfaces)
+srvlookup=yes ; Enable DNS SRV lookups on outbound calls
+alwaysauthreject=no
+allowguest=yes
+
+
+[100]
+username=100
+secret=100
+context=project-voip
+type=friend
+canreinvite=no
+host=dynamic
+qualify=1000
+mailbox=100
+allow=all
(DIR) diff --git a/voip.sql b/voip.sql
@@ -0,0 +1,49 @@
+
+
+DROP TABLE IF EXISTS `caller`;
+CREATE TABLE IF NOT EXISTS `caller` (
+ `id` int(15) NOT NULL AUTO_INCREMENT,
+ `uid` varchar(15) NOT NULL,
+ `number` varchar(100) DEFAULT NULL,
+ `agent` varchar(100) DEFAULT NULL,
+ `channel` varchar(100) DEFAULT NULL,
+ `capture` longblob NOT NULL,
+ `recording` longblob NOT NULL,
+ `timestamp` datetime NOT NULL,
+ `dumped` int(1) NOT NULL DEFAULT '0',
+ `honeypot` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `uid` (`uid`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+DROP TABLE IF EXISTS `information`;
+CREATE TABLE IF NOT EXISTS `information` (
+ `id` int(15) NOT NULL AUTO_INCREMENT,
+ `ip_address` varchar(15) NOT NULL,
+ `asn` varchar(100) DEFAULT NULL,
+ `as_path` varchar(100) DEFAULT NULL,
+ `prefix` varchar(100) DEFAULT NULL,
+ `as_org_name` varchar(100) DEFAULT NULL,
+ `org_name` varchar(100) DEFAULT NULL,
+ `country` varchar(100) DEFAULT NULL,
+ `net_name` varchar(100) DEFAULT NULL,
+ `lon` float(10,6) DEFAULT NULL,
+ `lat` float(10,6) DEFAULT NULL,
+ `city` varchar(100) DEFAULT NULL,
+ `region` varchar(100) DEFAULT NULL,
+ `traceroute` varchar(400) DEFAULT NULL,
+ `reported` int(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `ip_address` (`ip_address`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+DROP TABLE IF EXISTS `report`;
+CREATE TABLE IF NOT EXISTS `report` (
+ `id` int(15) NOT NULL AUTO_INCREMENT,
+ `uid` varchar(15) NOT NULL,
+ `email` varchar(200) DEFAULT NULL,
+ `last_contact` datetime DEFAULT NULL,
+ `total_contact` int(2) DEFAULT NULL,
+ `reply` text,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;