aspisec 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0774d430a48a87fa3e42c12c3128539d47ad0fd801e0f72d60f6e0bed0d748c7
4
+ data.tar.gz: 00323257ec5e60891045f4be245854334cb66848ef2232ceb894aefe35cb717c
5
+ SHA512:
6
+ metadata.gz: 74d2860157892606ce4113612e489cccece2eeaa138e825cf4be93f8c16f3182e18db4276f2bc6ce420e215c9d36b46bb3cbf9dc86f0ca557c2145795658707e
7
+ data.tar.gz: 64eb61bb34d63920da20059bb040da0890959726bdc407038191036d6d901a224538e7097ccd30e82aae8a33ec262dc26f4536a25699c9a452587e084fc6eaba
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Alexandre ZANNI at ACCEIS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/bin-ruby/aspisec ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Ruby internal
5
+ # Project internal
6
+ require 'aspisec'
7
+ # External
8
+ require 'docopt'
9
+ require 'pastel'
10
+
11
+ paint = Pastel.new(eachline: "\n")
12
+
13
+ doc = <<~DOCOPT
14
+ #{paint.decorate('AspiSec', :red)} v#{paint.decorate(Aspisec::VERSION, :bold)}
15
+
16
+ #{paint.decorate('Usage:', :red)}
17
+ aspisec [options] clean
18
+ aspisec [options] list
19
+ aspisec -h | --help
20
+ aspisec --version
21
+
22
+ #{paint.decorate('Commands:', :red)}
23
+ clean Removes the traces left by offensive security tools
24
+ list List available modules, locations and their status
25
+
26
+ #{paint.decorate('Options:', :red)}
27
+ --debug Display arguments
28
+ -v, --verbose <level> Set verbosity level (see documentation) [default: 2]
29
+ -h, --help Show this screen
30
+ --version Show version
31
+
32
+ #{paint.decorate('Examples:', :red)}
33
+ aspisec clean
34
+
35
+ #{paint.decorate('Project:', :red)}
36
+ #{paint.decorate('source', :underline)} (https://github.com/acceis/aspisec)
37
+ #{paint.decorate('documentation', :underline)} (https://acceis.github.io/aspisec)
38
+ DOCOPT
39
+
40
+ begin
41
+ args = Docopt.docopt(doc, version: Aspisec::VERSION)
42
+ puts args if args['--debug']
43
+ log_level = 2
44
+ log_level = args['--verbose'].to_i if args['--verbose']
45
+ if args['clean']
46
+ logger = Aspisec::Logger.new(log_level).logger
47
+ conf = Aspisec::Config.new(logger).conf
48
+ cl = Aspisec::Clean.new(conf:, logger:)
49
+ cl.clean
50
+ elsif args['list']
51
+ Aspisec::Modules.modules.each do |mod|
52
+ enabled = mod.enabled? ? '✅' : '❌'
53
+ print "#{enabled} "
54
+ puts paint.decorate(mod.name, :red, :on_black)
55
+ mod.locations.each do |loc|
56
+ enabled = loc.enabled? ? '✅' : '❌'
57
+ print " #{enabled} "
58
+ puts paint.decorate(loc.name, :white, :on_black)
59
+ end
60
+ end
61
+ end
62
+ rescue Docopt::Exit => e
63
+ puts e.message
64
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pastel'
4
+ require 'tty-prompt'
5
+
6
+ # ActiveSupport minimal load (we only use number_to_human_size)
7
+ require 'active_support'
8
+ require 'active_support/core_ext/numeric/conversions'
9
+
10
+ module Aspisec
11
+ # Manage the cleaning operations
12
+ class Clean
13
+ # @param conf [Aspisec::Config] an instance of the global configuration
14
+ # If none is provided, the default config is loaded.
15
+ # @param logger [TTY::Logger] logger instance. See {Aspisec::Logger}.
16
+ # If none is provided, a default logger with log level 2 is created.
17
+ # See {Aspisec::Logger::LOG_LEVEL}.
18
+ def initialize(conf: nil, logger: nil)
19
+ @logger = logger || Aspisec::Logger.new.logger
20
+ @conf = conf || Aspisec::Config.new(@logger).conf
21
+ @modules = Aspisec::Modules.modules(conf:, logger:).select(&:enabled?)
22
+ @autoclean = @conf.dig('aspisec', 'autoclean').fetch('enabled', false)
23
+ @describe = @conf.dig('aspisec', 'describe').fetch('enabled', true)
24
+ @prompt = TTY::Prompt.new
25
+ @painter = Pastel.new(eachline: "\n")
26
+ end
27
+
28
+ # Display location (file or directory) information and prompt user for deletion
29
+ # It will follow the configuration wether it has to display the description or not.
30
+ # @param location [Aspisec::Module::Location]
31
+ # @return [true|false]
32
+ def prompt_removal(location:)
33
+ puts "——— #{@painter.decorate(location.name, :cyan, :bold)} ———"
34
+ puts_decorated('Path', location.path.to_s)
35
+ puts_decorated('Type', file_type(location.path))
36
+ puts_decorated('Size', type_size(location.path))
37
+ puts_decorated('Description', location.description) if @describe
38
+ @prompt.yes?("Do you want to remove #{location.name}?")
39
+ end
40
+
41
+ # Display decorated key/value
42
+ # @param key [String]
43
+ # @param value [String]
44
+ # @return [nil]
45
+ def puts_decorated(key, value)
46
+ puts @painter.decorate("#{key}: ", :bright_blue, :bold) + value
47
+ end
48
+
49
+ # Type of file
50
+ # @param path [Pathname]
51
+ # @return [String] `file`, `directory` or `other`
52
+ def file_type(path)
53
+ if path.file?
54
+ 'file'
55
+ elsif path.directory?
56
+ 'directory'
57
+ else
58
+ 'other'
59
+ end
60
+ end
61
+
62
+ # Formats number as bytes into a human-friendly representation.
63
+ # @param size [Integer] file size in bytes
64
+ # @return [String] human-friendly size with the most suitable unit
65
+ # @see https://api.rubyonrails.org/classes/ActiveSupport/NumberHelper.html#method-i-number_to_human_size
66
+ def human_size(size)
67
+ ActiveSupport::NumberHelper.number_to_human_size(size)
68
+ end
69
+
70
+ # Calculate directory size (size of all files stored in it).
71
+ # It will be the real size of files not the size on disk.
72
+ # It ignores anything else than files so it could be wrong for symlinks, mounts, etc.
73
+ # It also don't take into consideration the size of the directory itself.
74
+ # @param path [Pathname]
75
+ # @return [Integer] size in bytes
76
+ def directory_size(path)
77
+ Dir[File.join(path, '**', '*')].select { |f| File.file?(f) }.sum { |f| File.size(f) }
78
+ end
79
+
80
+ # Displays the size (in human-friendly format with {human_size}) regardless of whether it is a file or a directory.
81
+ # @param path [Pathname]
82
+ # @return [String] human-friendly size with the most suitable unit, or `empty` is the size is zero
83
+ def type_size(path)
84
+ size = if path.directory?
85
+ directory_size(path)
86
+ else
87
+ path.size
88
+ end
89
+ size.zero? ? 'empty' : human_size(size)
90
+ end
91
+
92
+ # Delete the location regardless of whether it is a file or a directory.
93
+ # @param path [Pathname]
94
+ # @return [nil]
95
+ def type_delete(path)
96
+ if path.directory?
97
+ path.rmtree
98
+ else
99
+ path.delete
100
+ end
101
+ nil
102
+ end
103
+
104
+ # Handles and logs deletion of locations
105
+ # @param path [Pathname]
106
+ # @return [nil]
107
+ def delete_location(path)
108
+ type_delete(path)
109
+ @logger.info("#{path} was removed")
110
+ nil
111
+ end
112
+
113
+ # Handles the deletion mode. It could be automatic or manual cleaning.
114
+ # @param loc [Aspisec::Module::Location]
115
+ def delete_mode(loc)
116
+ return unless loc.enabled? && loc.path.exist?
117
+
118
+ if @autoclean
119
+ delete_location(loc.path)
120
+ else
121
+ manual_delete(loc)
122
+ end
123
+ end
124
+
125
+ # Handles the manual deletion mode.
126
+ # @param loc [Aspisec::Module::Location]
127
+ def manual_delete(loc)
128
+ remove = prompt_removal(location: loc)
129
+ if remove
130
+ delete_location(loc.path)
131
+ else
132
+ @logger.debug("#{loc.path} was left untouched")
133
+ end
134
+ end
135
+
136
+ # Main method, handling the cleaning.
137
+ # Only enabled modules and locations will be removed.
138
+ # Works either with auto-cleaning or ask for manual confirmation.
139
+ # @return [nil]
140
+ def clean
141
+ @modules.each do |mod|
142
+ next unless mod.enabled?
143
+
144
+ puts "━━━━━━━━━━━━ #{@painter.decorate(mod.name, :white, :bold, :on_blue)} ━━━━━━━━━━━━"
145
+ mod.locations.each do |loc|
146
+ delete_mode(loc)
147
+ end
148
+ end
149
+ nil
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,323 @@
1
+ # frozen_string_literal: true
2
+
3
+ # stdlib
4
+ require 'yaml'
5
+ # third-party
6
+ require 'xdg'
7
+ require 'tty-logger'
8
+
9
+ module Aspisec
10
+ # Managing the configuration file (location, creation, parsing)
11
+ class Config
12
+ CONFIG_FILENAME = 'aspisec.config.yaml'
13
+ DEFAULT_CONFIG = {
14
+ 'aspisec' => {
15
+ # Auto clean, remove files without asking confirmation
16
+ 'autoclean' => {
17
+ 'enabled' => false
18
+ },
19
+ # Display the description of each location to explain what the file /
20
+ # directory is storing
21
+ 'describe' => {
22
+ 'enabled' => true
23
+ }
24
+ },
25
+ 'tools' => {
26
+ # Example of a tool configuration
27
+ 'example' => {
28
+ # Putting this value to false allow to disable the check for this module only
29
+ 'enabled' => false,
30
+ 'location' => {
31
+ # The base location where the tool stores the confidential stuff to clean
32
+ # $XDG_DATA_HOME is evaluated with a XDG library so even if the environment
33
+ # variable doesn't exist it will be replaced with the default standard value
34
+ 'base' => '$XDG_DATA_HOME/tools/ex',
35
+ 'logs' => {
36
+ # Path to the confidential file n°1
37
+ # <base> will be replaced by location.base value
38
+ 'path' => '<base>/output',
39
+ # Each file check can be individually turned off rather than disabling the whole module
40
+ 'enaled' => false,
41
+ # The description explain which client-related data is stored there and how it is sensitive.
42
+ # It generally says if it's a file or directory.
43
+ 'description' => 'The directory containing log files. Logs contain IP addresses and hostnames.'
44
+ }
45
+ }
46
+ },
47
+ 'sqlmap' => {
48
+ 'enabled' => true,
49
+ 'location' => {
50
+ 'base' => '$XDG_DATA_HOME/sqlmap', # ~/.local/share/sqlmap
51
+ 'history' => {
52
+ 'path' => '<base>/history',
53
+ 'description' => "Directory containing history files.\n" \
54
+ "os.hst stores system commands entered when using --os-pwn option.\n" \
55
+ 'sql.hst stores SQL quries entered when using --os-shell option.'
56
+ },
57
+ 'logs' => {
58
+ 'path' => '<base>/output',
59
+ 'description' => "Directory containing a folder per target.\n" \
60
+ "<target>/log contains all successful injection vectors.\n" \
61
+ "<target>/session.sqlite contains retrieved data.\n" \
62
+ '<target>/target.txt contains target URL + command used.'
63
+ }
64
+ }
65
+ },
66
+ 'crackmapexec' => {
67
+ 'enabled' => true,
68
+ 'location' => {
69
+ 'base' => '$HOME/.cme', # ~/.cme
70
+ 'logs' => {
71
+ 'path' => '<base>/logs',
72
+ 'description' => 'Directory containing log files, secrets, hashes, cleartext passwords etc.'
73
+ },
74
+ 'screenshots' => {
75
+ 'path' => '<base>/screenshots',
76
+ 'description' => 'Directory where are stored all screenshots taken with the --screenshot option.'
77
+ },
78
+ 'workspaces' => {
79
+ 'path' => '<base>/workspaces',
80
+ 'description' => "Directory containing workspaces.\n" \
81
+ 'Workspaces contain SQLite databases including users (domain, usernames, password), ' \
82
+ 'shares, hosts, dpapi secrets, etc.'
83
+ }
84
+ }
85
+ },
86
+ 'netexec' => {
87
+ 'enabled' => true,
88
+ 'location' => {
89
+ 'base' => '$HOME/.nxc', # ~/.nxc
90
+ 'logs' => {
91
+ 'path' => '<base>/logs',
92
+ 'description' => 'Directory containing log files, secrets, hashes, cleartext password etc.'
93
+ },
94
+ 'screenshots' => {
95
+ 'path' => '<base>/screenshots',
96
+ 'description' => 'Directory where are stored all screenshots taken with the --screenshot option.'
97
+ },
98
+ 'workspaces' => {
99
+ 'path' => '<base>/workspaces',
100
+ 'description' => "Directory containing workspaces.\n" \
101
+ 'Workspaces contain SQLite databases including users (domain, usernames, password), ' \
102
+ 'shares, hosts, dpapi secrets, etc.'
103
+ }
104
+ }
105
+ },
106
+ 'hashcat' => {
107
+ 'enabled' => true,
108
+ 'location' => {
109
+ 'base' => '$XDG_DATA_HOME/hashcat', # ~/.local/share/hashcat
110
+ #
111
+ #
112
+ #
113
+ 'sessions' => {
114
+ 'path' => '<base>/sessions',
115
+ 'enaled' => false,
116
+ 'description' => "Directory containing session related data.\n" \
117
+ 'hashcat.log should not contain any sensible data unless the file name ' \
118
+ "of a target file is sensible.\n" \
119
+ 'show.log should not contain any sensible data unless the folder name is sensible.'
120
+ },
121
+ 'potfile' => {
122
+ 'path' => '<base>/hashcat.potfile',
123
+ 'description' => "File containing all cracked hashes.\n" \
124
+ 'Passwords may include enterprize related content or may be easily recognizable.'
125
+ },
126
+ 'dict_cache' => {
127
+ 'path' => '<base>/hashcat.dictstat2',
128
+ 'enabled' => false,
129
+ 'description' => "File is a cache for dictionaries.\n" \
130
+ 'It should not be sensible unless dict. contain confidential data.'
131
+ }
132
+ }
133
+ },
134
+ 'theharvester' => {
135
+ 'enabled' => true,
136
+ 'location' => {
137
+ 'base' => '$XDG_DATA_HOME/theHarvester', # ~/.local/share/theHarvester
138
+ #
139
+ 'stash' => {
140
+ 'path' => '<base>/stash.sqlite',
141
+ 'description' => 'File (SQLite DB) containing all the harvested addresses.'
142
+ }
143
+ }
144
+ },
145
+ 'john' => {
146
+ 'enabled' => true,
147
+ 'location' => {
148
+ 'base' => '$HOME/.john', # ~/.john
149
+ #
150
+ #
151
+ 'logs' => {
152
+ 'path' => '<base>/john.log',
153
+ 'description' => "File containing the logs of the commands launched.\n" \
154
+ 'Does not contain hashes or passwords but usernames and whole command lines.'
155
+ },
156
+ 'potfile' => {
157
+ 'path' => '<base>/john.pot',
158
+ 'description' => "File containing all cracked hashes.\n" \
159
+ 'Passwords may include enterprize related content or may be easily recognizable.'
160
+ }
161
+ }
162
+ },
163
+ 'metasploit' => {
164
+ 'enabled' => true,
165
+ 'location' => {
166
+ 'base' => '$HOME/.msf4', # ~/.msf4
167
+ #
168
+ #
169
+ 'history' => {
170
+ 'path' => '<base>/history',
171
+ 'description' => "File containing the history of commands used in msf shell.\n" \
172
+ 'It certainly contains username, passwords, hostnames, etc.'
173
+ },
174
+ 'logs' => {
175
+ 'path' => '<base>/logs',
176
+ 'description' => "Directory containing log files.\n" \
177
+ "framework.log may contain stacktraces that contain payloads.\n" \
178
+ "production.log and sessions/ ? (I don't know, empty for me)"
179
+ },
180
+ 'loot' => {
181
+ 'path' => '<base>/loot',
182
+ 'description' => "Directory containing looted files.\n" \
183
+ 'Those are retrieved clients files.'
184
+ },
185
+ 'meterpreter' => {
186
+ 'path' => '<base>/meterpreter_history',
187
+ 'description' => "File containing the history of commands used in meterpreter sessions.\n" \
188
+ "Less sensible than msf shell history but could still contains some file paths, \n" \
189
+ 'for example.'
190
+ }
191
+ }
192
+ }
193
+ },
194
+ 'audit' => {
195
+ 'enabled' => false,
196
+ 'location' => {
197
+ 'base' => '$HOME/Projets'
198
+ }
199
+ }
200
+ }.freeze
201
+
202
+ # The parsed Aspisec configuration
203
+ # @return [Hash] the Aspisec configuration object
204
+ attr_reader :conf
205
+
206
+ # Load config. or create a default config. file if not existing.
207
+ # Also parse and interprete custom values.
208
+ # @param logger [TTY::Logger] logger instance. See {Aspisec::Logger}.
209
+ # If none is provided, a default logger with log level 2 is created.
210
+ # See {Aspisec::Logger::LOG_LEVEL}.
211
+ # @example
212
+ # # With default logger
213
+ # cnf = Aspisec::Config.new
214
+ # cnf.conf
215
+ # # With custom logger
216
+ # logger = Aspisec::Logger.new(0).logger
217
+ # cnf = Aspisec::Config.new(logger)
218
+ # cnf.conf
219
+ def initialize(logger = nil)
220
+ # Set log level
221
+ @logger = logger || Aspisec::Logger.new.logger
222
+ # Create the configuration file if it doesn't exist
223
+ create_config unless config_exist?
224
+ # Else load it
225
+ @conf = load_config
226
+ # Replace the path variables / plaholders with real values
227
+ expand_path_conf!
228
+ end
229
+
230
+ # Read and parse (YAML ➡️ Ruby Hash) the config. file
231
+ # @return [Hash|nil] the corresponding Ruby object parsed from the YAML file
232
+ # or `nil` if the configuration file doesn't exist
233
+ def load_config
234
+ if config_exist?
235
+ @logger.debug("Loading configuration from #{config_filepath}")
236
+ YAML.load_file(config_filepath, symbolize_names: false)
237
+ else
238
+ @logger.warn('Configuration not loaded')
239
+ nil
240
+ end
241
+ end
242
+
243
+ # Create the configuration file with default value at default location if it doesn't already exist
244
+ def create_config
245
+ return if config_exist?
246
+
247
+ parent_dir = File.dirname(config_filepath)
248
+ # create parent folder recursively if it doesn't already exist
249
+ FileUtils.mkpath(parent_dir)
250
+ @logger.info("Creating configuration file: #{config_filepath}")
251
+ File.write(config_filepath, YAML.dump(DEFAULT_CONFIG))
252
+ end
253
+
254
+ # Get the Aspisec configuration file path
255
+ # @return [String] absolute file path
256
+ def config_filepath
257
+ xdg = XDG.new
258
+ # Logging this floods debug info and is not meaningful
259
+ # path = xdg.config_home + 'aspisec' + CONFIG_FILENAME
260
+ # @logger.debug("The default configuration file path should be: #{path}")
261
+ # path
262
+ # https://github.com/rubocop/rubocop/issues/11757
263
+ # rubocop:disable Style/StringConcatenation
264
+ xdg.config_home + 'aspisec' + CONFIG_FILENAME # /home/noraj/.config/aspisec/aspisec.config.yaml
265
+ # rubocop:enable Style/StringConcatenation
266
+ end
267
+
268
+ # Check if the Aspisec configuration file exists or not
269
+ # @return [true|false]
270
+ def config_exist?
271
+ # Logging this floods debug info and is not meaningful
272
+ # exist = File.exist?(config_filepath)
273
+ # neg = exist ? '' : 'does not'
274
+ # @logger.debug("The configuration file #{config_filepath} #{neg} exist")
275
+ # exist
276
+ File.exist?(config_filepath)
277
+ end
278
+
279
+ # @note see {Aspisec::Config.expand_path_variables}
280
+ def expand_path_variables(path)
281
+ Config.expand_path_variables(path)
282
+ end
283
+
284
+ # Evaluate XDG variables and $HOME in file path
285
+ # @param path [String] path with variables
286
+ # @return the absolute version of the evaluated path
287
+ # @note Arguments other than Strings are returned untouched, useful to iterate over configuration values
288
+ # @example
289
+ # conf.expand_path_variables('$XDG_DATA_HOME/sqlmap')
290
+ # # => "/home/noraj/.local/share/sqlmap"
291
+ def self.expand_path_variables(path)
292
+ return path unless path.is_a?(String) # not a path, let untouched
293
+
294
+ xdg = XDG.new
295
+ case path
296
+ when /\$XDG_CONFIG_HOME/
297
+ path.sub!('$XDG_CONFIG_HOME', xdg.config_home.to_s)
298
+ when /\$XDG_DATA_HOME/
299
+ path.sub!('$XDG_DATA_HOME', xdg.data_home.to_s)
300
+ when /\$HOME/
301
+ path.sub!('$HOME', Dir.home)
302
+ end
303
+ File.expand_path(path)
304
+ end
305
+
306
+ # Expand all base location with {Aspisec::Config.expand_path_variables} in the configuration
307
+ # + expand the custom `<base>` tags
308
+ def expand_path_conf!
309
+ @conf['tools'].each_key do |tool|
310
+ base_path = @conf.dig('tools', tool, 'location', 'base')
311
+ @conf['tools'][tool]['location']['base'] = expand_path_variables(base_path)
312
+ @conf['tools'][tool]['location'].each_key do |k|
313
+ unless k == 'base'
314
+ feature_path = @conf.dig('tools', tool, 'location', k, 'path')
315
+ @conf['tools'][tool]['location'][k]['path'] = feature_path.sub('<base>', base_path) if feature_path
316
+ end
317
+ end
318
+ end
319
+ @conf['audit']['location']['base'] = expand_path_variables(@conf.dig('audit', 'location', 'base'))
320
+ @conf
321
+ end
322
+ end
323
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tty-logger'
4
+
5
+ module Aspisec
6
+ # CLI / Terminal / console information logging
7
+ class Logger
8
+ # Mapping integers to log levels from tty-logger (https://github.com/piotrmurach/tty-logger?tab=readme-ov-file#22-levels)
9
+ LOG_LEVEL = {
10
+ 0 => :debug,
11
+ 1 => :info,
12
+ 2 => :warn,
13
+ 3 => :error,
14
+ 4 => :fatal
15
+ }.freeze
16
+
17
+ # The configuration of the logger
18
+ # @return [TTY::Logger]
19
+ attr_reader :logger
20
+
21
+ # @param log_level [Integer] Default is 2. See {LOG_LEVEL}.
22
+ # @example
23
+ # logger = Aspisec::Logger.new(0).logger
24
+ # conf = Aspisec::Config.new(logger)
25
+ def initialize(log_level = 2)
26
+ @logger = TTY::Logger.new { |config| config.level = LOG_LEVEL[log_level] }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # stdlib
4
+ require 'pathname'
5
+ # third-party
6
+ require 'tty-logger'
7
+
8
+ module Aspisec
9
+ # Generic module class that will be inherited in all modules instances
10
+ class Module
11
+ # The configuration for the tool.
12
+ # Sub-tree under `tools > tool_name` of {Aspisec::Config#conf}.
13
+ # @return [Hash]
14
+ attr_reader :conf
15
+
16
+ # The name of the tool.
17
+ # @return [String] tool name
18
+ attr_reader :name
19
+
20
+ # List of locations (name).
21
+ # Returns something only on module instances like {Aspisec::Modules::Sqlmap}.
22
+ # Will be empty for {Aspisec::Module}.
23
+ # For a list of objects, rather use {locations}.
24
+ # @return [Array<String>]
25
+ attr_reader :locations_list
26
+
27
+ # The base location (directory) where the tool data is stored.
28
+ # @return [Pathname] file path
29
+ attr_reader :base
30
+
31
+ # Not meant to be used directly but to be inherited in modules instead
32
+ # @param conf [Aspisec::Config] an instance of the global configuration
33
+ # @param tool_name [String] The name of the tool. It must match the configuration key.
34
+ # @param logger [TTY::Logger] logger instance. See {Aspisec::Logger}.
35
+ # If none is provided, a default logger with log level 2 is created.
36
+ # See {Aspisec::Logger::LOG_LEVEL}.
37
+ # @example
38
+ # conf = Aspisec::Config.new.conf
39
+ # # you should never do that as you'll get incomplete data and features
40
+ # sqlmap = Aspisec::Module.new(conf, 'sqlmap')
41
+ # # rather call the sqlmap module that will inherit this class
42
+ # sqlmap = Aspisec::Modules::Sqlmap.new(conf)
43
+ def initialize(conf, tool_name, logger: nil)
44
+ @logger = logger || Aspisec::Logger.new.logger
45
+ @name = tool_name
46
+ @logger.debug("Module #{@name} was loaded", app: @name)
47
+ @conf = conf['tools'][tool_name]
48
+ @base = Pathname.new(@conf.dig('location', 'base'))
49
+ @enabled = @conf.fetch('enabled', true)
50
+ @locations_list = []
51
+ end
52
+
53
+ # Is this module enabled?
54
+ # @return [true|false]
55
+ def enabled?
56
+ @enabled
57
+ end
58
+
59
+ # Returns all locations available for the tool.
60
+ # It returns a list {Location} objects unline {locations_list} that returns
61
+ # only strings (location names).
62
+ # @return [Array<Location>]
63
+ def locations
64
+ # Re-compute what's already cumputed and stored in properties
65
+ # @locations_list.map { |loc| Location.new(@conf, loc) }
66
+ # Access properties rather than re-computing
67
+ # Using send() is safe here because the input is a hadrcaoded whitelist
68
+ @locations_list.map { |loc| send(loc) }
69
+ end
70
+
71
+ # Object easing the manipulation of locations.
72
+ # Helpers to get the path, check if this feature/file/directory is enabled, etc.
73
+ class Location
74
+ # Name of the feature, file or directory of the tool.
75
+ # @return [String]
76
+ attr_reader :name
77
+
78
+ # File path of the file or directory location to clean.
79
+ # @return [Pathname] absolute path
80
+ attr_reader :path
81
+
82
+ # Explanation of what the location (file / directory) is containing, to give an idea of how sensitive it is.
83
+ # @return [String] description
84
+ attr_reader :description
85
+
86
+ # @param tool_conf [Hash] Tool configuration as returned by {Aspisec::Module#conf}.
87
+ # @param feature_name [String] Name of the feature/file/directory to clean.
88
+ # Must be equal to the configuration key.
89
+ def initialize(tool_conf, feature_name)
90
+ @name = feature_name
91
+ @path = Pathname.new(tool_conf.dig('location', @name, 'path'))
92
+ @enabled = tool_conf.dig('location', @name).fetch('enabled', true)
93
+ @description = tool_conf.dig('location', @name).fetch('description', '')
94
+ end
95
+
96
+ # Is this location enabled?
97
+ # @return [true|false]
98
+ def enabled?
99
+ @enabled
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/module'
4
+
5
+ module Aspisec
6
+ module Modules
7
+ # CrackMapExec module.
8
+ # Inherits {Aspisec::Module}.
9
+ # For more examples of methods, see {Aspisec::Modules::Sqlmap}.
10
+ # @see https://github.com/byt3bl33d3r/CrackMapExec
11
+ # @example
12
+ # # Get the global config
13
+ # conf = Aspisec::Config.new.conf
14
+ # # Create a Crackmapexec module instance
15
+ # cme = Aspisec::Modules::Crackmapexec.new(conf)
16
+ # # Locations available
17
+ # cme.locations_list # => ["logs", "screenshots", "workspaces"]
18
+ class Crackmapexec < Aspisec::Module
19
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
20
+ # @return [Location]
21
+ attr_reader :logs
22
+
23
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
24
+ # @return [Location]
25
+ attr_reader :screenshots
26
+
27
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
28
+ # @return [Location]
29
+ attr_reader :workspaces
30
+
31
+ # Inherits from {Aspisec::Module} but without the `tool_name` argument
32
+ # because it is hardcoded for each module.
33
+ # @param conf [Aspisec::Config] an instance of the global configuration
34
+ def initialize(conf, logger: nil)
35
+ super(conf, 'crackmapexec', logger:)
36
+ @logs = Location.new(@conf, 'logs')
37
+ @screenshots = Location.new(@conf, 'screenshots')
38
+ @workspaces = Location.new(@conf, 'workspaces')
39
+ @locations_list = %w[logs screenshots workspaces]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/module'
4
+
5
+ module Aspisec
6
+ module Modules
7
+ # HashCat module.
8
+ # Inherits {Aspisec::Module}.
9
+ # For more examples of methods, see {Aspisec::Modules::Sqlmap}.
10
+ # @see https://github.com/hashcat/hashcat
11
+ # @example
12
+ # # Get the global config
13
+ # conf = Aspisec::Config.new.conf
14
+ # # Create a Hashcat module instance
15
+ # hc = Aspisec::Modules::Hashcat.new(conf)
16
+ # # Locations available
17
+ # hc.locations_list # => ["sessions", "potfile", "dict_cache"]
18
+ class Hashcat < Aspisec::Module
19
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
20
+ # @return [Location]
21
+ attr_reader :sessions
22
+
23
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
24
+ # @return [Location]
25
+ attr_reader :potfile
26
+
27
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
28
+ # @return [Location]
29
+ attr_reader :dict_cache
30
+
31
+ # Inherits from {Aspisec::Module} but has only the `conf` argument,
32
+ # `tool_name` is hardcoded for each module.
33
+ # @param conf [Aspisec::Config] an instance of the global configuration
34
+ def initialize(conf, logger: nil)
35
+ super(conf, 'hashcat', logger:)
36
+ @sessions = Location.new(@conf, 'sessions')
37
+ @potfile = Location.new(@conf, 'potfile')
38
+ @dict_cache = Location.new(@conf, 'dict_cache')
39
+ @locations_list = %w[sessions potfile dict_cache]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/module'
4
+
5
+ module Aspisec
6
+ module Modules
7
+ # John (the Ripper) module.
8
+ # Inherits {Aspisec::Module}.
9
+ # For more examples of methods, see {Aspisec::Modules::Sqlmap}.
10
+ # @see https://github.com/openwall/john
11
+ # @example
12
+ # # Get the global config
13
+ # conf = Aspisec::Config.new.conf
14
+ # # Create a John module instance
15
+ # john = Aspisec::Modules::John.new(conf)
16
+ # # Locations available
17
+ # john.locations_list # => ["logs", "potfile"]
18
+ class John < Aspisec::Module
19
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
20
+ # @return [Location]
21
+ attr_reader :logs
22
+
23
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
24
+ # @return [Location]
25
+ attr_reader :potfile
26
+
27
+ # Inherits from {Aspisec::Module} but has only the `conf` argument,
28
+ # `tool_name` is hardcoded for each module.
29
+ # @param conf [Aspisec::Config] an instance of the global configuration
30
+ def initialize(conf, logger: nil)
31
+ super(conf, 'john', logger:)
32
+ @logs = Location.new(@conf, 'logs')
33
+ @potfile = Location.new(@conf, 'potfile')
34
+ @locations_list = %w[logs potfile]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/module'
4
+
5
+ module Aspisec
6
+ module Modules
7
+ # Metasploit module.
8
+ # Inherits {Aspisec::Module}.
9
+ # For more examples of methods, see {Aspisec::Modules::Sqlmap}.
10
+ # @see https://github.com/rapid7/metasploit-framework
11
+ # @example
12
+ # # Get the global config
13
+ # conf = Aspisec::Config.new.conf
14
+ # # Create a Metasploit module instance
15
+ # msf = Aspisec::Modules::Metasploit.new(conf)
16
+ # # Locations available
17
+ # msf.locations_list # => ["history", "logs", "loot", "meterpreter"]
18
+ class Metasploit < Aspisec::Module
19
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
20
+ # @return [Location]
21
+ attr_reader :history
22
+
23
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
24
+ # @return [Location]
25
+ attr_reader :logs
26
+
27
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
28
+ # @return [Location]
29
+ attr_reader :loot
30
+
31
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
32
+ # @return [Location]
33
+ attr_reader :meterpreter
34
+
35
+ # Inherits from {Aspisec::Module} but has only the `conf` argument,
36
+ # `tool_name` is hardcoded for each module.
37
+ # @param conf [Aspisec::Config] an instance of the global configuration
38
+ def initialize(conf, logger: nil)
39
+ super(conf, 'metasploit', logger:)
40
+ @history = Location.new(@conf, 'history')
41
+ @logs = Location.new(@conf, 'logs')
42
+ @loot = Location.new(@conf, 'loot')
43
+ @meterpreter = Location.new(@conf, 'meterpreter')
44
+ @locations_list = %w[history logs loot meterpreter]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/module'
4
+
5
+ module Aspisec
6
+ module Modules
7
+ # NetExec module.
8
+ # Inherits {Aspisec::Module}.
9
+ # For more examples of methods, see {Aspisec::Modules::Sqlmap}.
10
+ # @see https://github.com/Pennyw0rth/NetExec
11
+ # @example
12
+ # # Get the global config
13
+ # conf = Aspisec::Config.new.conf
14
+ # # Create a Netexec module instance
15
+ # nxc = Aspisec::Modules::Netexec.new(conf)
16
+ # # Locations available
17
+ # nxc.locations_list # => ["logs", "screenshots", "workspaces"]
18
+ class Netexec < Aspisec::Module
19
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
20
+ # @return [Location]
21
+ attr_reader :logs
22
+
23
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
24
+ # @return [Location]
25
+ attr_reader :screenshots
26
+
27
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
28
+ # @return [Location]
29
+ attr_reader :workspaces
30
+
31
+ # Inherits from {Aspisec::Module} but has only the `conf` argument,
32
+ # `tool_name` is hardcoded for each module.
33
+ # @param conf [Aspisec::Config] an instance of the global configuration
34
+ def initialize(conf, logger: nil)
35
+ super(conf, 'netexec', logger:)
36
+ @logs = Location.new(@conf, 'logs')
37
+ @screenshots = Location.new(@conf, 'screenshots')
38
+ @workspaces = Location.new(@conf, 'workspaces')
39
+ @locations_list = %w[logs screenshots workspaces]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/module'
4
+
5
+ module Aspisec
6
+ module Modules
7
+ # Sqlmap module.
8
+ # Inherits {Aspisec::Module}.
9
+ # @see https://github.com/sqlmapproject/sqlmap
10
+ # @example
11
+ # # Get the global config
12
+ # conf = Aspisec::Config.new.conf
13
+ # # Create a Sqlmap module instance
14
+ # sqlmap = Aspisec::Modules::Sqlmap.new(conf)
15
+ # # Generic methods
16
+ # sqlmap.name # => "sqlmap"
17
+ # sqlmap.conf # => {…}
18
+ # sqlmap.enabled? # => true
19
+ # sqlmap.base # => #<Pathname:/home/noraj/.local/share/sqlmap>
20
+ # sqlmap.locations_list # => ["history", "logs"]
21
+ # sqlmap.locations # => [#<Aspisec::Module::Location …>, … ]
22
+ # # Custom methods for the feature/file/directory location of Sqlmap to clean
23
+ # sqlmap.history # => #<Aspisec::Module::Location …>
24
+ # sqlmap.logs # => #<Aspisec::Module::Location …>
25
+ # # But those custom locations benefits of generic methods
26
+ # sqlmap.history.enabled? # => true
27
+ # sqlmap.history.name # => => "history"
28
+ # sqlmap.history.description # => "Directory containing…"
29
+ # sqlmap.history.path => #<Pathname:/home/noraj/.local/share/sqlmap/history>
30
+ # # Since `.path` returns a {Pathname} object, we can use generic {File},
31
+ # # {FileTest} methods and some from {Dir} and {FileUtils} as well.
32
+ # sqlmap.history.path.exist? # => true
33
+ # sqlmap.history.path.file? # => false
34
+ # sqlmap.history.path.directory? # => true
35
+ # sqlmap.history.path.readable? # => true
36
+ # sqlmap.history.path.children # => [#<Pathname:/home/noraj/.local/share/sqlmap/history/os.hst>, #<Pathname:…>]
37
+ # sqlmap.history.path.children.first.size # => 10
38
+ class Sqlmap < Aspisec::Module
39
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
40
+ # @return [Location]
41
+ attr_reader :history
42
+
43
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
44
+ # @return [Location]
45
+ attr_reader :logs
46
+
47
+ # Inherits from {Aspisec::Module} but has only the `conf` argument,
48
+ # `tool_name` is hardcoded for each module.
49
+ # @param conf [Aspisec::Config] an instance of the global configuration
50
+ def initialize(conf, logger: nil)
51
+ super(conf, 'sqlmap', logger:)
52
+ @history = Location.new(@conf, 'history')
53
+ @logs = Location.new(@conf, 'logs')
54
+ @locations_list = %w[history logs]
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/module'
4
+
5
+ module Aspisec
6
+ module Modules
7
+ # theHarvester module.
8
+ # Inherits {Aspisec::Module}.
9
+ # For more examples of methods, see {Aspisec::Modules::Sqlmap}.
10
+ # @see https://github.com/laramies/theHarvester
11
+ # @example
12
+ # # Get the global config
13
+ # conf = Aspisec::Config.new.conf
14
+ # # Create a Theharvester module instance
15
+ # th = Aspisec::Modules::Theharvester.new(conf)
16
+ # # Locations available
17
+ # th.locations_list # => ["stash"]
18
+ class Theharvester < Aspisec::Module
19
+ # see {Aspisec::Config::DEFAULT_CONFIG} or call {Aspisec::Module::Location#description}.
20
+ # @return [Location]
21
+ attr_reader :stash
22
+
23
+ # Inherits from {Aspisec::Module} but has only the `conf` argument,
24
+ # `tool_name` is hardcoded for each module.
25
+ # @param conf [Aspisec::Config] an instance of the global configuration
26
+ def initialize(conf, logger: nil)
27
+ super(conf, 'theharvester', logger:)
28
+ @stash = Location.new(@conf, 'stash')
29
+ @locations_list = %w[stash]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require all modules
4
+ Dir[File.join(__dir__, 'modules', '*.rb')].each { |f| require(f) }
5
+
6
+ module Aspisec
7
+ # This Ruby module contains all Aspisec modules.
8
+ # Each Aspisec module is a Ruby class inherinting the Aspisec::Module base class.
9
+ # The "Modules" module also contains methods to manage all Aspisec modules.
10
+ module Modules
11
+ # List all available Aspisec modules
12
+ # @return [Array<Symbol>] list of symbolized module names
13
+ # @example
14
+ # Aspisec::Modules.list_modules
15
+ # # => [:Netexec, :Sqlmap, :Hashcat, :Theharvester, :Crackmapexec, :John, :Metasploit]
16
+ def self.list_modules
17
+ Aspisec::Modules.constants.select { |c| Aspisec::Modules.const_get(c) <= Aspisec::Module }
18
+ end
19
+
20
+ # Intanciates all Aspisec modules
21
+ # @param conf [Aspisec::Config] an instance of the global configuration
22
+ # If none is provided, the default config is loaded.
23
+ # @param logger [TTY::Logger] logger instance. See {Aspisec::Logger}.
24
+ # If none is provided, a default logger with log level 2 is created.
25
+ # See {Aspisec::Logger::LOG_LEVEL}.
26
+ # @return [Array<Aspisec::Module>]
27
+ def self.modules(conf: nil, logger: nil)
28
+ cnf = conf || Aspisec::Config.new(logger).conf
29
+ list_modules.map { |c| Aspisec::Modules.const_get(c).new(cnf, logger:) }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aspisec
4
+ # Version of aspisec library and app
5
+ VERSION = '0.0.1'
6
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspisec/version'
4
+
5
+ require 'aspisec/clean'
6
+ require 'aspisec/config'
7
+ require 'aspisec/logger'
8
+ require 'aspisec/modules'
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aspisec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexandre ZANNI
8
+ autorequire:
9
+ bindir: bin-ruby
10
+ cert_chain: []
11
+ date: 2024-04-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 7.1.3.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '7.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 7.1.3.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: docopt
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.6'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.6'
47
+ - !ruby/object:Gem::Dependency
48
+ name: pastel
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.8'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.8'
61
+ - !ruby/object:Gem::Dependency
62
+ name: tty-logger
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.6'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.6'
75
+ - !ruby/object:Gem::Dependency
76
+ name: tty-prompt
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.23'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.23'
89
+ - !ruby/object:Gem::Dependency
90
+ name: xdg
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '8.0'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '8.0'
103
+ description: Vacuuming out the remnants of offensive tools. AspiSec is responsible
104
+ for removing the traces and confidential information left by offensive security
105
+ tools on an auditor's computer in various cache and log files.
106
+ email: alexandre.zanni@europe.com
107
+ executables:
108
+ - aspisec
109
+ extensions: []
110
+ extra_rdoc_files: []
111
+ files:
112
+ - LICENSE
113
+ - bin-ruby/aspisec
114
+ - lib-ruby/aspisec.rb
115
+ - lib-ruby/aspisec/clean.rb
116
+ - lib-ruby/aspisec/config.rb
117
+ - lib-ruby/aspisec/logger.rb
118
+ - lib-ruby/aspisec/module.rb
119
+ - lib-ruby/aspisec/modules.rb
120
+ - lib-ruby/aspisec/modules/crackmapexec.rb
121
+ - lib-ruby/aspisec/modules/hashcat.rb
122
+ - lib-ruby/aspisec/modules/john.rb
123
+ - lib-ruby/aspisec/modules/metasploit.rb
124
+ - lib-ruby/aspisec/modules/netexec.rb
125
+ - lib-ruby/aspisec/modules/sqlmap.rb
126
+ - lib-ruby/aspisec/modules/theharvester.rb
127
+ - lib-ruby/aspisec/version.rb
128
+ homepage: https://acceis.github.io/aspisec/
129
+ licenses:
130
+ - MIT
131
+ metadata:
132
+ yard.run: yard
133
+ bug_tracker_uri: https://github.com/acceis/aspisec/issues
134
+ changelog_uri: https://github.com/acceis/aspisec/blob/master/docs/CHANGELOG.md
135
+ documentation_uri: https://acceis.github.io/aspisec/
136
+ homepage_uri: https://acceis.github.io/aspisec/
137
+ source_code_uri: https://github.com/acceis/aspisec/
138
+ rubygems_mfa_required: 'true'
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib-ruby
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: 3.1.0
148
+ - - "<"
149
+ - !ruby/object:Gem::Version
150
+ version: '4.0'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubygems_version: 3.5.3
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Removes the traces left by offensive security tools.
161
+ test_files: []