Mehben
Mehben

Reputation: 49

Unable to decode AWS Session Manager websocket output in python

Hope you're doing great !

The usecase

I'm trying to PoC something on AWS, the use case is that we need to be able to check on all our infrastructure that all instance are reachable through AWS Session Manager.

In order to do that, I will use a Lambda in Python 3.7, I make my PoC locally currently. I'm able to open the websocket, send the Token Payload and get an output that contains a shell.

The problem is that the byte output contains character that the python decode function can't decode in a lot of tested character encoding, every time something block.

The output

Here is the output I have after sending the payload :

print(event)

b'\x00\x00\x00toutput_stream_data \x00\x00\x00\x01\x00\x00\x01m\x1a\x1b\x9b\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xb1\x0b?\x19\x99A\xfc\xae%\xb2b\xab\xfd\x02A\xd7C\xcd\xd8}L\xa8\xb2J\xad\x12\xe3\x94\n\xed\xb81\xfa\xb6\x11\x18\xc2\xecR\xf66&4\x18\xf6\xbdd\x00\x00\x00\x01\x00\x00\x00\x10\x1b[?1034hsh-4.2$ '

What I already tried

I researched a lot on stackoverflow, tried to decode with ascii, cp1252, cp1251, cp1250, iso8859-1, utf-16, utf-8, utf_16_be, but everytime, it doesn't decode anything or it leads to an error because a character is unknown.

I also already tried to use chardet.detect, but the returned encoding is not working and also the probability result is really low. And also tried to strip the \x00 but strip doesn't work that time.

I already know that shell output can sometimes contains coloring character and some things that make it looks like garbled, but here, I tried to pass colorama on it, tried to match some ANSI character with some regex, nothing successfully decode this bytes response.

The code

Here is the code for my PoC, feel free to use it to try, you just have to change the target instance id (your instance needs to have the latest amazon-ssm-agent running on it).

import boto3
import uuid
import json
from websocket import create_connection

# Setting the boto3 client and the target
client = boto3.client('ssm','eu-west-1')
target = 'i-012345678910'

# Starting a session, this return a WebSocket URL and a Token for the Payload
response = client.start_session(Target=target)

# Creating a session with websocket.create_connection()
ws = create_connection(response['StreamUrl'])

# Building the Payload with the Token
payload = {
    "MessageSchemaVersion": "1.0",
    "RequestId": str(uuid.uuid4()),
    "TokenValue": response['TokenValue']
    }

# Sending the Payload
ws.send(json.dumps(payload))

# Receiving, printing and measuring the received message
event = ws.recv()
print(event)
print(len(event))

# Sending pwd, that should output /usr/bin
ws.send('pwd')

# Checking the result of the received message after the pwd
event = ws.recv()
print(event)
print(len(event))

Expected output

In the final solution, I expect to be able to do something like a curl http://169.254.169.254/latest/meta-data/instance-id through the websocket, and compare the instance-id of the command output against the target, to validate that instance is reachable. But I need to be able to decode the websocket output before achieving that.

Thank you in advance for any help on this.

Enjoy the rest of your day !

Upvotes: 4

Views: 1743

Answers (1)

J.Prigent
J.Prigent

Reputation: 11

As per my reading of the amazon-ssm-agent code, the payload exchanged via the websocket connection and managed by the session-manager channels follow a specific structure called the AgentMessage.

You will have to comply with this structure to use session-manager with the remote agent through the MGS Service, which means serializing messages and deserializing responses.

The fields of the above struct are also broken down into models via additional structs.

It shouldn't be too long to re-implement that in python. Good luck!

Upvotes: 1

Related Questions