Skip to content

Stream Control Transmission Protocol (SCTP)#56

Merged
adfoster-r7 merged 1 commit intorapid7:masterfrom
sempervictus:feature/sctp_sockets
Feb 6, 2023
Merged

Stream Control Transmission Protocol (SCTP)#56
adfoster-r7 merged 1 commit intorapid7:masterfrom
sempervictus:feature/sctp_sockets

Conversation

@sempervictus
Copy link
Copy Markdown

RFC: https://www.rfc-editor.org/rfc/rfc4960.html

Define constants for SCTP in ::Socket namespace for IPPPROTO
and SOL.
Create param definitions and socket marshalling using the newly
defined constants.
Implement stream-server mechanics for SctpServer from TcpServer
extending the clients with Rex::Socket::Sctp upon connection.

Testing:

svr = Rex::Socket::SctpServer.create(
  'LocalHost' => '127.0.0.1', 'LocalPort' => 8888
)
csock = nil
Thread.new { csock = svr.accept }
cli = Rex::Socket::Sctp.create(
  'PeerHost' => '127.0.0.1', 'PeerPort' => 8888
)
cli.write("test\n")
csock.gets
$stdout.write(File.read('/proc/net/sctp/eps'))

Notes:
No idea how/whether this is going to work on non-Linux hosts
Meterpreters will need SCTPs implementation to pivot, along with the relevant encapsulation and relay mechanics within TLVs.

@adfoster-r7
Copy link
Copy Markdown
Contributor

Looks like you're pulling in some commits that are already landed to master; I think a rebase will fix that

@sempervictus
Copy link
Copy Markdown
Author

Ping @hdm and skape (can't seem to find a GH handle which is mildly ironic): i did this in an hour this morning and it dawns on me that there had to be some reason why the founders didn't - obviously there aren't any comments to find on code that doesn't exist, so hoping you might recall whether this was discussed and why it wasn't implemented if it was.
It works in naive testing, seems to use the correct L4 stack, and operates like TCP so it probably worked before i rewired the Stream/IO abstractions for stateless sockets. Is there some elephant in the room which i'm not seeing (other than Windows not having SCTP sockets natively)?

Ping @zeroSteiner, @OJ, @timwr regarding relevant meterpreter types and discussion re implementing the pivot infrastructure in the various meterps you gents maintain.

Far as SCTP compatibility for Framework-side, looks like SCTPLabs has a usermode SCTP implementation which is cross-platform @ https://github.com/sctplab/usrsctp

@sempervictus
Copy link
Copy Markdown
Author

Looks like you're pulling in some commits that are already landed to master; I think a rebase will fix that

Pardon, all set.

@sempervictus sempervictus mentioned this pull request Jan 18, 2023
2 tasks
sempervictus pushed a commit to sempervictus/metasploit-framework that referenced this pull request Jan 19, 2023
With the introduction of SCTP socket support in Rex::Socket via
rapid7/rex-socket#56, Framework can utilize
this protocol for session transports similarly to  TCP as it is a
stream-wise transport. Netstat doesn't show SCTP sockets (on Linux
anyway), but any NIDS and flow monitors might notice that "this
one is not like the others."

Implement bind and reverse handlers for the new socket type.
Implement example bind and reverse payloads using socat copying
from the initial udp sessions implementation.

Testing:
  Rudimentary bind session test against local Libvirt Linux VM

Next steps:
  Implement the language-level payloads for the interpreters common
to POSIX environments supporting SCTP.
  Implement meterpreter transports for SCTP in Python, PHP, Mettle,
and Java modalities (Windows doesn't support it without carrying
its own usermode protocol library).
sempervictus pushed a commit to sempervictus/metasploit-framework that referenced this pull request Jan 19, 2023
With the introduction of SCTP socket support in Rex::Socket via
rapid7/rex-socket#56, Framework can utilize
this protocol for session transports similarly to  TCP as it is a
stream-wise transport.

Implement bind and reverse handlers for the new socket type.
Implement example bind and reverse payloads using socat copying
from the initial udp sessions implementation.

Testing:
  Rudimentary bind session test against local Libvirt Linux VM

Next steps:
  Implement the language-level payloads for the interpreters common
to POSIX environments supporting SCTP.
  Implement meterpreter transports for SCTP in Python, PHP, Mettle,
and Java modalities (Windows doesn't support it without carrying
its own usermode protocol library).
sempervictus pushed a commit to sempervictus/metasploit-framework that referenced this pull request Jan 19, 2023
With the introduction of SCTP socket support in Rex::Socket via
rapid7/rex-socket#56, Framework can utilize
this protocol for session transports similarly to  TCP as it is a
stream-wise transport.

Implement bind and reverse handlers for the new socket type.
Implement example bind and reverse payloads using socat copying
from the initial udp sessions implementation.

