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

Add option to try to connect to a range of TCP ports #1119

Merged
merged 1 commit into from
Dec 17, 2024

Conversation

gerymate
Copy link
Contributor

@gerymate gerymate commented Oct 7, 2024

Add option to try to connect to a range of TCP ports

Fixes: #368
Fixes: #1117

Description

We can set an integer value with --port-range or RUBY_DEBUG_PORT_RANGE in addition to setting a TCP port for remote debugging. When port is unavailable, rdbg will try to open port + 1, port + 2, etc. until it finds a suitable port, or reaches the length of the range. This makes it possible to remote debug multiple debuggees in a multithreaded environment, but still use TCP ports in a determined way.

@gerymate
Copy link
Contributor Author

gerymate commented Nov 7, 2024

@ko1 sorry for disturbing, I'm new here. Who and how can I ask for some feedback?

@ko1
Copy link
Collaborator

ko1 commented Nov 7, 2024

Thank you for pinging me.

I'm not a network and security expert, but is it safe to try to connect not specific port?

My malicious scenario is:

  1. Attacker opens a port X
  2. Debuggee uses port range X to X+10, and choose X+1 (because X is used by attacker's process)
  3. Debugger connect with port range X to X+10 and connect to attacker's process (port X)
  4. Attacker can snoop any messages by proxying to debuggee port (X+1).

@gerymate
Copy link
Contributor Author

gerymate commented Nov 13, 2024

I'm not a security expert either, however, I don't see additional security risk from trying a port range.

  • The attacker can't open a port X without already being able to execute arbitrary code on the target machine with rights to open a port (as occupying a port can not be initiated from "outside", just from inside).
  • When the above fails and the debugger connects to the port the attacker opened, it is still used as a one-to-one connection. I don't know the internals there, but I think the debugger has the responsibility to initiate the connection (at least in DAP), issues commands, and the attacker's process can only mimic a debuggee and reply according to the DAP, but can't query the debugger process, the flow of the communication is the other way around.

Unless there are security flaws in DAP or CDP, I don't see how could the attacker proxy traffic to another port. However, I consider the first reason to be the strongest: the developer's responsibility is to secure the dev box, it's not the task of the debug tool.

@duerst
Copy link
Member

duerst commented Nov 14, 2024

I'm not really a network expert, nor a debugging expert, but something like --port-range 10000 doesn't look good to me. It may be seen as an attack (port scanning). I'd suggest to limit --port-range to some maximum (e.g. 100 or 256 or so).

@ko1
Copy link
Collaborator

ko1 commented Nov 14, 2024

I'm not a security expert either, however, I don't see additional security risk from trying a port range.

  • The attacker can't open a port X without already being able to execute arbitrary code on the target machine with rights to open a port (as occupying a port can not be initiated from "outside", just from inside).

For example, on a shared machine (many users share a one machine. not seen now a day), attacker can open the port.

  • When the above fails and the debugger connects to the port the attacker opened, it is still used as a one-to-one connection. I don't know the internals there, but I think the debugger has the responsibility to initiate the connection (at least in DAP), issues commands, and the attacker's process can only mimic a debuggee and reply according to the DAP, but can't query the debugger process, the flow of the communication is the other way around.

attacker's process can search correct port (X+1 for example) and it can be a proxy to X+1. Debugging protocol is simple text messaging and easy to scan.

Anyway, we are not expert, could you find other examples such mechanism?

@gerymate
Copy link
Contributor Author

I've updated the PR based on @duerst's feedback. The use case for this feature is to be able to reliably debug in a container where multiple worker threads are created. In our case, we use it for a Rails app running in a container, and we want to be able to debug both the main thread, the worker threads, and also to be able to run Rails console in the the context of the container (which, when debug is enabled by an ENV var, already starts two threads) or RSpec. Currently we could set PORT to 0 and thus have random ports opened, but it makes unnecessary hard to find those ports.

There are many examples of using similar mechanism for reliably connecting to applications. For example KDE Connect uses dynamic ports in a port range (see docs). Discord is using a port range for local RPC server. Microsoft and Apple uses it in various communication software (Teams, Silverlight and RTP/RTPC protocols), but those are mostly encrypted, so it's not that relevant here. Many multiplayer games use port ranges to find available ones.

Sorry, I still don't understand the proxy argument, as even when using port ranges there is only one port open during debugging by one debugger process. The port range just means that when X is already used, the debuggee will be listening on X+1 instead of X. The user has to choose one port for debugging (unless using a debugger tool that supports multiple remote debug sessions at the same time - I don't know if such system exists today or not). So a debug session either connects to the attacker's process, or one of the debuggees, but not both.

@ko1
Copy link
Collaborator

ko1 commented Dec 17, 2024

I see. I thought the debugger client (rdbg -A) also use a port range feature and it can connect to the attacker's port.

However, your proposal is only server side (opening ports on debuggee) and the opened port is printed on the debuggee's console.
And the debugger client needs to select the port which is printed on the debuggee's console.

Copy link

launchable-app bot commented Dec 17, 2024

Tests Failed

✖️7 tests failed ✔️662 tests passed(1 flake)

7/23 test sessions failed

❌ Test session #3564876 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564837 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️8 tests failed ✔️56 tests passed

❌ Test session #3564835 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564833 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564831 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564830 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564829 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

Copy link

Tests Failed

✖️7 tests failed ✔️69 tests passed

3/9 test sessions failed

❌ Test session #3564586 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564585 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564584 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

1 similar comment
Copy link

Tests Failed

✖️7 tests failed ✔️69 tests passed

3/9 test sessions failed

❌ Test session #3564586 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564585 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

❌ Test session #3564584 failedos:ubuntu-latest test_task:test_protocoldetails on CI
🔔 no issues ✖️7 tests failed ✔️57 tests passed

@ko1 ko1 merged commit affee18 into ruby:master Dec 17, 2024
21 of 28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants