-
Notifications
You must be signed in to change notification settings - Fork 317
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
WIP - New interface for modules to given greater control over connection (L4/TLS/etc) establishment #498
base: master
Are you sure you want to change the base?
Conversation
return d.DefaultDialer(ctx, target) | ||
} | ||
|
||
func (d *DialerGroup) SetDefaultDialer(dialer func(ctx context.Context, target *ScanTarget) (net.Conn, error)) { |
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.
It seems a bit weird that this is specific to a target if it's the default. Can we just call this once at the initiation of ZGrab?
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.
Well, the DefaultDialer
is used for the "base case" when protocols don't care about their transport. And in the case that we want to run the protocol over TLS, we'll need the target.Domain
for SNI in the handshake.
What I have currently is the modules provide their DefaultDialer
in Init
, so only once. This defines their default behavior since only the modules know the value of the specific Flags. The Fox
module has a good, simple example: here.
@@ -165,39 +173,27 @@ func (scanner *Scanner) Protocol() string { | |||
return "amqp091" | |||
} | |||
|
|||
func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, any, error) { | |||
conn, err := target.Open(&scanner.config.BaseFlags) | |||
func (scanner *Scanner) GetDefaultDialerGroup() *zgrab2.DialerGroup { |
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.
I think this should be more about getting default options from the module not getting a DailerGroup. Semantically, it doesn't make sense to ask a scanner for a Dialer.
Description and Motivation
Some users of ZGrab modules, especially those who are doing scanning of L7 hosts as part of a larger scanning pipeline, desire having more control over the connections ZGrab establishes/uses in order to scan.
This PR intends to modify the interface between protocol modules and the ZGrab framework in order to give users the ability to have full control over ZGrab's connections. This could include:
In sum, we want to give the user the ability to take full control of establishing a connection to a scanned host. We also want all existing functionality of ZGrab as a CLI tool to remain unaffected.
Protocol Differences in needs for a Connection
First, let's delineate between 2 classes of protocol.
Transport-Agnostic
The majority of protocols are transport-agnostic and can run on any L4 connection or a TLS-wrapped connection. There may be standard norms (HTTPS on TCP port 443, NTP on port 123 over UDP, etc) but the protocol will work over any if both sides agree.
Non-Transport-Agnostic
Some L7 protocols have certain demands of the underlying transport. For example, HTTPS needs to be able to follow re-directs to HTTP sites and vice-versa. The HTTP module will usually require both a L4 connection and a TLS-wrapped connection to be able to follow both of these types of redirects.
There are other protocols as well, some (SMTP for ex.) want to establish an L4 connection, send a
STARTTLS
packet, and then proceed with a TLS handshake. We could not just hand this module a pre-existing, post-handshake TLS connection and expect the protocol to work.Dialer Groups
In order to accomplish this in a clean abstraction, we've settled on the idea of a
DialerGroup
that is taken as input in every call toScan()
. Modules will provide a "default" dialer group setting the dialers to be as they'd commonly expect. Transport-agnostic modules will set theTransportAgnosticDialer
to their default L4/TLS settings, minding any flags the user sets.For example,
NTP
would set the dialer to be a UDP dialer connecting to port 123, by default.From
module.go
:Protocols like HTTP will instead use the
L4Dialer
andTLSWrapper
to specify the two types of connections they require.Users that require full control over connections can set these dialers to whichever they wish and the
Scan()
function will utilize them as specified.The new
Scan()
function looks as follows:How it all comes together
The overall flow will look as follows:
Init(scanFlags)
, a scan module will use the user-provided scan flags (entries like what dst port to scan on, TLS flags to control aspects of the TLS connection, etc) to configure the default dialer group the module will usually use. So in the case ofNTP
, it'll set theTransportAgnosticDialer
to a UDP dialer connecting to port 123.Framework
will callGetDefaultDialerGroup
to get a module's dialers for "default" operation.Scan(ctx context.Context, t *ScanTarget, dialer *DialerGroup)
.Scan()
to connect to the target.This let's users of the modules themselves inject their own dialers into
Scan()
in Step 5.In conclusion, this interface let's modules define a certain "default behavior" as each L7 protocol has differing norms on what connections it usually uses, while also giving developers who use these modules in larger scanning systems the ability to fully control all aspects of a connection.