-
Notifications
You must be signed in to change notification settings - Fork 14k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Winrm login workaround #13974
Winrm login workaround #13974
Conversation
@@ -246,7 +246,8 @@ def send_request(opts) | |||
begin | |||
cli.connect | |||
req = cli.request_cgi(opts) | |||
res = cli.send_recv(req) | |||
# Authenticate by default | |||
res = opts['authenticate'].nil? || opts['authenticate'] ? cli.send_recv(req) : cli._send_recv(req) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
res = opts['authenticate'].nil? || opts['authenticate'] ? cli.send_recv(req) : cli._send_recv(req) | |
res = if opts['authenticate'].nil? || opts['authenticate'] | |
cli.send_recv(req) | |
else | |
cli._send_recv(req) | |
end |
opts['authenticate'] = false | ||
allowed_auth_methods = parse_auth_methods(super(opts)) | ||
opts['authenticate'] = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This side effect was unexpected for me, maybe something like this is cleaner:
opts['authenticate'] = false | |
allowed_auth_methods = parse_auth_methods(super(opts)) | |
opts['authenticate'] = true | |
allowed_auth_methods = parse_auth_methods(super(opts.merge({ 'authenticate' => true })) |
But I don't have the full picture here to know if this is the best approach overall just yet
# send an HTTP request that WinRM would consider as valid (SOAP XML in the message matching the XML schema definition) | ||
def send_request(opts) | ||
opts['authenticate'] = false | ||
allowed_auth_methods = parse_auth_methods(super(opts)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be better off in a check_request
override to prevent doubling the volume of requests sent to the server.
@@ -9,6 +9,7 @@ module LoginScanner | |||
|
|||
# Windows Remote Management login scanner | |||
class WinRM < HTTP | |||
# include Msf::Exploit::Remote::WinRM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed still? 👀
lib/rex/proto/http/client.rb
Outdated
@@ -272,7 +272,6 @@ def send_auth(res, opts, t, persist) | |||
|
|||
# if several providers are available, the client may want one in particular | |||
preferred_auth = opts['preferred_auth'] | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this file be reverted? 👀
def parse_auth_methods(resp) | ||
return [] unless resp and resp.code == 401 | ||
methods = [] | ||
methods << "Negotiate" if resp.headers['WWW-Authenticate'].include? "Negotiate" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dwelch-r7 Under what circumstances will winrm return this header? I haven't found a target that sends this back yet. What target did you use? 👀
Edit: Found it https://docs.microsoft.com/en-us/windows/win32/winrm/authentication-for-remote-connections
# send an HTTP request that WinRM would consider as valid (SOAP XML in the message matching the XML schema definition) | ||
def send_request(opts) | ||
allowed_auth_methods = parse_auth_methods(super(opts.merge({ 'authenticate' => true }))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
allowed_auth_methods = parse_auth_methods(super(opts.merge({ 'authenticate' => true }))) | |
allowed_auth_methods = parse_auth_methods(super(opts.merge({ 'authenticate' => false }))) |
Typo, will fix
Tested successfully against metasploitable3, a windows 7 target, and the original box from #13839 Valid credentials:
Output:
Invalid credentials working as expected:
As a sanity test, I checked
|
Release NotesImproved the |
This still sends two requests to the WinRM server per credential pair. Was there a reason that the |
@acammack-r7 I took a look at the
seems to be intended more for checking that the scanner can actually run rather than for setting options per server |
It would be an error if the server wanted an authentication method we didn't support or we weren't configured to connect with, correct? We already check that there are authentication methods in metasploit-framework/lib/metasploit/framework/login_scanner/http.rb Lines 197 to 198 in d300ddb
That would also be a reasonable place to set an instance variable and make sure that we use an expected authentication. For an example, see the Glassfish scanner which auto-detects SSL:
This code as-is creates a large performance regression for this scanner since it doubles the time it takes to run. |
@acammack-r7 We can circle back to this, for now the module was pretty broke - so a performance regression wasn't a priority in comparison to making it work 📈 |
if allowed_auth_methods.include? 'Negotiate' | ||
opts['preferred_auth'] = 'Negotiate' | ||
elsif allowed_auth_methods.include? 'Basic' | ||
# Straight up hack since if Basic auth is used winrm complains about the content size being 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we set it to 1 and give them a null byte instead?
This PR fixes an issue where the winrm login scanner was failing to authenticate with serves that did not accept 'Basic' authentication.
The issues arose from a recent PR which made an attempt to fix logging into winrm servers with 'Basic' authentication here #13442
The data this PR added to the request caused logging into winrm with anything other than 'Basic' authentication to fail
This PR addresses this issue in a couple ways