pwn 0.5.154 → 0.5.156

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: cdc176de7f592b5c19650942854e4efa7d0158c835e89ace9f40af31a5a92f90
4
- data.tar.gz: 3f756b2f5deb2589c2e9d30068d13b1e460b0e7091cdeae6a0097fa3947e98ce
3
+ metadata.gz: 47f160c73c391cf48bd0a847d0031d342ef79b77575e86872153105905072141
4
+ data.tar.gz: 7c71dc97fd8e8e4e99584ab8bbb97363d46a2edd6786f2bb8e4ee9bd7c0b16cb
5
5
  SHA512:
6
- metadata.gz: 7a6437ab3cb220bd0c374b9672848646bace31fd6ba283e717a67db97a7826a397a9e8a68d0339f209cffebb55d8e63c918ebd211335b9406961822b2136c715
7
- data.tar.gz: 7ece6c1aeb18b7a16d772552717708c0df8b30483547e4080f2f2699173e52b1207b2a2b55ab3856cd077a958e065e89f32bf274d58894799db53b55db6a1939
6
+ metadata.gz: 55c9643d11b525ef375396f51354e2356363567de4ca1b9e0d9ea9281ff2af58698bd819a38f1e8b0c7212b03012403257c5e4622ae16e7ee018a36e1d66c7e1
7
+ data.tar.gz: c67b6fe7fbf5966d2630c4a0e99f254e58e6b09a6b15cad13a79897f9ab42c0f2efb7147547c70b4663e0f830af672d72859abc50e64e54b51ad999c4a33220b
data/README.md CHANGED
@@ -37,7 +37,7 @@ $ cd /opt/pwn
37
37
  $ ./install.sh
38
38
  $ ./install.sh ruby-gem
39
39
  $ pwn
40
- pwn[v0.5.154]:001 >>> PWN.help
40
+ pwn[v0.5.156]:001 >>> PWN.help
41
41
  ```
42
42
 
43
43
  [![Installing the pwn Security Automation Framework](https://raw.githubusercontent.com/0dayInc/pwn/master/documentation/pwn_install.png)](https://youtu.be/G7iLUY4FzsI)
@@ -52,7 +52,7 @@ $ rvm use ruby-3.3.1@pwn
52
52
  $ gem uninstall --all --executables pwn
53
53
  $ gem install --verbose pwn
54
54
  $ pwn
55
- pwn[v0.5.154]:001 >>> PWN.help
55
+ pwn[v0.5.156]:001 >>> PWN.help
56
56
  ```
57
57
 
58
58
  If you're using a multi-user install of RVM do:
@@ -62,7 +62,7 @@ $ rvm use ruby-3.3.1@pwn
62
62
  $ rvmsudo gem uninstall --all --executables pwn
63
63
  $ rvmsudo gem install --verbose pwn
64
64
  $ pwn
65
- pwn[v0.5.154]:001 >>> PWN.help
65
+ pwn[v0.5.156]:001 >>> PWN.help
66
66
  ```
67
67
 
68
68
  PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
data/bin/pwn_sast CHANGED
@@ -117,7 +117,7 @@ begin
117
117
  TypeScriptTypeJuggling
118
118
  Version
119
119
  WindowLocationHash
120
- ]
120
+ ].sort.uniq
121
121
  end
122
122
 
123
123
  if list_test_cases
@@ -46,12 +46,30 @@ module PWN
46
46
  raise e
47
47
  end
48
48
 
49
+ # Supported Method Parameters::
50
+ # is_rfc1918 = PWN::Plugins::IPInfo.check_rfc1918(
51
+ # ip: 'required - IP to check'
52
+ # )
53
+ public_class_method def self.check_rfc1918(opts = {})
54
+ ip = opts[:ip].to_s.scrub.strip.chomp
55
+ ip_obj = IPAddress.valid?(ip) ? IPAddress.parse(ip) : nil
56
+
57
+ rfc1918_ranges = [
58
+ IPAddress('10.0.0.0/8'), # 10.0.0.0 - 10.255.255.255
59
+ IPAddress('172.16.0.0/12'), # 172.16.0.0 - 172.31.255.255
60
+ IPAddress('192.168.0.0/16') # 192.168.0.0 - 192.168.255.255
61
+ ]
62
+
63
+ rfc1918_ranges.any? { |range| range.include?(ip_obj) }
64
+ end
65
+
49
66
  # Supported Method Parameters::
50
67
  # ip_info_struc = PWN::Plugins::IPInfo.get(
51
68
  # target: 'required - IP or Host to lookup',
52
69
  # proxy: 'optional - use a proxy',
53
70
  # tls_port: 'optional port to check cert for Domain Name (default: 443). Will not execute if proxy parameter is set.',
54
- # skip_api: 'optional - skip the API call'
71
+ # skip_api: 'optional - skip the API call',
72
+ # dns_server: 'optional - DNS server to use for lookup (default: your default DNS server)'
55
73
  # )
56
74
 
57
75
  public_class_method def self.get(opts = {})
@@ -63,19 +81,29 @@ module PWN
63
81
  ip_info_resp = []
64
82
  ip_resp_hash = {}
65
83
  is_ip = IPAddress.valid?(target)
66
-
67
- begin
68
- ip_resp_hash[:hostname] = target
69
- target = Resolv.getaddress(target) unless is_ip
70
- rescue Resolv::ResolvError
71
- target = nil
84
+ hostname = '' if is_ip
85
+
86
+ unless is_ip
87
+ begin
88
+ hostname = target
89
+ dns_server = opts[:dns_server]
90
+ dns_resolver = Resolv::DNS.new(nameserver: [dns_server]) if dns_server
91
+ dns_resolver ||= Resolv::DNS.new
92
+ target = dns_resolver.getaddress(target).to_s
93
+ rescue Resolv::ResolvError
94
+ target = nil
95
+ end
72
96
  end
73
97
 
74
98
  ip_resp_hash = ip_info_rest_call(ip: target, proxy: proxy) unless skip_api
99
+ is_rfc1918 = check_rfc1918(ip: target)
75
100
  ip_resp_hash[:ip] = target
101
+ ip_resp_hash[:is_rfc1918] = is_rfc1918
102
+ ip_resp_hash[:hostname] = hostname
103
+
76
104
  ip_info_resp.push(ip_resp_hash) unless target.nil?
77
105
 
78
- if proxy.nil? && is_ip
106
+ if proxy.nil?
79
107
  ip_info_resp.each do |ip_resp|
80
108
  tls_port_avail = PWN::Plugins::Sock.check_port_in_use(
81
109
  server_ip: target,
@@ -128,7 +156,7 @@ module PWN
128
156
  # PWN::Plugins::IPInfo.bruteforce_subdomains(
129
157
  # parent_domain: 'required - Parent Domain to brute force',
130
158
  # dictionary: 'required - Dictionary to use for subdomain brute force',
131
- # max_threads: 'optional - Maximum number of threads to use (default: 10)',
159
+ # max_threads: 'optional - Maximum number of threads to use (default: 9)',
132
160
  # proxy: 'optional - use a proxy',
133
161
  # tls_port: 'optional port to check cert for Domain Name (default: 443). Will not execute if proxy parameter is set.',
134
162
  # results_file: 'optional - File to write results to (default: /tmp/parent_domain-timestamp-pwn_bruteforce_subdomains.txt)'
@@ -141,15 +169,14 @@ module PWN
141
169
  dictionary = opts[:dictionary] ||= default_dictionary
142
170
  raise "ERROR: Dictionary file not found: #{dictionary}" unless File.exist?(dictionary)
143
171
 
144
- max_threads = opts[:max_threads].to_i
145
- max_threads = 8 unless max_threads.positive?
172
+ max_threads = opts[:max_threads]
146
173
 
147
174
  proxy = opts[:proxy]
148
175
  tls_port = opts[:tls_port]
149
176
  timestamp = Time.now.strftime('%Y-%m-%d_%H.%M.%S')
150
177
  results_file = opts[:results_file] ||= "/tmp/SUBS.#{parent_domain}-#{timestamp}-pwn_bruteforce_subdomains.txt"
151
178
 
152
- File.write(results_file, '[')
179
+ File.write(results_file, "[\n")
153
180
 
154
181
  # Break up dictonary file into sublines and process each subline in a thread
155
182
  dict_lines = File.readlines(dictionary).shuffle
@@ -158,17 +185,16 @@ module PWN
158
185
  enumerable_array: dict_lines,
159
186
  max_threads: max_threads
160
187
  ) do |subline|
188
+ print '.'
161
189
  subdomain = subline.to_s.scrub.strip.chomp
162
190
  target = parent_domain if subdomain.empty?
163
- target = "#{subdomain}.#{parent_domain}"
191
+ target = "#{subdomain}.#{parent_domain}" unless subdomain.empty?
164
192
  ip_info_resp = get(
165
193
  target: target,
166
194
  proxy: proxy,
167
195
  tls_port: tls_port,
168
196
  skip_api: true
169
197
  )
170
- puts "SUBD: #{target} RESP: #{ip_info_resp}" if ip_info_resp.empty?
171
- puts "SUBD: #{target} RESP:\n#{ip_info_resp}" if ip_info_resp.any?
172
198
 
173
199
  mutex.synchronize do
174
200
  File.open(results_file, 'a') do |file|
@@ -185,8 +211,11 @@ module PWN
185
211
  raise e
186
212
  ensure
187
213
  # Strip trailing comma and close JSON array
188
- File.readlines(results_file)[-1].chomp!(',')
189
- File.append(results_file, ']')
214
+ final_results = File.readlines(results_file)
215
+ # Strip trailing comma from last line
216
+ last_line = final_results[-1][0..-2]
217
+ final_results[-1] = last_line
218
+ File.write(results_file, "#{final_results.join}\n]")
190
219
  end
191
220
 
192
221
  # Author(s):: 0day Inc. <support@0dayinc.com>
@@ -201,17 +230,22 @@ module PWN
201
230
 
202
231
  public_class_method def self.help
203
232
  puts "USAGE:
233
+ is_rfc1918 = #{self}.check_rfc1918(
234
+ ip: 'required - IP to check'
235
+ )
236
+
204
237
  ip_info_struc = #{self}.get(
205
238
  target: 'required - IP or Host to lookup',
206
239
  proxy: 'optional - use a proxy',
207
240
  tls_port: 'optional port to check cert for Domain Name (default: 443). Will not execute if proxy parameter is set.',
208
- skip_api: 'optional - skip the API call'
241
+ skip_api: 'optional - skip the API call',
242
+ dns_server: 'optional - DNS server to use for lookup (default: your default DNS server)'
209
243
  )
210
244
 
211
245
  #{self}.bruteforce_subdomains(
212
246
  parent_domain: 'required - Parent Domain to brute force',
213
247
  dictionary: 'required - Dictionary to use for subdomain brute force',
214
- max_threads: 'optional - Maximum number of threads to use (default: 10)',
248
+ max_threads: 'optional - Maximum number of threads to use (default: 9)',
215
249
  proxy: 'optional - use a proxy',
216
250
  tls_port: 'optional port to check cert for Domain Name (default: 443). Will not execute if proxy parameter is set.',
217
251
  results_file: 'optional - File to write results to (default: /tmp/parent_domain-timestamp-pwn_bruteforce_subdomains.txt)'
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'concurrent-ruby'
4
+
3
5
  module PWN
4
6
  module Plugins
5
7
  # This plugin makes the creation of a thread pool much simpler.
@@ -27,34 +29,54 @@ module PWN
27
29
  detach = opts[:detach] ||= false
28
30
 
29
31
  puts "Initiating Thread Pool of #{max_threads} Worker Threads...."
30
- queue = SizedQueue.new(max_threads)
31
- threads = Array.new(max_threads) do
32
- Thread.new do
33
- until (this_thread = queue.pop) == :POOL_EXHAUSTED
34
- yield this_thread
35
- end
36
- end
37
- end
38
-
39
- enumerable_array.uniq.sort.each do |this_thread|
40
- queue << this_thread
41
- end
32
+ pool = Concurrent::FixedThreadPool.new(max_threads)
42
33
 
43
- max_threads.times do
44
- queue << :POOL_EXHAUSTED
34
+ enumerable_array.each do |this_thread|
35
+ pool.post do
36
+ yield this_thread
37
+ end
45
38
  end
46
39
 
47
- if detach
48
- puts 'Detaching from thread pool...'
49
- else
50
- threads.each(&:join)
51
- end
40
+ pool.shutdown
41
+ pool.wait_for_termination unless detach
52
42
  rescue Interrupt
53
43
  puts "\nGoodbye."
54
44
  rescue StandardError => e
45
+ puts e.backtrace
55
46
  raise e
56
47
  end
57
48
 
49
+ # public_class_method def self.fill(opts = {})
50
+ # enumerable_array = opts[:enumerable_array]
51
+ # max_threads = opts[:max_threads].to_i
52
+ # max_threads = 9 if max_threads.zero?
53
+ # detach = opts[:detach] ||= false
54
+
55
+ # puts "Initiating Thread Pool of #{max_threads} Worker Threads...."
56
+ # queue = SizedQueue.new(max_threads)
57
+ # threads = Array.new(max_threads) do
58
+ # Thread.new do
59
+ # until (this_thread = queue.pop) == :POOL_EXHAUSTED
60
+ # yield this_thread
61
+ # end
62
+ # end
63
+ # end
64
+
65
+ # enumerable_array.uniq.each do |this_thread|
66
+ # queue << this_thread
67
+ # end
68
+
69
+ # max_threads.times do
70
+ # queue << :POOL_EXHAUSTED
71
+ # end
72
+
73
+ # threads.each(&:join) unless detach
74
+ # rescue Interrupt
75
+ # puts "\nGoodbye."
76
+ # rescue StandardError => e
77
+ # raise e
78
+ # end
79
+
58
80
  # Author(s):: 0day Inc. <support@0dayinc.com>
59
81
 
60
82
  public_class_method def self.authors
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.154'
4
+ VERSION = '0.5.156'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.154
4
+ version: 0.5.156
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-04 00:00:00.000000000 Z
11
+ date: 2024-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport