Update the enum_ssm module to use the correct session type with the
appropriate platform. Also set the session information to the same
string which also removes the eye sore that is the shell banner.
Create an AwsSsmCommandShellBind session type to provide intercept
points for shell command interactions and a wrapper class which is
used to register the new session.
Update Msf::Handler::BindAwsSsm with its own #create_session method
utilizing the new session type to provide direct control of session
initialization.
Restore standard handler attributes and thread nomenclature in an
attempt to resolve the repeating session creation when #to_handler
is called on the payloads.
Testing:
Tested in local framework, unfortunately the recurring session
init problem appears to persist. Requesting testing on an upstream
Framework by saner folks.
Update SSM handler code to standardize datastore option names per
@zeroSteiner.
Update payload modules to reflect the OS targets against which they
are to execute.
Bail out of console resize operation if ::IO.console doesn't exist
Enforce REGION datastore option and remove the multi-region enum
code by Aaron - users can write resource scripts if they need
automation.
Expand SSM enumeration module docs to explain full functionality.
Enable the LIMIT configuration option to restricte results per
region.
Implement FILTER_EC2_ID configuration option to permit targeting
of a specific instance for session initiation.
Testing:
Finds limtied sets of systems and initiates sessions
Finds desired system ID and initiates session
The SSM session socket times out without data being sent at the
upper (SSM) WS layer. Implement keep-alive in a separate thread
which simply writes nothing into the channel at irregular intervals
to simulate user activity.
Testing:
Sessions established with this code running have not timed-out
in over 15m despite being completely unused
Enable session acquisition from AWS SSM enumeration module simiar
to how the telnet login scanner acquires sessions on the sockets
exposed.
Testing
Tested execution - finds systems, gets shells, autopwn-capable
Coopt Aaron Soto's EC2 enum module & replace the guts with an SSM
query for not-terminated EC2 instances with SSM capability. This
will proide users with the instance IDs needed to test their SSM
shells and can be expanded to report information or even act as a
"brute-force" module which automatically starts SSM sessions.
Testing:
None - might eat your monitor lizard
Implement terminal resizing to WebSocket shell
Reorganize code to ease later extension
Implement peerinfo in channel context from AWS EC2 SSM information
gathered during session validation
Implement echo-filtering for session inputs (hacky, but works)
Testing:
Verified console resizing, color/reset/etc
Verified peerinfo and interaction
Verified common session operations
Notes:
SSM WebSocket sessions time out pretty quickly, implementing
dedicated SSM session types which support suspend/resume to match
backgrounding/foregrounding operations in the console should help
to resolve this. Alternatively, a keep-alive using empty frames
may be implemented in the SsmChannel itself on a separate thread.
Alter WebSocket::Interface::Channel to accept a mask_write flag to
set the Channel behavior for outgoing data (since the on_data_write
handler can only deal with the buffer provided, not how the wsframe
containing it is written to the "wire"). Set the flag to false for
SSM's WebSocket operations.
Extract Rex::Proto::Http::WebSocket::AmazonSsm from the handler to
permit reuse by other framework elements.
Implement SSM-specific UUID handling.
Create sane SsmFrame constructor to permit convenient operations.
Implement Http::WebSocket::AmazonSsm::Inteface::SsmChannel from
Http::WebSocket::Inferface::Channel with message-type handling and
output processing. Acknowledge incoming messages, process incoming
acknowledgements, increment sequence IDs appropriately, and handle
basic logging.
This new session type removes the 2500 char output restriction and
stateless peer cwd.
Testing:
Execution of handler now provides stateful interactive shells
Next steps:
More testing, preferably by other people with upstream framework.
Peerinfo and presentation updates for the session channel
Misc cleanup
Future work:
Implement new SSM session type with support for multi-console,
port-forwarding/socket routing, and custom SSM documents.
Implement FSM handlers for session suspension and resumption in
Http::WebSocket::AmazonSsm::Interface::SsmChannel
Create BinData structure to handle the proprietary format of AWS'
SSM WebSocket protocol. Implement relevant inter-field dependencies
and a virtual payload_valid field to handle the SHA256 digest check
for the current state of r the payload_data field.
Implement user-accessible SSM document definition to permit use of
custom-defined command and session documents (stubbing for session
types such as port-forwarding) which may be of use when dealing
with restrictive IAM.
Restructure handler in preparation for moving the WebSocket code
into Rex::Proto for use by other consumers such as custom payloads
and session types like fully interactive (vs REPL) modalities, or
some form of "cloud-native" MeterSSM.
Testing:
Verified acquisition of SSM WS frame and relevant field ops
Next Steps:
Create WS loop to abstract shell communications
Wrap in Rex*Abstraction bowties for the session handler
Test -> ? -> Profit
Using the implementation in https://github.com/humanmade/ssm, use
the onconnect websocket authenticator as a JSON string written as
a wstext Frame into the established WebSocket. This keeps the sock
open with AWS after returning it from the method, but subsequent
operations will require definition and encoding/decoding of SSM's
proprietary data structures.
Testing:
The initialized WebSocket is kept open and returns wsframes when
requested.
Next steps:
Port the various data structures from the JavaScript library
Implement encoding & decoding for their wire-level formats
Implement state management and data flow handling logic for
the WS SSM protocol.
Port WebSocket initiation routine from Exploit::Remote::HttpClient.
Currently inert since it appears to require a handshake procedure
along with its own type of data frame.
Implement graceful fail-down for session establishment which tries
to initiate a WebSocket session for proper functionality, failing
down to the script-execution style session abstraction if the WS
session does not marshal properly. Use this exception handling to
deal with the WIP WS session state.
Testing:
Gets the same kind of command-abstracted session as before
Interface-extended socket returns garbage from naive #write and
nothing from put_string or put_binary - not going to get anything
out of this thing until we establish the handshake procedure.
Next steps:
Figure out data frame structures for handshake and console IO
Implement handshake on-init, validate state
Implement IO abstraction for the resulting Channel for handoff
to #handle_connection
Amazon Web Services provides conveniently privileged backdoors in
the form of their SSM agents which do not require connectivity with
the target instance, merely valid credentials to AWS' API. Due to
this indirect "connection" paradigm, this mechanism can be used to
control otherwise "air-gapped" targets.
This approach abstracts asynchronous request/response parsing for
SSM requests into an IO channel with which the AWS SSM client is
then wrapped to emulate the expected Stream. The mechanism is rather
raw and could use better error handling, retries on laggy output,
and a threadsafe cursor implementation. It may be possible to start
an actually interactive session using the #start_session method in
the AWS client library, but so far testing has not yielded positive
results.
There is a significant limitation with these sessions not present
in normal stream-wise abstractions: a response limit of 2500 chars.
This limitation can be overcome by utilizing an S3 bucket to store
command output; however, due to the nature of access we seek to
obtain, it would not only add to the logged event loads but retain
the results of our TTPs in a "buffer" accessible to other people.
This functionality can be added down the line in the form of S3
config options in the handler to be passed into the SSM client for
command execution and acquisition of output.
Testing:
Gets sessions, provides command IO, leaves a bunch of log entries
in CloudTrail (something to keep in mind for opsec considerations).
Next steps:
Reorganize our WebSocket code a bit to provide connection and WS
state management inside Rex::Proto::Http::Client which can then be
exposed to the Handler without having to mix-in other namespaces
from Exploit.
Use the #start_session SSM Client method to extract the WS URL
for the relevant channel, and utilize that as the underpinning for
our session comms.