wordstress 0.15.0 → 0.20.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/README.md +5 -0
- data/Rakefile +12 -0
- data/bin/wordstress +15 -5
- data/lib/wordstress/site.rb +42 -6
- data/lib/wordstress/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b75716cca39e58a1207a5d4901dbc878ca553fcd
|
4
|
+
data.tar.gz: d63b16b6134ba9640c627d45a535714f36fb968c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 968b67f94189455ee2f9c88efd70153283bd3dd74a00570cf0173c06f7dc0e80e4e707e533de464a68630a11df0df375f96e1d73d5ca6dc54c2b6308b15775f4
|
7
|
+
data.tar.gz: 20c5b07abad346fd080ede674850d9e0d0b9a0c5680b46a1423ae24469ad148cc8100cf365a2c7c4e3d32f9ce53af1b0a169188bc3cda59eba8f666d9e9fd91f
|
data/README.md
CHANGED
@@ -27,11 +27,16 @@ During those years I was very upset as pentester with false positives about
|
|
27
27
|
themes and plugins and their version. Since an authenticated check is necessary
|
28
28
|
to match scan results with installed plugin (or theme) version, I tought it was
|
29
29
|
a better idea to start authenticated from the beginning.
|
30
|
+
** UPDATE ** - this can be very tricky to accomplish
|
30
31
|
|
31
32
|
Of course, wordstress will perform blackbox testing, trying to guess the
|
32
33
|
installed wordpress version and listing vulnerabilities taken from
|
33
34
|
[wpvulndb](https://wpvulndb.com).
|
34
35
|
|
36
|
+
## Online resource
|
37
|
+
|
38
|
+
[Attacking Wordpress](http://hackertarget.com/attacking-wordpress/)
|
39
|
+
|
35
40
|
## Killing features
|
36
41
|
|
37
42
|
* A great knowledge base powered by [wpvulndb API](https://wpvulndb.com)
|
data/Rakefile
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
|
3
|
+
namespace :update do
|
4
|
+
desc 'Update themes'
|
5
|
+
task :themes, :name do |t,args|
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
desc 'Update plugins'
|
10
|
+
task :plugins, :name do |t, args|
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
3
15
|
namespace :import do
|
4
16
|
desc 'Import themes'
|
5
17
|
task :themes, :name do |t,args|
|
data/bin/wordstress
CHANGED
@@ -19,12 +19,16 @@ APPNAME = File.basename($0)
|
|
19
19
|
$logger = Codesake::Commons::Logging.instance
|
20
20
|
@output_root = File.join(Dir.home, '/wordstress')
|
21
21
|
scanning_mode = :gentleman
|
22
|
+
interactive = {:url=>"", :pwd=>""}
|
22
23
|
|
23
24
|
opts = GetoptLong.new(
|
24
|
-
[ '--gentleman','-G', GetoptLong::NO_ARGUMENT],
|
25
|
-
[ '--
|
26
|
-
[ '--
|
27
|
-
[ '--
|
25
|
+
[ '--gentleman', '-G', GetoptLong::NO_ARGUMENT],
|
26
|
+
[ '--interactive','-I', GetoptLong::NO_ARGUMENT],
|
27
|
+
[ '--interactive-url', '-u', GetoptLong::REQUIRED_ARGUMENT],
|
28
|
+
[ '--interactive-pwd', '-p', GetoptLong::REQUIRED_ARGUMENT],
|
29
|
+
[ '--csv', '-C', GetoptLong::NO_ARGUMENT],
|
30
|
+
[ '--version', '-v', GetoptLong::NO_ARGUMENT],
|
31
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT]
|
28
32
|
)
|
29
33
|
|
30
34
|
opts.quiet=true
|
@@ -32,6 +36,12 @@ opts.quiet=true
|
|
32
36
|
begin
|
33
37
|
opts.each do |opt, val|
|
34
38
|
case opt
|
39
|
+
when '--interactive'
|
40
|
+
scanning_mode = :interactive
|
41
|
+
when '--interactive-url'
|
42
|
+
interactive[:url] = val
|
43
|
+
when '--interactive-pwd'
|
44
|
+
interactive[:pwd] = val
|
35
45
|
when '--version'
|
36
46
|
puts "#{Wordstress::VERSION}"
|
37
47
|
Kernel.exit(0)
|
@@ -63,7 +73,7 @@ trap("INT") { $logger.die('[INTERRUPTED]') }
|
|
63
73
|
$logger.die("missing target") if target.nil?
|
64
74
|
|
65
75
|
$logger.log "scanning #{target}"
|
66
|
-
site = Wordstress::Site.new({:target=>target, :scanning_mode=>scanning_mode})
|
76
|
+
site = Wordstress::Site.new({:target=>target, :scanning_mode=>scanning_mode, :interactive=>interactive})
|
67
77
|
|
68
78
|
if site.version[:version] == "0.0.0"
|
69
79
|
$logger.err "can't detect wordpress version running on #{target}. Giving up!"
|
data/lib/wordstress/site.rb
CHANGED
@@ -5,7 +5,7 @@ module Wordstress
|
|
5
5
|
|
6
6
|
attr_reader :version, :scanning_mode, :wp_vuln_json, :plugins, :themes, :themes_vuln_json
|
7
7
|
|
8
|
-
def initialize(options={:target=>"http://localhost", :scanning_mode=>:gentleman})
|
8
|
+
def initialize(options={:target=>"http://localhost", :scanning_mode=>:gentleman, :interactive=>{}})
|
9
9
|
begin
|
10
10
|
@uri = URI(options[:target])
|
11
11
|
@raw_name = options[:target]
|
@@ -24,6 +24,8 @@ module Wordstress
|
|
24
24
|
@wp_vuln_json = get_wp_vulnerabilities unless @version[:version] == "0.0.0"
|
25
25
|
@wp_vuln_json = Hash.new.to_json if @version[:version] == "0.0.0"
|
26
26
|
|
27
|
+
@wordstress_page = post_and_get(options[:interactive][:url], options[:interactive][:pwd]) if options[:scanning_mode] == :interactive && !options[:interactive][:pwd].empty?
|
28
|
+
@wordstress_page = get(options[:interactive][:url]) if options[:scanning_mode] == :interactive && options[:interactive][:pwd].empty?
|
27
29
|
@plugins = find_plugins
|
28
30
|
@themes = find_themes
|
29
31
|
# @themes_vuln_json = get_themes_vulnerabilities
|
@@ -99,9 +101,13 @@ module Wordstress
|
|
99
101
|
|
100
102
|
v_rss = ""
|
101
103
|
rss_doc = Nokogiri::HTML(@homepage.body)
|
102
|
-
|
104
|
+
begin
|
105
|
+
rss = Nokogiri::HTML(get(rss_doc.css('link[type="application/rss+xml"]').first.attr('href')).body) unless l.nil?
|
106
|
+
v_rss= rss.css('generator').text.split('=')[1]
|
107
|
+
rescue => e
|
108
|
+
v_rss = "0.0.0"
|
109
|
+
end
|
103
110
|
|
104
|
-
v_rss= rss.css('generator').text.split('=')[1]
|
105
111
|
|
106
112
|
return {:version => v_meta, :accuracy => 1.0} if v_meta == v_readme && v_meta == v_rss
|
107
113
|
return {:version => v_meta, :accuracy => 0.8} if v_meta == v_readme || v_meta == v_rss
|
@@ -123,11 +129,13 @@ module Wordstress
|
|
123
129
|
end
|
124
130
|
|
125
131
|
def find_themes
|
126
|
-
return find_themes_gentleman
|
132
|
+
return find_themes_gentleman if @scanning_mode == :gentleman
|
133
|
+
return find_themes_interactive if @scanning_mode == :interactive
|
127
134
|
return []
|
128
135
|
end
|
129
136
|
def find_plugins
|
130
137
|
return find_plugins_gentleman if @scanning_mode == :gentleman
|
138
|
+
return find_plugins_interactive if @scanning_mode == :interactive
|
131
139
|
|
132
140
|
# bruteforce check must start with error page discovery.
|
133
141
|
# the idea is to send 2 random plugin names (e.g. 2 sha256 of time seed)
|
@@ -136,14 +144,42 @@ module Wordstress
|
|
136
144
|
return []
|
137
145
|
end
|
138
146
|
|
147
|
+
def post_and_get(url, pass)
|
148
|
+
uri = URI(url)
|
149
|
+
res = Net::HTTP.post_form(uri, {'post_password' => pass, 'Submit'=>'Submit'})
|
150
|
+
get(url)
|
151
|
+
res.body
|
152
|
+
end
|
153
|
+
|
139
154
|
private
|
155
|
+
def find_plugins_interactive
|
156
|
+
ret = []
|
157
|
+
doc = Nokogiri::HTML(@wordstress_page.body)
|
158
|
+
doc.css('#all_plugin').each do |link|
|
159
|
+
l=link.text.split(',')
|
160
|
+
ret << {:name=>l[2], :version=>l[1], :status=>l[3]}
|
161
|
+
end
|
162
|
+
$logger.debug ret
|
163
|
+
ret
|
164
|
+
end
|
165
|
+
def find_themes_interactive
|
166
|
+
ret = []
|
167
|
+
doc = Nokogiri::HTML(@wordstress_page.body)
|
168
|
+
doc.css('#all_theme').each do |link|
|
169
|
+
l=link.text.split(',')
|
170
|
+
ret << {:name=>l[2], :version=>l[1]}
|
171
|
+
end
|
172
|
+
$logger.debug ret
|
173
|
+
ret
|
174
|
+
end
|
175
|
+
|
140
176
|
def find_themes_gentleman
|
141
177
|
ret = []
|
142
178
|
doc = Nokogiri::HTML(@homepage.body)
|
143
179
|
doc.css('link').each do |link|
|
144
180
|
if link.attr('href').include?("wp-content/themes")
|
145
181
|
theme = theme_name(link.attr('href'))
|
146
|
-
ret << theme if ret.index(theme).nil?
|
182
|
+
ret << {:name=>theme, :version=>""} if ret.index(theme).nil?
|
147
183
|
end
|
148
184
|
end
|
149
185
|
ret
|
@@ -163,7 +199,7 @@ module Wordstress
|
|
163
199
|
if ! link.attr('src').nil?
|
164
200
|
if link.attr('src').include?("wp-content/plugins")
|
165
201
|
plugin = plugin_name(link.attr('src'))
|
166
|
-
ret << plugin if ret.index(plugin).nil?
|
202
|
+
ret << {:name=>plugin, :version=>"", :status=>"active"} if ret.index(plugin).nil?
|
167
203
|
end
|
168
204
|
end
|
169
205
|
end
|
data/lib/wordstress/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wordstress
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paolo Perego
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|