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

Socket leak: HTTP service not dereferenced #16315

Closed
smashery opened this issue Mar 8, 2022 · 0 comments
Closed

Socket leak: HTTP service not dereferenced #16315

smashery opened this issue Mar 8, 2022 · 0 comments
Assignees
Labels

Comments

@smashery
Copy link
Contributor

smashery commented Mar 8, 2022

Background

When certain services are run within Metasploit (mainly payload handlers, but others as well), they use the "Service Manager", which manages lifetime, including sharing a service instance between multiple jobs.

The bug

When stopping a service run by the service manager, the process should be as follows:

  • Call the ServiceManager's stop_service static method
  • It will call the module's stop_service instance method
  • It will call the service's deref instance method
  • If this is the last reference to it, it will call the ServiceManager's stop_service static method (again) - I guess because the ServiceManager itself has a reference to it, so we use that special knowledge to remove that one remaining reference. Then it'll return true to say it actually stopped.

This process is violated by the HTTP service handler, which seemingly does not trust the reference counting functionality. Instead, it inspects its own internals and realises "Other resources are still registered on this handler, I'd better not stop the service". This means it chooses not to call stop_service (seemingly presuming that stop_service will actually stop the service... I guess I can understand the confusion). This means that the job terminates, but the service is not dereferenced. The result is that, if you launch the HTTP service twice, with different LURIs, killing one of these jobs will not dereference the service. Killing the second job will dereference it, thus leaving the reference count one higher than it should be, and thus the port is held open indefinitely.

msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload linux/x64/meterpreter_reverse_http
payload => linux/x64/meterpreter_reverse_http
msf6 exploit(multi/handler) > set lport 8080
lport => 8080
msf6 exploit(multi/handler) > set lhost 0.0.0.0
lhost => 0.0.0.0
msf6 exploit(multi/handler) > run -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started HTTP reverse handler on http://0.0.0.0:8080
msf6 exploit(multi/handler) > set luri abc
luri => abc
msf6 exploit(multi/handler) > run -j
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.

[*] Started HTTP reverse handler on http://0.0.0.0:8080/abc
msf6 exploit(multi/handler) > jobs

Jobs
====

  Id  Name                    Payload                             Payload opts
  --  ----                    -------                             ------------
  0   Exploit: multi/handler  linux/x64/meterpreter_reverse_http  http://0.0.0.0:8080
  1   Exploit: multi/handler  linux/x64/meterpreter_reverse_http  http://0.0.0.0:8080/abc

msf6 exploit(multi/handler) > jobs -k 0
[*] Stopping the following job(s): 0
[*] Stopping job 0
msf6 exploit(multi/handler) > jobs -k 1
[*] Stopping the following job(s): 1
[*] Stopping job 1
msf6 exploit(multi/handler) > jobs

Jobs
====

No active jobs.

msf6 exploit(multi/handler) > run -j
[*] Exploit running as background job 2.
[*] Exploit completed, but no session was created.

[-] Handler failed to bind to 0.0.0.0:8080
[-] Handler failed to bind to 0.0.0.0:8080
[-] Exploit failed [bad-config]: Rex::BindFailed The address is already in use or unavailable: (0.0.0.0:8080).

Sessions are complicit in this circumvention of process, in that they also do a dereference (from the shutdown_passive_dispatcher method), but never add a reference in the first place. It turns out that in this situation, two wrongs kind of make a right, since they won't do a dereference while a resource is attached to the server, and the server won't do a dereference while a session is attached to the handler. Effectively, we have an implicit reference counting implementation on top of our reference counting implementation. There's probably a race condition there if a session ends while a job is being terminated, or if two sessions end at the same time; they would both see each other and choose not to dereference; but it's probably also unlikely. Nonetheless, we have to be aware of this when making a fix.

@smashery smashery added the bug label Mar 8, 2022
@smashery smashery self-assigned this Mar 8, 2022
@smashery smashery mentioned this issue Mar 9, 2022
2 tasks
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant