rcs-backdoor 8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +56 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +20 -0
- data/Rakefile +21 -0
- data/bin/binary.yaml +16 -0
- data/bin/config.yaml +2 -0
- data/bin/ident.yaml +12 -0
- data/bin/rcs-backdoor +16 -0
- data/bin/rcs-backdoor-add +115 -0
- data/bin/rcs-backdoor-multi +25 -0
- data/bin/trace.yaml +32 -0
- data/lib/rcs-backdoor.rb +2 -0
- data/lib/rcs-backdoor/backdoor.rb +326 -0
- data/lib/rcs-backdoor/command.rb +567 -0
- data/lib/rcs-backdoor/config.rb +42 -0
- data/lib/rcs-backdoor/protocol.rb +108 -0
- data/lib/rcs-backdoor/sync.rb +41 -0
- data/lib/rcs-backdoor/transport.rb +113 -0
- data/lib/rcs-backdoor/version.rb +5 -0
- data/rcs-backdoor.gemspec +28 -0
- metadata +182 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fcc4702d14c3b715b9804ba55c711ac85b1e4fe4
|
4
|
+
data.tar.gz: 80df4d159e0df208e1587b92d1aacfff9c84b3ed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dcac7da44c6ddbd0722ce434818284ea40183338d9d0c782a6eb974b4d10e5d52764052dd3a6b5cb1c9964a52b467ba624fed69228ceaf07a0ff30cd9f1be1be
|
7
|
+
data.tar.gz: 879003d4e72fd9a487bd4dfef841842b9a47e74ca7a5b9a4faa350c32a86bef99085a500ba41021b9dcdad218f799a6a8aefa10de01e9bccc0fcbb34bf785f3e
|
data/.gitignore
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
|
14
|
+
# jeweler generated
|
15
|
+
pkg
|
16
|
+
|
17
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
18
|
+
#
|
19
|
+
# * Create a file at ~/.gitignore
|
20
|
+
# * Include files you want ignored
|
21
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
22
|
+
#
|
23
|
+
# After doing this, these files will be ignored in all your git projects,
|
24
|
+
# saving you from having to 'pollute' every project you touch with them
|
25
|
+
#
|
26
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
27
|
+
#
|
28
|
+
# For MacOS:
|
29
|
+
#
|
30
|
+
.DS_Store
|
31
|
+
#
|
32
|
+
# For TextMate
|
33
|
+
#*.tmproj
|
34
|
+
#tmtags
|
35
|
+
#
|
36
|
+
# For emacs:
|
37
|
+
#*~
|
38
|
+
#\#*
|
39
|
+
#.\#*
|
40
|
+
#
|
41
|
+
# For vim:
|
42
|
+
*.swp
|
43
|
+
|
44
|
+
# For RubyMine
|
45
|
+
.idea
|
46
|
+
|
47
|
+
Gemfile.lock
|
48
|
+
|
49
|
+
#evidences
|
50
|
+
evidence
|
51
|
+
|
52
|
+
# RVM gemset
|
53
|
+
.ruby-gemset
|
54
|
+
|
55
|
+
*_config.dec
|
56
|
+
*_config.enc
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 ALoR
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
def execute(message)
|
4
|
+
print message + '...'
|
5
|
+
STDOUT.flush
|
6
|
+
if block_given? then
|
7
|
+
yield
|
8
|
+
end
|
9
|
+
puts ' ok'
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Housekeeping for the project"
|
13
|
+
task :clean do
|
14
|
+
execute "Cleaning the evidence directory" do
|
15
|
+
Dir['./evidences/*'].each do |f|
|
16
|
+
File.delete(f)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::Task["release"].clear
|
data/bin/binary.yaml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
---
|
2
|
+
default:
|
3
|
+
BACKDOOR_ID: ALoR0000000001
|
4
|
+
BACKDOOR_TYPE: OSX
|
5
|
+
CONF_KEY: -HcIbnSmrnaXFk6peeZJMx8HFcJPg9Hx
|
6
|
+
EVIDENCE_KEY: Ez2vdMwu6VNQxsSj2OmUhbOzoPwsgJTP
|
7
|
+
SIGNATURE: 4yeN5zu0+il3Jtcb5a1sBcAdjYFcsD9z
|
8
|
+
VERSION: 2013090401
|
9
|
+
|
10
|
+
minotauro:
|
11
|
+
BACKDOOR_ID: RCS_0000041952
|
12
|
+
BACKDOOR_TYPE: OSX
|
13
|
+
CONF_KEY: vzDkDLNyjGhs8_DHEZgz0i9RWK7dlHrw
|
14
|
+
EVIDENCE_KEY: 7bzcX8cccAXnpm27DxN84_NnNDHWX688
|
15
|
+
SIGNATURE: 7faa628b44f45e6e1cf1289b87eed01d
|
16
|
+
VERSION: 2013103101
|
data/bin/config.yaml
ADDED
data/bin/ident.yaml
ADDED
data/bin/rcs-backdoor
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
#begin
|
7
|
+
# Bundler.setup(:default, :development)
|
8
|
+
#rescue Bundler::BundlerError => e
|
9
|
+
# $stderr.puts e.message
|
10
|
+
# $stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
# exit e.status_code
|
12
|
+
#end
|
13
|
+
|
14
|
+
require 'rcs-backdoor'
|
15
|
+
|
16
|
+
exit RCS::Backdoor::Application.run!(*ARGV)
|
@@ -0,0 +1,115 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
require 'pry'
|
6
|
+
require 'json'
|
7
|
+
require 'moped'
|
8
|
+
require 'digest/sha1'
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
ARGV << "--help" if ARGV.empty?
|
12
|
+
|
13
|
+
$options = {db_addr: 'localhost'}
|
14
|
+
|
15
|
+
OptionParser.new do |parser|
|
16
|
+
parser.banner = "Add configuration entry for a new backdoor"
|
17
|
+
|
18
|
+
parser.on("-d", "--db ADDR", "Default is localhost. Specify db addr") do |addr|
|
19
|
+
$options[:db_addr] = addr
|
20
|
+
end
|
21
|
+
|
22
|
+
parser.on("-n", "--name FACTORY_NAME", "Specify the factory name") do |name|
|
23
|
+
$options[:factory_name] = name
|
24
|
+
end
|
25
|
+
end.parse!
|
26
|
+
|
27
|
+
def db_address
|
28
|
+
"#{db_host}:27017"
|
29
|
+
end
|
30
|
+
|
31
|
+
def db_host
|
32
|
+
$options[:db_addr]
|
33
|
+
end
|
34
|
+
|
35
|
+
def session
|
36
|
+
@session ||= begin
|
37
|
+
session = Moped::Session.new([db_address])
|
38
|
+
session.use('rcs')
|
39
|
+
session
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def can_reach_db?
|
44
|
+
session.collections.count rescue nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def factory_name
|
48
|
+
$options[:factory_name]
|
49
|
+
end
|
50
|
+
|
51
|
+
def factory
|
52
|
+
@factory ||= session['items'].find({_kind: 'factory', name: factory_name}).first
|
53
|
+
end
|
54
|
+
|
55
|
+
def signature
|
56
|
+
doc = session['signatures'].find(scope: 'agent').first
|
57
|
+
doc['value'].to_s if doc
|
58
|
+
end
|
59
|
+
|
60
|
+
def append_configuration(filename, hash)
|
61
|
+
path = File.expand_path("../#{filename}", __FILE__)
|
62
|
+
raise("Unable to find file #{path}") unless File.exists?(path)
|
63
|
+
raise("#{filename} already has an entry named #{entry_name.inspect}") if File.read(path) =~ /#{entry_name}/i
|
64
|
+
|
65
|
+
File.open(path, 'a') do |f|
|
66
|
+
f.write("\n")
|
67
|
+
f.write("#{entry_name}:\n")
|
68
|
+
hash.each { |key, value| f.write(" #{key}: #{value}\n") }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def entry_name
|
73
|
+
"fac_" << factory_name.to_s.downcase.gsub(/[^a-z0-9]/, '').strip
|
74
|
+
end
|
75
|
+
|
76
|
+
def update_binary_yaml
|
77
|
+
hash = {
|
78
|
+
:BACKDOOR_ID => factory['ident'],
|
79
|
+
:BACKDOOR_TYPE => 'OSX',
|
80
|
+
:CONF_KEY => factory['confkey'],
|
81
|
+
:EVIDENCE_KEY => factory['logkey'],
|
82
|
+
:SIGNATURE => signature,
|
83
|
+
:VERSION => 2013103101
|
84
|
+
}
|
85
|
+
|
86
|
+
append_configuration('binary.yaml', hash)
|
87
|
+
end
|
88
|
+
|
89
|
+
def instance_id
|
90
|
+
@instance_id ||= Digest::SHA1.hexdigest(rand(1E20).to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_ident_yaml
|
94
|
+
hash = {
|
95
|
+
:INSTANCE_ID => instance_id,
|
96
|
+
:USERID => "topac#{rand(1E5)}",
|
97
|
+
:DEVICEID => '',
|
98
|
+
:SOURCEID => '',
|
99
|
+
}
|
100
|
+
|
101
|
+
append_configuration("ident.yaml", hash)
|
102
|
+
end
|
103
|
+
|
104
|
+
raise "Unable to connect to database #{db_address.inspect}" unless can_reach_db?
|
105
|
+
raise "Unable to find factory name #{factory_name.inspect}" unless factory
|
106
|
+
raise "Unable to find agent signature in db #{db_address.inspect}" unless signature
|
107
|
+
|
108
|
+
update_binary_yaml
|
109
|
+
update_ident_yaml
|
110
|
+
|
111
|
+
puts "Configuration entry added to binary.yaml and ident.yaml"
|
112
|
+
cmd = "./bin/rcs-backdoor -s #{db_host} -c #{entry_name}"
|
113
|
+
puts "Try to sync with the command #{cmd} (the command has been copied on clipboard)"
|
114
|
+
|
115
|
+
exec("echo '#{cmd}' | pbcopy")
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
BINPATH = File.join(File.dirname(__FILE__), 'rcs-backdoor')
|
3
|
+
|
4
|
+
count = ARGV[0].to_i
|
5
|
+
|
6
|
+
exit(1) if count <= 0
|
7
|
+
|
8
|
+
args_for_backdoor = ARGV[1..-1].join(' ')
|
9
|
+
|
10
|
+
require 'colorize'
|
11
|
+
|
12
|
+
$threads = []
|
13
|
+
|
14
|
+
count.times do |i|
|
15
|
+
$threads << Thread.new do
|
16
|
+
puts "Thread #{i}: sleeping".colorize(:red)
|
17
|
+
sleep(rand(0..30))
|
18
|
+
|
19
|
+
cmd = "#{BINPATH} #{args_for_backdoor} --tag TAG#{i}"
|
20
|
+
puts "Thread #{i}: #{cmd}".colorize(:yellow)
|
21
|
+
system(cmd)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
$threads.map &:join
|
data/bin/trace.yaml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#
|
2
|
+
# Available name trace:
|
3
|
+
# :cookie - the cookie of the current session
|
4
|
+
# :host - the server for the sync
|
5
|
+
|
6
|
+
log4r_config:
|
7
|
+
pre_config:
|
8
|
+
global:
|
9
|
+
level: DEBUG
|
10
|
+
root :
|
11
|
+
level: DEBUG
|
12
|
+
|
13
|
+
loggers:
|
14
|
+
- name : rcslogger
|
15
|
+
level : DEBUG
|
16
|
+
additive : 'false'
|
17
|
+
trace : 'false'
|
18
|
+
outputters:
|
19
|
+
- stderr
|
20
|
+
|
21
|
+
|
22
|
+
outputters:
|
23
|
+
- type : StderrOutputter
|
24
|
+
name : stderr
|
25
|
+
level : DEBUG
|
26
|
+
formatter:
|
27
|
+
# take a look at this: http://log4r.rubyforge.org/rdoc/Log4r/PatternFormatter.html
|
28
|
+
date_pattern: '%Y-%m-%d %H:%M:%S'
|
29
|
+
pattern : '%d [%l]: %x %m'
|
30
|
+
type : PatternFormatter
|
31
|
+
|
32
|
+
|
data/lib/rcs-backdoor.rb
ADDED
@@ -0,0 +1,326 @@
|
|
1
|
+
#
|
2
|
+
# The main file of the backdoor
|
3
|
+
#
|
4
|
+
|
5
|
+
# relatives
|
6
|
+
require_relative 'sync.rb'
|
7
|
+
require_relative 'protocol.rb'
|
8
|
+
|
9
|
+
# from RCS::Common
|
10
|
+
require 'rcs-common/trace'
|
11
|
+
require 'rcs-common/crypt'
|
12
|
+
require 'rcs-common/evidence'
|
13
|
+
|
14
|
+
# from System
|
15
|
+
require 'digest/md5'
|
16
|
+
require 'digest/sha1'
|
17
|
+
require 'ostruct'
|
18
|
+
require 'yaml'
|
19
|
+
require 'optparse'
|
20
|
+
require 'fileutils'
|
21
|
+
|
22
|
+
module RCS
|
23
|
+
module Backdoor
|
24
|
+
#
|
25
|
+
# This is the Backdoor object
|
26
|
+
# it needs the backdoor_id, instance and conf_key to be created
|
27
|
+
# all those parameters need to be passed as string taken from the db
|
28
|
+
#
|
29
|
+
|
30
|
+
class Backdoor
|
31
|
+
include Tracer
|
32
|
+
|
33
|
+
attr_reader :id
|
34
|
+
attr_reader :instance
|
35
|
+
attr_reader :type
|
36
|
+
attr_reader :conf_key
|
37
|
+
attr_reader :evidence_key
|
38
|
+
attr_reader :signature
|
39
|
+
attr_reader :version
|
40
|
+
|
41
|
+
attr_reader :userid
|
42
|
+
attr_reader :deviceid
|
43
|
+
attr_reader :sourceid
|
44
|
+
|
45
|
+
attr_reader :evidences
|
46
|
+
|
47
|
+
attr_accessor :scout
|
48
|
+
attr_accessor :soldier
|
49
|
+
|
50
|
+
#setup all the backdoor parameters
|
51
|
+
def initialize(binary_file, ident_file, options = {})
|
52
|
+
@options = options
|
53
|
+
|
54
|
+
# parse the parameters from the binary patched constants
|
55
|
+
trace :debug, "Parsing binary data..."
|
56
|
+
binary = load_yaml(binary_file)
|
57
|
+
|
58
|
+
# instantiate le empty log queue
|
59
|
+
@evidences = []
|
60
|
+
|
61
|
+
# plain string 'RCS_000000000x'
|
62
|
+
@id = binary['BACKDOOR_ID']
|
63
|
+
|
64
|
+
# the subtype of the backdoor (eg: WIN32, BLACKBERRY...)
|
65
|
+
@type = binary['BACKDOOR_TYPE']
|
66
|
+
|
67
|
+
# the conf key is passed as a string taken from the db
|
68
|
+
# we need to calculate the MD5 and use it in binary form
|
69
|
+
@conf_key = Digest::MD5.digest binary['CONF_KEY']
|
70
|
+
|
71
|
+
# the log key is passed as a string taken from the db
|
72
|
+
# we need to calculate the MD5 and use it in binary form
|
73
|
+
@evidence_key = Digest::MD5.digest binary['EVIDENCE_KEY']
|
74
|
+
|
75
|
+
# the backdoor signature is passed as a string taken from the db
|
76
|
+
# we need to calculate the MD5 and use it in binary form
|
77
|
+
@signature = Digest::MD5.digest binary['SIGNATURE']
|
78
|
+
|
79
|
+
# the backdoor version
|
80
|
+
@version = binary['VERSION']
|
81
|
+
|
82
|
+
ident = load_yaml(ident_file)
|
83
|
+
ident['INSTANCE_ID'] = ident['INSTANCE_ID'][0..-((@options[:tag].size)+2)]+"_"+@options[:tag] if @options[:tag]
|
84
|
+
# the instance is passed as a string taken from the db
|
85
|
+
# we need to convert to binary
|
86
|
+
@instance = [ident['INSTANCE_ID']].pack('H*')
|
87
|
+
|
88
|
+
# directory where evidence files are be stored
|
89
|
+
@evidence_dir = File.join(Dir.pwd, 'evidence', ident['INSTANCE_ID'])
|
90
|
+
|
91
|
+
@userid = ident['USERID'] || ''
|
92
|
+
@deviceid = ident['DEVICEID'] || ''
|
93
|
+
@sourceid = ident['SOURCEID'] || ''
|
94
|
+
|
95
|
+
@info = { :device_id => @deviceid, :user_id => @userid, :source_id => @sourceid }
|
96
|
+
|
97
|
+
trace :debug, "Backdoor instantiated: " << @id << @instance.unpack('H*').to_s
|
98
|
+
trace :debug, "Backdoor ident: [#{@userid}] [#{@deviceid}] [#{@sourceid}]"
|
99
|
+
|
100
|
+
@scout = false
|
101
|
+
|
102
|
+
begin
|
103
|
+
# instantiate the sync object with the protocol to be used
|
104
|
+
# and a reference to the backdoor
|
105
|
+
@sync = Sync.new(:REST, self)
|
106
|
+
rescue Exception => detail
|
107
|
+
trace :fatal, "ERROR: " << detail.to_s
|
108
|
+
raise
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def load_yaml(path)
|
113
|
+
File.open(path, "r") do |f|
|
114
|
+
hash = YAML.load(f.read)
|
115
|
+
is_single_config = hash.keys.include?("INSTANCE_ID")
|
116
|
+
return hash if is_single_config
|
117
|
+
config_name = @options[:config_name] || "default"
|
118
|
+
hash[config_name] || raise("Unable to find configuration #{config_name.inspect} in file #{File.basename(path)}")
|
119
|
+
return hash[config_name]
|
120
|
+
end
|
121
|
+
rescue Exception => ex
|
122
|
+
trace :fatal, "Cannot load yaml file #{File.basename(path)}: #{ex.message}"
|
123
|
+
exit(1)
|
124
|
+
end
|
125
|
+
|
126
|
+
# perform the synchronization with the server
|
127
|
+
def sync(host, delete_evidence = true)
|
128
|
+
trace :debug, "Loading evidences in memory ..."
|
129
|
+
# retrieve the evidence from the local dir
|
130
|
+
Dir["#{@evidence_dir}/*"].each do |f|
|
131
|
+
@evidences << Evidence.new(@evidence_key).load_from_file(f)
|
132
|
+
end
|
133
|
+
|
134
|
+
trace :debug, "Synchronizing ..."
|
135
|
+
# perform the sync
|
136
|
+
@sync.perform host
|
137
|
+
|
138
|
+
if delete_evidence
|
139
|
+
trace :debug, "Deleting evidences ..."
|
140
|
+
# delete all evidence sent
|
141
|
+
Dir["#{@evidence_dir}/*"].each do |f|
|
142
|
+
File.delete(f)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
# create some evidences
|
149
|
+
def create_evidences(num, type = :RANDOM)
|
150
|
+
# ensure the directory is created
|
151
|
+
|
152
|
+
FileUtils.rm_rf(@evidence_dir)
|
153
|
+
|
154
|
+
FileUtils.mkpath(@evidence_dir) if not File.directory?(@evidence_dir)
|
155
|
+
|
156
|
+
real_type = type
|
157
|
+
|
158
|
+
# generate the evidence
|
159
|
+
num.times do
|
160
|
+
#real_type = RCS::EVIDENCE_TYPES.values.sample if type == :RANDOM
|
161
|
+
real_type = [:APPLICATION, :DEVICE, :CHAT, :CLIPBOARD, :CAMERA, :INFO, :KEYLOG, :SCREENSHOT, :MOUSE, :FILEOPEN, :FILECAP].sample if type == :RANDOM
|
162
|
+
Evidence.new(@evidence_key).generate(real_type, @info).dump_to_file(@evidence_dir)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# this module is used only form bin/rcs-backdoor as a wrapper to
|
168
|
+
# execute the backdoor from command line
|
169
|
+
class Application
|
170
|
+
include RCS::Tracer
|
171
|
+
|
172
|
+
def run_backdoor(path_to_binary, path_to_ident, options)
|
173
|
+
b = RCS::Backdoor::Backdoor.new(path_to_binary, path_to_ident, options)
|
174
|
+
|
175
|
+
# set the scout flag if specified
|
176
|
+
b.scout = true if options[:scout]
|
177
|
+
b.soldier = true if options[:soldier]
|
178
|
+
|
179
|
+
if options[:generate] then
|
180
|
+
trace :info, "Creating #{options[:gen_num]} fake evidences..."
|
181
|
+
b.create_evidences(options[:gen_num], options[:gen_type])
|
182
|
+
end
|
183
|
+
|
184
|
+
while true
|
185
|
+
if options[:sync] then
|
186
|
+
b.sync options[:sync_host], !(options[:randomize] or options[:loop]) # delete evidences if not randomizing
|
187
|
+
end
|
188
|
+
|
189
|
+
break unless options[:loop]
|
190
|
+
|
191
|
+
options[:loop_delay].times do |n|
|
192
|
+
sleep 1
|
193
|
+
trace :info, "#{options[:loop_delay] - n} seconds to next synchronization." if n % 5 == 0
|
194
|
+
end
|
195
|
+
end
|
196
|
+
rescue Interrupt
|
197
|
+
trace :info, "User asked to exit. Bye bye!"
|
198
|
+
return 0
|
199
|
+
rescue Exception => e
|
200
|
+
trace :fatal, "FAILURE: " << e.to_s
|
201
|
+
trace :fatal, "EXCEPTION: " + e.backtrace.join("\n")
|
202
|
+
return 1
|
203
|
+
end
|
204
|
+
|
205
|
+
def run(options)
|
206
|
+
|
207
|
+
# if we can't find the trace config file, default to the system one
|
208
|
+
if File.exist?('trace.yaml') then
|
209
|
+
load_path = Dir.pwd
|
210
|
+
trace_yaml = 'trace.yaml'
|
211
|
+
else
|
212
|
+
load_path = File.dirname(File.dirname(File.dirname(__FILE__))) + "/bin"
|
213
|
+
trace_yaml = load_path + "/trace.yaml"
|
214
|
+
puts "Cannot find 'trace.yaml' using the default one (#{trace_yaml})"
|
215
|
+
end
|
216
|
+
|
217
|
+
# initialize the tracing facility
|
218
|
+
begin
|
219
|
+
trace_init load_path, trace_yaml
|
220
|
+
rescue Exception => e
|
221
|
+
puts e
|
222
|
+
exit
|
223
|
+
end
|
224
|
+
|
225
|
+
unless options[:randomize].nil?
|
226
|
+
binary = begin
|
227
|
+
File.open(load_path + '/ident.yaml', "r") do |f|
|
228
|
+
binary = YAML.load(f.read)
|
229
|
+
end
|
230
|
+
rescue
|
231
|
+
trace :fatal, "Cannot open binary patched file"
|
232
|
+
exit
|
233
|
+
end
|
234
|
+
|
235
|
+
threads = []
|
236
|
+
options[:randomize].times do |n|
|
237
|
+
binary["INSTANCE_ID"] = Digest::SHA1.hexdigest(n.to_s).upcase
|
238
|
+
path_to_yaml = load_path + "/ident#{n}.yaml"
|
239
|
+
File.open(path_to_yaml, "w") {|f| f.write(binary.to_yaml)}
|
240
|
+
trace :info, "Spawned backdoor #{path_to_yaml}"
|
241
|
+
threads << Thread.new { run_backdoor(load_path + '/binary.yaml', path_to_yaml, options)}
|
242
|
+
end
|
243
|
+
|
244
|
+
begin
|
245
|
+
threads.each do |th|
|
246
|
+
th.join
|
247
|
+
end
|
248
|
+
rescue Interrupt
|
249
|
+
trace :info, "User asked to exit. Bye bye!"
|
250
|
+
return 0
|
251
|
+
end
|
252
|
+
|
253
|
+
else
|
254
|
+
run_backdoor(load_path + '/binary.yaml', load_path + '/ident.yaml', options)
|
255
|
+
end
|
256
|
+
|
257
|
+
# concluded successfully
|
258
|
+
return 0
|
259
|
+
end
|
260
|
+
|
261
|
+
# since we cannot use trace from a class method
|
262
|
+
# we instantiate here an object and run it
|
263
|
+
def self.run!(*argv)
|
264
|
+
# This hash will hold all of the options parsed from the command-line by OptionParser.
|
265
|
+
options = {}
|
266
|
+
|
267
|
+
srand(Time.now.to_i)
|
268
|
+
|
269
|
+
types = [:RANDOM] + RCS::EVIDENCE_TYPES.values
|
270
|
+
|
271
|
+
optparse = OptionParser.new do |opts|
|
272
|
+
# Set a banner, displayed at the top of the help screen.
|
273
|
+
opts.banner = "Usage: rcs-backdoor [options] arg1 arg2 ..."
|
274
|
+
|
275
|
+
# Define the options, and what they do
|
276
|
+
opts.on( '-r', '--randomize NUM', Integer, 'Randomize NUM instances') do |num|
|
277
|
+
options[:randomize] = num
|
278
|
+
end
|
279
|
+
opts.on( '-g', '--generate NUM', Integer, 'Generate NUM evidences' ) do |num|
|
280
|
+
options[:generate] = true
|
281
|
+
options[:gen_num] = num
|
282
|
+
end
|
283
|
+
opts.on( '-t', '--type TYPE', types, 'Generate evidences of type TYPE' ) do |type|
|
284
|
+
options[:gen_type] = type
|
285
|
+
end
|
286
|
+
opts.on( '-s', '--sync HOST', 'Synchronize with remote HOST' ) do |host|
|
287
|
+
options[:sync] = true
|
288
|
+
options[:sync_host] = host
|
289
|
+
end
|
290
|
+
opts.on('--tag STRING', 'Append to instance string' ) do |tag|
|
291
|
+
options[:tag] = tag
|
292
|
+
end
|
293
|
+
opts.on( '-l', '--loop DELAY', Integer, 'Loop synchronization every DELAY seconds') do |seconds|
|
294
|
+
options[:loop] = true
|
295
|
+
options[:loop_delay] = seconds
|
296
|
+
end
|
297
|
+
opts.on( '-c', '--config CONFIGURATION', String, 'Configuration/environment name') do |value|
|
298
|
+
options[:config_name] = value
|
299
|
+
end
|
300
|
+
opts.on( '--scout', 'Auth like a scout' ) do
|
301
|
+
options[:scout] = true
|
302
|
+
end
|
303
|
+
opts.on( '--soldier', 'Auth like a soldier' ) do
|
304
|
+
options[:soldiers] = true
|
305
|
+
end
|
306
|
+
|
307
|
+
# This displays the help screen, all programs are assumed to have this option.
|
308
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
309
|
+
puts opts
|
310
|
+
exit
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
optparse.parse(argv)
|
315
|
+
|
316
|
+
return Application.new.run(options)
|
317
|
+
end
|
318
|
+
|
319
|
+
end # Application::
|
320
|
+
|
321
|
+
end # Backdoor::
|
322
|
+
end # RCS::
|
323
|
+
|
324
|
+
if __FILE__ == $0
|
325
|
+
RCS::Backdoor::Application.run!(*ARGV)
|
326
|
+
end
|