Testing:
  Rudimentary bind session test against local Libvirt Linux VM

Next steps:
  Implement the language-level payloads for the interpreters common
to POSIX environments supporting SCTP.
  Implement meterpreter transports for SCTP in Python, PHP, Mettle,
and Java modalities (Windows doesn't support it without carrying
its own usermode protocol library).
sempervictus pushed a commit to sempervictus/metasploit-framework that referenced this pull request Jan 19, 2023
With the introduction of SCTP socket support in Rex::Socket via
rapid7/rex-socket#56, Framework can utilize
this protocol for session transports similarly to  TCP as it is a
stream-wise transport.

Implement bind and reverse handlers for the new socket type.
Implement example bind and reverse payloads using socat copying
from the initial udp sessions implementation.

Testing:
  Rudimentary bind session test against local Libvirt Linux VM

Next steps:
  Implement the language-level payloads for the interpreters common
to POSIX environments supporting SCTP.
  Implement meterpreter transports for SCTP in Python, PHP, Mettle,
and Java modalities (Windows doesn't support it without carrying
its own usermode protocol library).
sempervictus pushed a commit to sempervictus/metasploit-framework that referenced this pull request Jan 19, 2023
With the introduction of SCTP socket support in Rex::Socket via
rapid7/rex-socket#56, Framework can utilize
this protocol for session transports similarly to  TCP as it is a
stream-wise transport.

Implement bind and reverse handlers for the new socket type.
Implement example bind and reverse payloads using socat copying
from the initial udp sessions implementation.

Testing:
  Rudimentary bind session test against local Libvirt Linux VM

Next steps:
  Implement the language-level payloads for the interpreters common
to POSIX environments supporting SCTP.
  Implement meterpreter transports for SCTP in Python, PHP, Mettle,
and Java modalities (Windows doesn't support it without carrying
its own usermode protocol library).
@sempervictus
Copy link
Copy Markdown
Author

@adfoster-r7 - we gotta land this for the framework side (new shells!!) to get reviewed. Who's taking this one? You? Come at me bro! 😁

@adfoster-r7
Copy link
Copy Markdown
Contributor

adfoster-r7 commented Feb 3, 2023

Looks like SCTP wouldn't work on windows:

irb(main):003:0> s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 132)
(irb):3:in `initialize': The requested protocol has not been configured into the system, or no implementation for it exists. - socket(2) (Errno::EPROTONOSUPPORT)
        from (irb):3:in `new'
        from (irb):3:in `<main>'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/irb-1.3.6/exe/irb:11:in `<top (required)>'
        from C:/Ruby30-x64/bin/irb:25:in `load'
        from C:/Ruby30-x64/bin/irb:25:in `<main>'

Or Mac:

2.7.2 :013 > require 'socket'
 => true 
2.7.2 :014 > s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 132)
Traceback (most recent call last):
        23: from /Users/user/.rvm/gems/ruby-2.7.2/bin/ruby_executable_hooks:22:in `<main>'           
        22: from /Users/user/.rvm/gems/ruby-2.7.2/bin/ruby_executable_hooks:22:in `eval'             
        21: from /Users/user/.rvm/gems/ruby-2.7.2/bin/irb:23:in `<main>'                             
        20: from /Users/user/.rvm/gems/ruby-2.7.2/bin/irb:23:in `load'                               
        19: from /Users/user/.rvm/gems/ruby-2.7.2/gems/irb-1.6.2/exe/irb:11:in `<top (required)>'    
         2: from (irb):14:in `<main>'                                                                    
         1: from (irb):14:in `new'                                                                       
(irb):14:in `initialize': Protocol not supported - socket(2) (Errno::EPROTONOSUPPORT)

But I was able to create a socket for the linux-y boxes I checked, such as ubuntu 2016, and centos 7, alpine 3.14 with a simple test script. Mac returned -1, all the other targets gave a valid fd back

#include <stdio.h>
#include <sys/socket.h>

int main() {
  int listenfd;

  listenfd = socket(AF_INET, SOCK_STREAM, 132);

  printf("fd: %d\n", listenfd);
}

It would be great if there was wider support; but it looks like it's still a lot of targets that it could work against

Copy link
Copy Markdown
Contributor

@adfoster-r7 adfoster-r7 left a comment

Choose a reason for hiding this comment

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

I think we if we move the constants to rex socket, I'd be good with these changes - it's mostly copied from the existing tcp files

Comment thread lib/rex/socket.rb Outdated
Comment thread lib/rex/socket/sctp.rb
class ::Socket
IPPROTO_SCTP = 132
SOL_SCTP = 132
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thoughts on adding these constants to ::Rex::Socket instead?

Copy link
Copy Markdown
Author

@sempervictus sempervictus Feb 5, 2023

Choose a reason for hiding this comment

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

At the end of the day, Rex::Sockets are still Sockets so i figure the constant belongs with the rest of them. No objection to moving if we have a good reason.
The actual namespace where IPPROTO_* and SOL_* constants are defined in Ruby is ::Socket:: - parallel to where you find the SCTP constants in languages which define it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The rationale behind the comment was - we shouldn't patch core files we don't own, that's why ::Rex::Socket exists in the first place right?

There's also load order issues if a module ends up depending on this patched ::Socket constant, but this file hasn't been loaded etc

Copy link
Copy Markdown
Author

@sempervictus sempervictus Feb 5, 2023

Choose a reason for hiding this comment

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

Kind of? Rex::Socket is really a factory for the dynamic dispatch of API-consistent "virtual wiring" but it uses ::Socket for "everything" under the skin. If you're worried about namespace corruption, just take a look at .class.ancestors in almost any Msf object - some of the gems we pull in do things that make my work look downright pristine 😉
IMO, I'm not so much corrupting someone else's namespace as i'm fixing a missing element in their implementation - that's a real Socket class per the RFC, and they just neglected to define the constant.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'll treat this as not a blocker, but I'm not a massive fan of the pattern

Comment thread lib/rex/socket/sctp.rb
elsif param.proto == 'sctp'
klass = Rex::Socket::SctpServer
else
raise Rex::BindFailed.new(param.localhost, param.localport), caller
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not a blocker: I think this is the right exception to raise here, but I worry it might be hard to debug if this code path ever triggers as it's probably caught and silently ignored in some cases in framework

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If that is the case, (IMO) we should fix it higher up in the stack where it is erroneously ignored.
I look at Rex as the "kernel" of Metasploit which needs to be consistent and informative as much as possible, especially going down to the core (Socket, IO, Event, locking, all that fun junk). That said, Errors are Objects too and we can do whatever we want with them - like mixing in/extending with an ancestor which will increase chances of trapping on Socket errors...

RFC: https://www.rfc-editor.org/rfc/rfc4960.html

Define constants for SCTP in ::Socket namespace for IPPPROTO
and SOL.
Create param definitions and socket marshalling using the newly
defined constants.
Implement stream-server mechanics for SctpServer from TcpServer
extending the clients with Rex::Socket::Sctp upon connection.

Testing:
```ruby
  svr = Rex::Socket::SctpServer.create(
    'LocalHost' => '127.0.0.1', 'LocalPort' => 8888
  )
  csock = nil
  Thread.new { csock = svr.accept }
  cli = Rex::Socket::Sctp.create(
    'PeerHost' => '127.0.0.1', 'PeerPort' => 8888
  )
  cli.write("test\n")
  csock.gets
  $stdout.write(File.read('/proc/net/sctp/eps'))
```

Notes:
  No idea how/whether this is going to work on non-Linux hosts
  Meterpreters will need SCTPs implementation to pivot, along
with the relevant encapsulation and relay mechanics within TLVs.
@sempervictus
Copy link
Copy Markdown
Author

Regarding OS support, from what i can tell, it's any moderately modern Linux (Android is an open question), any FreeBSD after 7 (which to me implies HBSD as well, but i'll test that theory to make sure), as well as Solaris 10+.
Macs had an NKE up to 10.13, but i think that the way to go nowadays would be https://github.com/sctplab/usrsctp. Same goes for Windows, and would need to be implemented inside Meterpreter/Mettle since its a binary object (unless someone knows of a way to carry those into Py/PHP/Java execution space correctly).

@adfoster-r7 adfoster-r7 merged commit bb13947 into rapid7:master Feb 6, 2023
@sempervictus
Copy link
Copy Markdown
Author

Thanks boss.
Given that we're one of the biggest Ruby projects out there, maybe its not a bad idea for us to reach out to whatever Ruby's version of a steering committee is and ask them what the right way to do things is from their point of view. Commits going in here are not likely to be touched (or seen) by another soul for quite a while, but being infrastructure code, everything runs atop it...

sempervictus pushed a commit to sempervictus/metasploit-framework that referenced this pull request Feb 9, 2023
With the introduction of SCTP socket support in Rex::Socket via
rapid7/rex-socket#56, Framework can utilize
this protocol for session transports similarly to  TCP as it is a
stream-wise transport.

Implement bind and reverse handlers for the new socket type.
Implement example bind and reverse payloads using socat copying
from the initial udp sessions implementation.

Testing:
  Rudimentary bind session test against local Libvirt Linux VM

Next steps:
  Implement the language-level payloads for the interpreters common
to POSIX environments supporting SCTP.
  Implement meterpreter transports for SCTP in Python, PHP, Mettle,
and Java modalities (Windows doesn't support it without carrying
its own usermode protocol library).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants