Skip to content
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

Fix crashes on timeouts for multiple modules and Meterpreter #16491

Merged
merged 1 commit into from
May 5, 2022

Conversation

adfoster-r7
Copy link
Contributor

@adfoster-r7 adfoster-r7 commented Apr 23, 2022

Before

msf6 auxiliary(scanner/winrm/winrm_login) > run  http://user:pass@192.168.123.139:5985

[!] No active DB -- Credential data will not be saved!
[+] 192.168.123.139:5985 - Login Successful: WORKSTATION\user:p4$$w0rd
[*] Command shell session 2 opened (192.168.123.1:58619 -> 192.168.123.139:5985 ) at 2022-04-23 02:33:27 +0100
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/winrm/winrm_login) > [*] 192.168.123.139 - Command shell session 2 closed.  Reason: uninitialized constant Msf::Sessions::WinrmCommandShell::WinRMStreamAdapter::TimeoutError

After

msf6 auxiliary(scanner/winrm/winrm_login) > run http://user:pass@192.168.123.139:5985

[!] No active DB -- Credential data will not be saved!
[+] 192.168.123.139:5985 - Login Successful: WORKSTATION\user:pass
[*] Command shell session 7 opened (192.168.123.1:58673 -> 192.168.123.139:5985 ) at 2022-04-23 02:36:34 +0100
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/winrm/winrm_login) > sessions -i -1
[*] Starting interaction with 7...

Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.

C:\Users\user>

Verification

Either run this module against a machines machine with WinRM enabled, and verify the other modules too.
Or verify the specific timeout exception semantics various Ruby versions.

Create a test file foo.rb

begin
  require 'timeout'
  Timeout.timeout(0.1) { sleep 1 }
rescue TimeoutError
  puts "Successfully caught timeout #{$!.class}"
end

Run against different ruby versions, 2.4:

$ docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:2.4-alpine /bin/sh -c 'ruby foo.rb'   
foo.rb:4: warning: constant ::TimeoutError is deprecated
Successfully caught timeout Timeout::Error

2.7

$ docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:2.7-alpine /bin/sh -c 'ruby foo.rb'
Successfully caught timeout Timeout::Error

3.0.x

$ docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:3-alpine /bin/sh -c 'ruby foo.rb'
foo.rb:4:in `rescue in <main>': uninitialized constant TimeoutError (NameError)

rescue TimeoutError
       ^^^^^^^^^^^^
        from foo.rb:1:in `<main>'
foo.rb:3:in `sleep': execution expired (Timeout::Error)
        from foo.rb:3:in `block in <main>'
        from /usr/local/lib/ruby/3.1.0/timeout.rb:123:in `timeout'
        from foo.rb:3:in `<main>'

Fix working in Ruby 3.x:

begin
  require 'timeout'
  Timeout.timeout(0.1) { sleep 1 }
rescue ::Timeout::Error
  puts "Successfully caught timeout #{$!.class}"
end
docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:3-alpine /bin/sh -c 'ruby foo.rb'
Successfully caught timeout Timeout::Error

Fix still working in Ruby 2.4:

docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:2.4-alpine /bin/sh -c 'ruby foo.rb'
Successfully caught timeout Timeout::Error

Comment on lines 178 to 179
if timeout.nil?
return nil
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -1208,7 +1208,7 @@ def cmd_migrate(*args)

begin
server = client.sys.process.open
rescue TimeoutError => e
rescue Rex::TimeoutError, ::Timeout::Error => e
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably this was intended to catch the exceptions raised by lib/rex/post/meterpreter/packet_dispatcher.rb within the send_request method - fixed above. I've decided to catch both Rex::TimeoutError and Timeout::Error here for simplicity.

@adfoster-r7
Copy link
Contributor Author

adfoster-r7 commented Apr 23, 2022

Actually; This rabbit hole goes deeper than expected - will draft for now.

Edit: Resolved #16491 (comment)

@adfoster-r7 adfoster-r7 marked this pull request as draft April 23, 2022 02:38
@adfoster-r7 adfoster-r7 marked this pull request as ready for review May 4, 2022 08:44
@gwillcox-r7 gwillcox-r7 self-assigned this May 5, 2022
@gwillcox-r7
Copy link
Contributor

Seems to be working fine to me:

Before changes:

 ~/git/metasploit-framework │ master ?25  nano foo.rb                 ✔ │ 3s │ 3.0.2 Ruby 
 ~/git/metasploit-framework │ master ?26  sudo docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:2.4-alpine /bin/sh -c 'ruby foo.rb'  
[sudo] password for gwillcox: 
Unable to find image 'ruby:2.4-alpine' locally
2.4-alpine: Pulling from library/ruby
aad63a933944: Pull complete 
cca28d9d22b9: Pull complete 
e46ee7bc75f6: Pull complete 
77f6ac0a75a8: Pull complete 
7d7702b298dc: Pull complete 
Digest: sha256:e81f81a1212ead9850417aaabe9787bafec62d5ecbc93000bd5422ba6042600d
Status: Downloaded newer image for ruby:2.4-alpine
foo.rb:4: warning: constant ::TimeoutError is deprecated
Successfully caught timeout Timeout::Error
 ~/git/metasploit-framework │ master ?26  sudo docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:2.7-alpine /bin/sh -c 'ruby foo.rb'

Unable to find image 'ruby:2.7-alpine' locally
2.7-alpine: Pulling from library/ruby
df9b9388f04a: Pull complete 
837e9cfc7e43: Pull complete 
c7850f1a8c23: Pull complete 
2f1b0fc20e43: Pull complete 
f56d8c6ef3c8: Pull complete 
Digest: sha256:7752f70e7a50dcf4892bd3427c3ef8dd5bc100169deeecfc7d07db67b52d81bc
Status: Downloaded newer image for ruby:2.7-alpine
Successfully caught timeout Timeout::Error
 ~/git/metasploit-framework │ master ?26  docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:3-alpine /bin/sh -c 'ruby foo.rb'
docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/create": dial unix /var/run/docker.sock: connect: permission denied.
See 'docker run --help'.
 ~/git/metasploit-framework │ master ?26  sudo docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:3-alpine /bin/sh -c 'ruby foo.rb'
Unable to find image 'ruby:3-alpine' locally
3-alpine: Pulling from library/ruby
df9b9388f04a: Already exists 
837e9cfc7e43: Already exists 
c7850f1a8c23: Already exists 
ae0a3cc0f34c: Pull complete 
81637037ea3a: Pull complete 
Digest: sha256:0b91e98c4613c2287bb7274a1584ea141b68960fb6b0edd7fe32127dc888d1a0
Status: Downloaded newer image for ruby:3-alpine
foo.rb:4:in `rescue in <main>': uninitialized constant TimeoutError (NameError)

rescue TimeoutError
       ^^^^^^^^^^^^
	from foo.rb:1:in `<main>'
foo.rb:3:in `sleep': execution expired (Timeout::Error)
	from foo.rb:3:in `block in <main>'
	from /usr/local/lib/ruby/3.1.0/timeout.rb:123:in `timeout'
	from foo.rb:3:in `<main>'
 ~/git/metasploit-framework │ master ?26  cat foo.rb                1 х │ 6s │ 3.0.2 Ruby 
begin
  require 'timeout'
  Timeout.timeout(0.1) { sleep 1 }
rescue TimeoutError
  puts "Successfully caught timeout #{$!.class}"
end

After changes

 ~/git/metasploit-framework │ master ?26  nano foo2.rb                     ✔ │ 3.0.2 Ruby 
 ~/git/metasploit-framework │ master ?27  cat foo2.rb                 ✔ │ 9s │ 3.0.2 Ruby 
begin
  require 'timeout'
  Timeout.timeout(0.1) { sleep 1 }
rescue ::Timeout::Error
  puts "Successfully caught timeout #{$!.class}"
end
 ~/git/metasploit-framework │ master ?27  sudo docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:2.4-alpine /bin/sh -c 'ruby foo2.rb'  
Successfully caught timeout Timeout::Error
 ~/git/metasploit-framework │ master ?27  sudo docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:2.7-alpine /bin/sh -c 'ruby foo2.rb'

Successfully caught timeout Timeout::Error
 ~/git/metasploit-framework │ master ?27  sudo docker run -it --rm -w $(pwd) -v $(pwd):$(pwd) ruby:3-alpine /bin/sh -c 'ruby foo2.rb'  
Successfully caught timeout Timeout::Error
 ~/git/metasploit-framework │ master ?27  

@gwillcox-r7 gwillcox-r7 merged commit 0a86d07 into rapid7:master May 5, 2022
@gwillcox-r7 gwillcox-r7 added bug rn-fix release notes fix labels May 5, 2022
@gwillcox-r7
Copy link
Contributor

gwillcox-r7 commented May 5, 2022

Release Notes

This fixes a bug whereby Meterpreter sessions and modules would crash when encountering a timeout issue due to using an invalid or deprecated error name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug rn-fix release notes fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants