From 245907df1f0f3fab94b6a8d97bb218fdae0cf313 Mon Sep 17 00:00:00 2001 From: Raymond Nook <59678453+developStorm@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:05:54 -0700 Subject: [PATCH 1/2] New Protocol: AMQP 0.9.1 (#426) --- go.mod | 1 + go.sum | 3 + integration_tests/amqp091/cleanup.sh | 15 ++ integration_tests/amqp091/setup.sh | 37 ++++ integration_tests/amqp091/test.sh | 60 +++++++ modules/amqp.go | 7 + modules/amqp091/scanner.go | 257 +++++++++++++++++++++++++++ output.json | 1 + zgrab2_schemas/zgrab2/__init__.py | 1 + zgrab2_schemas/zgrab2/amqp091.py | 50 ++++++ 10 files changed, 432 insertions(+) create mode 100755 integration_tests/amqp091/cleanup.sh create mode 100755 integration_tests/amqp091/setup.sh create mode 100755 integration_tests/amqp091/test.sh create mode 100644 modules/amqp.go create mode 100644 modules/amqp091/scanner.go create mode 100644 output.json create mode 100644 zgrab2_schemas/zgrab2/amqp091.py diff --git a/go.mod b/go.mod index 5c1e5265..20b8d4fe 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect + github.com/rabbitmq/amqp091-go v1.9.0 github.com/sirupsen/logrus v1.9.0 github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 github.com/zmap/zflags v1.4.0-beta.1.0.20200204220219-9d95409821b6 diff --git a/go.sum b/go.sum index 8236b487..a8fb2e2f 100644 --- a/go.sum +++ b/go.sum @@ -207,6 +207,8 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo= +github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -252,6 +254,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/integration_tests/amqp091/cleanup.sh b/integration_tests/amqp091/cleanup.sh new file mode 100755 index 00000000..a80456c1 --- /dev/null +++ b/integration_tests/amqp091/cleanup.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# Keep cleaning up even if something fails +set +e + +# Stop all MySQL containers. + +VERSIONS="3.12.14 3.13.2" + +for version in $MYSQL_VERSIONS; do + CONTAINER_NAME="zgrab_amqp091-$version" + echo "amqp091/cleanup: Stopping $CONTAINER_NAME..." + docker stop $CONTAINER_NAME + echo "amqp091/cleanup: ...stopped." +done diff --git a/integration_tests/amqp091/setup.sh b/integration_tests/amqp091/setup.sh new file mode 100755 index 00000000..ddf52e9c --- /dev/null +++ b/integration_tests/amqp091/setup.sh @@ -0,0 +1,37 @@ +#!/bin/bash -e + +VERSIONS="3.12.14 3.13.2" + +function launch() { + VERSION=$1 + CONTAINER_NAME="zgrab_amqp091-$VERSION" + if docker ps --filter "name=$CONTAINER_NAME" | grep -q $CONTAINER_NAME; then + echo "amqp091/setup: Container $CONTAINER_NAME already running -- skipping launch..." + return + fi + docker run -td --rm --name $CONTAINER_NAME rabbitmq:$VERSION +} + +function waitFor() { + VERSION=$1 + CONTAINER_NAME=zgrab_amqp091-$VERSION + echo "amqp091/setup: Waiting for $CONTAINER_NAME to become ready..." + while ! (docker logs --tail all $CONTAINER_NAME | grep -q "started TCP listener on"); do + echo -n "." + sleep 1 + done + for i in $(seq 1 5); do + echo -n "*" + sleep 1 + done + echo "...ok." +} + +echo "amqp091/setup: Launching docker containers..." +for version in $VERSIONS; do + launch $version +done + +for version in $VERSIONS; do + waitFor $version +done diff --git a/integration_tests/amqp091/test.sh b/integration_tests/amqp091/test.sh new file mode 100755 index 00000000..65cdfa2a --- /dev/null +++ b/integration_tests/amqp091/test.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +set -e + +VERSIONS="3.12.14 3.13.2" + +# Run the AMQP-specific integration tests: +# 1. Run zgrab2 on the container +# 2. Check that data.amqp091.result.server_properties.version matches $MQ_VERSION + +ZGRAB_ROOT=$(git rev-parse --show-toplevel) +ZGRAB_OUTPUT=$ZGRAB_ROOT/zgrab-output + +status=0 + +function doTest() { + MQ_VERSION=$1 + + SUFFIX="" + AUTH_ARGS="" + if [[ -n "$2" ]]; then + AUTH_ARGS=$2 + SUFFIX="-auth" + fi + CONTAINER_NAME="zgrab_amqp091-${MQ_VERSION}" + OUTPUT_FILE="$ZGRAB_OUTPUT/amqp091/${MQ_VERSION}${SUFFIX}.json" + echo "amqp091/test: Testing RabbitMQ Version ${MQ_VERSION}${SUFFIX}..." + CONTAINER_NAME=$CONTAINER_NAME $ZGRAB_ROOT/docker-runner/docker-run.sh amqp091 $AUTH_ARGS --timeout 10s >$OUTPUT_FILE + SERVER_VERSION=$(jp -u data.amqp091.result.server_properties.version <$OUTPUT_FILE) + if [[ "$SERVER_VERSION" == "$MQ_VERSION" ]]; then + echo "amqp091/test: Server version matches expected version: $SERVER_VERSION == $MQ_VERSION" + else + echo "amqp091/test: Server version mismatch: Got $SERVER_VERSION, expected $MQ_VERSION. Full output: [[" + cat $OUTPUT_FILE + echo "]]" + status=1 + fi + + if [[ -n "$AUTH_ARGS" ]]; then + AUTH_SUCCESS=$(jp -u data.amqp091.result.auth_success <$OUTPUT_FILE) + if [[ "$AUTH_SUCCESS" == "true" ]]; then + echo "amqp091/test: Auth test successful" + else + echo "amqp091/test: Auth test failed" + status=1 + fi + fi + + echo "amqp091/test: BEGIN docker+amqp091 logs from $CONTAINER_NAME [{(" + docker logs --tail all $CONTAINER_NAME + echo ")}] END docker+amqp091 logs from $CONTAINER_NAME" +} + +mkdir -p $ZGRAB_OUTPUT/amqp091 + +for version in $VERSIONS; do + doTest $version + doTest $version "--auth-user guest --auth-pass guest" +done + +exit $status diff --git a/modules/amqp.go b/modules/amqp.go new file mode 100644 index 00000000..48144f69 --- /dev/null +++ b/modules/amqp.go @@ -0,0 +1,7 @@ +package modules + +import "github.com/zmap/zgrab2/modules/amqp091" + +func init() { + amqp091.RegisterModule() +} diff --git a/modules/amqp091/scanner.go b/modules/amqp091/scanner.go new file mode 100644 index 00000000..ce436f9c --- /dev/null +++ b/modules/amqp091/scanner.go @@ -0,0 +1,257 @@ +package amqp091 + +import ( + "fmt" + + "encoding/json" + + amqpLib "github.com/rabbitmq/amqp091-go" + log "github.com/sirupsen/logrus" + "github.com/zmap/zgrab2" +) + +// Flags holds the command-line configuration for the smb scan module. +// Populated by the framework. +type Flags struct { + zgrab2.BaseFlags + + Vhost string `long:"vhost" description:"The vhost to connect to" default:"/"` + AuthUser string `long:"auth-user" description:"Username to use for authentication. Must be used with --auth-pass. No auth is attempted if not provided."` + AuthPass string `long:"auth-pass" description:"Password to use for authentication. Must be used with --auth-user. No auth is attempted if not provided."` + + UseTLS bool `long:"use-tls" description:"Use TLS to connect to the server. Note that AMQPS uses a different default port (5671) than AMQP (5672) and you will need to specify that port manually with -p."` + zgrab2.TLSFlags +} + +// Module implements the zgrab2.Module interface. +type Module struct { +} + +// Scanner implements the zgrab2.Scanner interface. +type Scanner struct { + config *Flags +} + +type connectionTune struct { + ChannelMax int `json:"channel_max"` + FrameMax int `json:"frame_max"` + Heartbeat int `json:"heartbeat"` +} + +// https://www.rabbitmq.com/amqp-0-9-1-reference#connection.start.server-properties +type knownServerProperties struct { + Product string `json:"product"` + Version string `json:"version"` + Platform string `json:"platform"` + Copyright string `json:"copyright"` + Information string `json:"information"` + UnknownProps string `json:"unknown_props"` +} + +// copy known properties, and store unknown properties in serialized json string +// if known properties are not found, set fields to empty strings +func (p *knownServerProperties) populate(props amqpLib.Table) { + if product, ok := props["product"].(string); ok { + p.Product = product + delete(props, "product") + } + if version, ok := props["version"].(string); ok { + p.Version = version + delete(props, "version") + } + if platform, ok := props["platform"].(string); ok { + p.Platform = platform + delete(props, "platform") + } + if copyright, ok := props["copyright"].(string); ok { + p.Copyright = copyright + delete(props, "copyright") + } + if information, ok := props["information"].(string); ok { + p.Information = information + delete(props, "information") + } + + if unknownProps, err := json.Marshal(props); err == nil { + p.UnknownProps = string(unknownProps) + } +} + +type Result struct { + Failure string `json:"failure"` + + VersionMajor int `json:"version_major"` + VersionMinor int `json:"version_minor"` + ServerProperties knownServerProperties `json:"server_properties"` + Locales []string `json:"locales"` + + AuthSuccess bool `json:"auth_success"` + + Tune *connectionTune `json:"tune,omitempty"` + + TLSLog *zgrab2.TLSLog `json:"tls,omitempty"` +} + +// RegisterModule registers the zgrab2 module. +func RegisterModule() { + var module Module + _, err := zgrab2.AddCommand("amqp091", "amqp091", module.Description(), 5672, &module) + if err != nil { + log.Fatal(err) + } +} + +// NewFlags returns a default Flags object. +func (module *Module) NewFlags() interface{} { + return new(Flags) +} + +// NewScanner returns a new Scanner instance. +func (module *Module) NewScanner() zgrab2.Scanner { + return new(Scanner) +} + +// Description returns an overview of this module. +func (module *Module) Description() string { + return "Probe for Advanced Message Queuing Protocol 0.9.1 servers" +} + +// Validate checks that the flags are valid. +// On success, returns nil. +// On failure, returns an error instance describing the error. +func (flags *Flags) Validate(args []string) error { + if flags.AuthUser != "" && flags.AuthPass == "" { + return fmt.Errorf("must provide --auth-pass if --auth-user is set") + } + if flags.AuthPass != "" && flags.AuthUser == "" { + return fmt.Errorf("must provide --auth-user if --auth-pass is set") + } + return nil +} + +// Help returns the module's help string. +func (flags *Flags) Help() string { + return "" +} + +// Init initializes the Scanner. +func (scanner *Scanner) Init(flags zgrab2.ScanFlags) error { + f, ok := flags.(*Flags) + if !ok { + return fmt.Errorf("failed to cast flags to AMQP flags") + } + + scanner.config = f + return nil +} + +// InitPerSender initializes the scanner for a given sender. +func (scanner *Scanner) InitPerSender(senderID int) error { + return nil +} + +// GetName returns the Scanner name defined in the Flags. +func (scanner *Scanner) GetName() string { + return scanner.config.Name +} + +// GetTrigger returns the Trigger defined in the Flags. +func (scanner *Scanner) GetTrigger() string { + return scanner.config.Trigger +} + +// Protocol returns the protocol identifier of the scan. +func (scanner *Scanner) Protocol() string { + return "amqp091" +} + +func (scanner *Scanner) Scan(target zgrab2.ScanTarget) (zgrab2.ScanStatus, interface{}, error) { + conn, err := target.Open(&scanner.config.BaseFlags) + if err != nil { + return zgrab2.TryGetScanStatus(err), nil, err + } + + // Setup result and connection cleanup + result := &Result{ + AuthSuccess: false, + } + var tlsConn *zgrab2.TLSConnection + defer func() { + conn.Close() + + if tlsConn != nil { + result.TLSLog = tlsConn.GetLog() + } + }() + + // If we're using TLS, wrap the connection + if scanner.config.UseTLS { + tlsConn, err = scanner.config.TLSFlags.GetTLSConnection(conn) + if err != nil { + return zgrab2.TryGetScanStatus(err), nil, err + } + + if err := tlsConn.Handshake(); err != nil { + return zgrab2.TryGetScanStatus(err), nil, err + } + + conn = tlsConn + } + + // Prepare AMQP connection config + config := amqpLib.Config{ + Vhost: scanner.config.Vhost, + ChannelMax: 0, + FrameSize: 0, + Heartbeat: 0, + } + + // If we have auth credentials, set up PLAIN SASL + if scanner.config.AuthUser != "" && scanner.config.AuthPass != "" { + config.SASL = []amqpLib.Authentication{ + &amqpLib.PlainAuth{ + Username: scanner.config.AuthUser, + Password: scanner.config.AuthPass, + }, + } + } + + // Open the AMQP connection + amqpConn, err := amqpLib.Open(conn, config) + if err != nil { + result.Failure = err.Error() + } + defer amqpConn.Close() + + // If there's an error and we haven't even received START frame from the server, consider it a failure + if err != nil && len(amqpConn.Locales) == 0 { + status := zgrab2.TryGetScanStatus(err) + if status == zgrab2.SCAN_UNKNOWN_ERROR { + // Consider this a protocol error if it's not any of the known network errors + status = zgrab2.SCAN_PROTOCOL_ERROR + } + + return status, nil, err + } + // If amqpConn.Locales has sth, we are (almost) sure that we are talking to an AMQP 091 server, + // therefore the scan is considered successful from this point on. + + // Following is basic server information that can be gathered without authentication + result.VersionMajor = amqpConn.Major + result.VersionMinor = amqpConn.Minor + result.Locales = amqpConn.Locales + result.ServerProperties.populate(amqpConn.Properties) + + // Heuristic to see if we're authenticated. + // These values are expected to be non-zero if and only if a tune is received and we're authenticated. + if err != amqpLib.ErrSASL && err != amqpLib.ErrCredentials && amqpConn.Config.ChannelMax > 0 { + result.AuthSuccess = true + result.Tune = &connectionTune{ + ChannelMax: amqpConn.Config.ChannelMax, + FrameMax: amqpConn.Config.FrameSize, + Heartbeat: int(amqpConn.Config.Heartbeat.Seconds()), + } + } + + return zgrab2.SCAN_SUCCESS, result, nil +} diff --git a/output.json b/output.json new file mode 100644 index 00000000..a2108239 --- /dev/null +++ b/output.json @@ -0,0 +1 @@ +{"ip":"165.227.114.176","data":{"amqp091":{"status":"success","protocol":"amqp091","result":{"failure":"Exception (403) Reason: \"SASL could not negotiate a shared mechanism\"","version_major":0,"version_minor":9,"server_properties":{"product":"RabbitMQ","version":"3.8.16","platform":"Erlang/OTP 24.0.2","copyright":"Copyright (c) 2007-2021 VMware, Inc. or its affiliates.","information":"Licensed under the MPL 2.0. Website: https://rabbitmq.com","unknown_props":"{\"capabilities\":{\"authentication_failure_close\":true,\"basic.nack\":true,\"connection.blocked\":true,\"consumer_cancel_notify\":true,\"consumer_priorities\":true,\"direct_reply_to\":true,\"exchange_exchange_bindings\":true,\"per_consumer_qos\":true,\"publisher_confirms\":true},\"cluster_name\":\"speedy-red-elephant\"}"},"locales":["en_US"],"auth_success":false,"tls":{"handshake_log":{"server_hello":{"version":{"name":"TLSv1.2","value":771},"random":"ZkReGV9XxyHJdhvR5YvbXWoxZaqOD+F7RE9XTkdSRAE=","session_id":"ienBC9iUZ0TDvYsQK4E3wAhhGPds9QyKfK2+8ZHH10E=","cipher_suite":{"hex":"0xC02F","name":"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","value":49199},"compression_method":0,"ocsp_stapling":false,"ticket":false,"secure_renegotiation":true,"heartbeat":false,"extended_master_secret":false},"server_certificates":{"certificate":{"raw":"MIIFDzCCA/egAwIBAgISBAameeroCAfXEX+P6HjPx4o3MA0GCSqGSIb3DQEBCwUAMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJSMzAeFw0yNDA0MTkwOTA0MTNaFw0yNDA3MTgwOTA0MTJaMB8xHTAbBgNVBAMMFCoucm1xMi5jbG91ZGFtcXAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvzm4SlktbWfAFiUh5x1gHz0ZwocaIrcWlsRNk5iYP33NvQmFNAwv5kGq//BDU62IIEaRvKlXOMvn+1e62TSwQ65RUYpZRlHAOJ64+64adfiGUrIvif2i0VaK5kQrbsPzlm50GNKU3AJtD30bQZnAsrguudGWp8XrHz7smc/+oSiP2TfU0pWyZh94mtx18xMRRBGRCkSY3GiMWHO0zRUVpH0Rdh0U40SdMfqUCOaIo8hEM6q1qmECvm4hAtlqKpW3bvDKFQytb/jqgWomuqQ4TyLL/4In7Ecac01bxrMpUglM18mSNdXfRdrzWMKRb7i8sTsRX9MxhmHJNErDpT5nEwIDAQABo4ICMDCCAiwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTM/XXvsow84DPre+rCCefZyorEODAfBgNVHSMEGDAWgBQULrMXt1hWy65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3JnLzA4BgNVHREEMTAvghcqLmluLnJtcTIuY2xvdWRhbXFwLmNvbYIUKi5ybXEyLmNsb3VkYW1xcC5jb20wEwYDVR0gBAwwCjAIBgZngQwBAgEwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdwBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAY710E/6AAAEAwBIMEYCIQCU6Hlu2rXR9kA1JVGA/tT6h9cs10zJ5jKmpQkDd/NakQIhAK3MKAvRLe+C1qmS9E/BJV1wcsV2VDhXSFzKTQx7VpafAHYAGZgQcQnw1lIuMIDSnj9ku4NuKMz5D1KO7t/OSj8WtMoAAAGO9dBQdgAABAMARzBFAiEAvjIwxkWSNlmj3V5vz5RC9gNeryKRVMSANdcRu4bml7ACIDqzkLl38EdQKxqY1sNLEo9GCpoKoQwxJ/PUo1avmj2lMA0GCSqGSIb3DQEBCwUAA4IBAQB/WnVLyFClipmQTP/5cnkwx5vPK2ijc745zNX16CCdoOEnUKOsQkOKhv/7v4/Hl61BIj/sDb+jlxlbN07Uzbsd54fha/KPcwSnVEgOwuPVA4ruYPRhfPrU4zSCeMp0i0LdbsFMVNRaXIfsQvWGRhlEmmL3i8FTDUV4cWQRvK6U80sCwxyWhkKckvT2qOnjjL2iL16zEJkhIfQ68rFr0lUrpb7Jh6hWonUHQxA4j6/jM0Ath+haBudjH4HqcR/gsAXK5sw7n9vVcFPv74dO0xqJN7q6Erouzht4tfvZxfkVItVzo30SQ7FzGBYCwUT839mhPElCRVTbdp6gvJw6K8sk","parsed":{"version":3,"serial_number":"350712122808254062432312023692293498702391","signature_algorithm":{"name":"SHA256-RSA","oid":"1.2.840.113549.1.1.11"},"issuer":{"common_name":["R3"],"country":["US"],"organization":["Let's Encrypt"]},"issuer_dn":"C=US, O=Let's Encrypt, CN=R3","validity":{"start":"2024-04-19T09:04:13Z","end":"2024-07-18T09:04:12Z","length":7775999},"subject":{"common_name":["*.rmq2.cloudamqp.com"]},"subject_dn":"CN=*.rmq2.cloudamqp.com","subject_key_info":{"key_algorithm":{"name":"RSA"},"rsa_public_key":{"exponent":65537,"modulus":"vzm4SlktbWfAFiUh5x1gHz0ZwocaIrcWlsRNk5iYP33NvQmFNAwv5kGq//BDU62IIEaRvKlXOMvn+1e62TSwQ65RUYpZRlHAOJ64+64adfiGUrIvif2i0VaK5kQrbsPzlm50GNKU3AJtD30bQZnAsrguudGWp8XrHz7smc/+oSiP2TfU0pWyZh94mtx18xMRRBGRCkSY3GiMWHO0zRUVpH0Rdh0U40SdMfqUCOaIo8hEM6q1qmECvm4hAtlqKpW3bvDKFQytb/jqgWomuqQ4TyLL/4In7Ecac01bxrMpUglM18mSNdXfRdrzWMKRb7i8sTsRX9MxhmHJNErDpT5nEw==","length":2048},"fingerprint_sha256":"760c92c9f2b79f1eb9ae2dcf33a08699de785fd394ba9177ed3cb5f962a81ce9"},"extensions":{"key_usage":{"digital_signature":true,"key_encipherment":true,"value":5},"basic_constraints":{"is_ca":false},"subject_alt_name":{"dns_names":["*.in.rmq2.cloudamqp.com","*.rmq2.cloudamqp.com"]},"authority_key_id":"142eb317b75856cbae500940e61faf9d8b14c2c6","subject_key_id":"ccfd75efb28c3ce033eb7beac209e7d9ca8ac438","extended_key_usage":{"server_auth":true,"client_auth":true},"certificate_policies":[{"id":"2.23.140.1.2.1"}],"authority_info_access":{"ocsp_urls":["http://r3.o.lencr.org"],"issuer_urls":["http://r3.i.lencr.org/"]},"signed_certificate_timestamps":[{"version":0,"log_id":"SLDja9qmRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHM=","timestamp":1713521053,"signature":"BAMASDBGAiEAlOh5btq10fZANSVRgP7U+ofXLNdMyeYypqUJA3fzWpECIQCtzCgL0S3vgtapkvRPwSVdcHLFdlQ4V0hcyk0Me1aWnw=="},{"version":0,"log_id":"GZgQcQnw1lIuMIDSnj9ku4NuKMz5D1KO7t/OSj8WtMo=","timestamp":1713521053,"signature":"BAMARzBFAiEAvjIwxkWSNlmj3V5vz5RC9gNeryKRVMSANdcRu4bml7ACIDqzkLl38EdQKxqY1sNLEo9GCpoKoQwxJ/PUo1avmj2l"}]},"signature":{"signature_algorithm":{"name":"SHA256-RSA","oid":"1.2.840.113549.1.1.11"},"value":"f1p1S8hQpYqZkEz/+XJ5MMebzytoo3O+OczV9eggnaDhJ1CjrEJDiob/+7+Px5etQSI/7A2/o5cZWzdO1M27HeeH4Wvyj3MEp1RIDsLj1QOK7mD0YXz61OM0gnjKdItC3W7BTFTUWlyH7EL1hkYZRJpi94vBUw1FeHFkEbyulPNLAsMcloZCnJL09qjp44y9oi9esxCZISH0OvKxa9JVK6W+yYeoVqJ1B0MQOI+v4zNALYfoWgbnYx+B6nEf4LAFyubMO5/b1XBT7++HTtMaiTe6uhK6Ls4beLX72cX5FSLVc6N9EkOxcxgWAsFE/N/ZoTxJQkVU23aeoLycOivLJA==","valid":false,"self_signed":false},"fingerprint_md5":"50d77a385bb3556dd99074550ea0f664","fingerprint_sha1":"8e85228d704ac0972817d43f5f0f22264e2e7654","fingerprint_sha256":"eda0b0b8a9c28fbbeac1781eb1a8fa49df8480befefa1654cfcebcd7cf3d0891","tbs_noct_fingerprint":"da8a7597d6f3e3ad6a584804f7146a9e38cbd4189035612946b0b2bafe2ce192","spki_subject_fingerprint":"9a3ae45305db9efc51adaddf15ed499f9ef338706c9f9c3d84be359c1ede3305","tbs_fingerprint":"766514440cf4512aeaf14e153dd4acf143f1cf5fa5a7f36a9c02e6c7ba9a85fb","validation_level":"DV","names":["*.in.rmq2.cloudamqp.com","*.rmq2.cloudamqp.com"],"redacted":false}},"chain":[{"raw":"MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAwWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cPR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdxsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8ZutmNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxgZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6WPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wlikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQzCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BImlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1OyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90IdshCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6ZvMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqXnLRbwHOoq7hHwg==","parsed":{"version":3,"serial_number":"192961496339968674994309121183282847578","signature_algorithm":{"name":"SHA256-RSA","oid":"1.2.840.113549.1.1.11"},"issuer":{"common_name":["ISRG Root X1"],"country":["US"],"organization":["Internet Security Research Group"]},"issuer_dn":"C=US, O=Internet Security Research Group, CN=ISRG Root X1","validity":{"start":"2020-09-04T00:00:00Z","end":"2025-09-15T16:00:00Z","length":158774400},"subject":{"common_name":["R3"],"country":["US"],"organization":["Let's Encrypt"]},"subject_dn":"C=US, O=Let's Encrypt, CN=R3","subject_key_info":{"key_algorithm":{"name":"RSA"},"rsa_public_key":{"exponent":65537,"modulus":"uwIVKMz2oJTTDxLsjVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKpTm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnBU840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1RoYvbFQ==","length":2048},"fingerprint_sha256":"8d02536c887482bc34ff54e41d2ba659bf85b341a0a20afadb5813dcfbcf286d"},"extensions":{"key_usage":{"digital_signature":true,"certificate_sign":true,"crl_sign":true,"value":97},"basic_constraints":{"is_ca":true,"max_path_len":0},"crl_distribution_points":["http://x1.c.lencr.org/"],"authority_key_id":"79b459e67bb6e5e40173800888c81a58f6e99b6e","subject_key_id":"142eb317b75856cbae500940e61faf9d8b14c2c6","extended_key_usage":{"server_auth":true,"client_auth":true},"certificate_policies":[{"id":"2.23.140.1.2.1"},{"id":"1.3.6.1.4.1.44947.1.1.1"}],"authority_info_access":{"issuer_urls":["http://x1.i.lencr.org/"]}},"signature":{"signature_algorithm":{"name":"SHA256-RSA","oid":"1.2.840.113549.1.1.11"},"value":"hcpORz6j94VEhbzVZ3iymGOtdU0elj0zZXJULYGg6sPt+CC/X8y3cAC3bjv2XpTe5CCfpu+LsgPnorUWPJHOtO05Aud8JYpH5mVuP0b02fDOlCvuVM4SvIwnS7jBmC+ir81xkUoIt8i4I3sELQj5CFc+g9kEMwpHIXgJgifDKsibuc5c8mTIwL55wE+ObUQMXpK7LveLEOHoHUQp21kg7WO5IfgSJpSTV6AdZQTBCiKuEA1Dl6EYH37g4IY3tVqxvTC/h24rKv8hThsFw/UYl/BerMOluGrwLrw7M7nuS97M/OSvhAuGP8BVQzb2aOE2F2qOmdH/pUCnNLfA0GM5NTl1bvK6dsiTAumpS2wXzgwC2b2B+5+3aNQGZbOCPXdT+I55A60KMQd1KkPYVZdyxCkO98RdTsiuRoQw1/KFXxihebvnXnCLB+GGk8O5j9xhcSUqr9/tJVBSaIuS3OXWtePafdCHbIQhMa6C9fu5q8iJFz3hTOU4Dva9K72WgRTr1ds9IKd+WdPi+Fj5W7hIzf5cTxYp/h5VI6/IEbCN6nyTkBcv/ayiCUdGP/DpsLf/KE1oMtZnXh5po5O49Z2LLwvSUkOmbzJXZU0ygd84U4Vdfl1mKeq43eSVtc21VhJCzcROxiU4RFBt7M4AVRj+6Ulk1E7Kl5y0W8BzqKu4R8I=","valid":false,"self_signed":false},"fingerprint_md5":"e829e65d7c4307d6fbc13c179e037a36","fingerprint_sha1":"a053375bfe84e8b748782c7cee15827a6af5a405","fingerprint_sha256":"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd","tbs_noct_fingerprint":"444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce","spki_subject_fingerprint":"390bc358202771a65e7be7a87924d7f2a079de04feb5ffd4163fae4fbf9b11e9","tbs_fingerprint":"444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce","validation_level":"DV","redacted":false}}],"validation":{"browser_trusted":false,"browser_error":"x509: failed to load system roots and no roots provided"}},"server_key_exchange":{"ecdh_params":{"curve_id":{"name":"secp256r1","id":23},"server_public":{"x":{"value":"nfV5Z/BX7NG6WAK+7CohY1MI1m76yGrhm3/omzRkRJc=","length":256},"y":{"value":"thOt8w1Yaw5zhmo9+NS8PgjHdlMMPn8Zl1aLvwC7z50=","length":256}}},"digest":"zsHfGj/e8lFwyqqn61neIIhm25oyABuTofdOq4bdi8s=","signature":{"raw":"E+2Fz4oduylrlhqaLHqImJ5IuJ3/RQwyENA9q+o6U9VQsfXvbRw/4ndY5zfyypoFjzOoGRc0Dhx8nz8T4zqui0SPgChSTzCStt1KIfvaVIHWntVa5uWODCjgorji9b4XCrh4hszutMzeV8NXlMMIerTiluTEAiYlsACgArPG0YFoyBLb6ohDTKGeaEq296DxRCaJI1jNfRwbY9z+EBmlfaekjPucPcjnzlEAhMsPlrzEzHPEg8XkGBPGYcadHSbl/9CqOMGws7acR1JTyJAtyKVaJkauZorzsGSN5ZW2lEF/2eqTBal0431dNygx4nuoz1CpqGfAamQbqnLAbTPDZQ==","type":"rsa","valid":true,"signature_and_hash_type":{"signature_algorithm":"rsa","hash_algorithm":"sha256"},"tls_version":{"name":"TLSv1.2","value":771}}},"client_key_exchange":{"ecdh_params":{"curve_id":{"name":"secp256r1","id":23},"client_public":{"x":{"value":"FphxrWdXsuFxMSAu4nK1QkL5gmakbxp3ZFoVgoDKiyk=","length":256},"y":{"value":"n4YXrWbOELzor2eB9sddXjeRmzF8t1++mYnI9yWIe0k=","length":256}},"client_private":{"value":"aD2Kcjp9xdUNcx+j5N7NXxlvxBKFj1vAVc3pnXt7B04=","length":32}}},"client_finished":{"verify_data":"ZwBhDZRd2iJW/Dmf"},"server_finished":{"verify_data":"CIXmEd1/E8gMxmNi"},"key_material":{"master_secret":{"value":"+ZA70wONtgCIJMTd+oATK8EkbqXZLeEV0kv0iGMKmmM6R9BgQlFoYlr6LDTKdG0w","length":48},"pre_master_secret":{"value":"sxkQa0ePkbyP4un9hzAF+jJuLP4XExZq3QC5HjeIQek=","length":32}}}}},"timestamp":"2024-05-15T00:02:49-07:00"}}} diff --git a/zgrab2_schemas/zgrab2/__init__.py b/zgrab2_schemas/zgrab2/__init__.py index 5d510400..5ca9ed17 100644 --- a/zgrab2_schemas/zgrab2/__init__.py +++ b/zgrab2_schemas/zgrab2/__init__.py @@ -21,3 +21,4 @@ from . import telnet from . import ipp from . import banner +from . import amqp091 diff --git a/zgrab2_schemas/zgrab2/amqp091.py b/zgrab2_schemas/zgrab2/amqp091.py new file mode 100644 index 00000000..842e301b --- /dev/null +++ b/zgrab2_schemas/zgrab2/amqp091.py @@ -0,0 +1,50 @@ +# zschema sub-schema for zgrab2's AMQP091 module +# Registers zgrab2-amqp091 globally, and amqp091 with the main zgrab2 schema. +from zschema.leaves import * +from zschema.compounds import * +import zschema.registry + +from . import zgrab2 + +# Schema for connectionTune struct +connection_tune = SubRecord( + { + "channel_max": Unsigned32BitInteger(), + "frame_max": Unsigned32BitInteger(), + "heartbeat": Unsigned32BitInteger(), + } +) + +# Schema for knownServerProperties struct +known_server_properties = SubRecord( + { + "product": String(), + "version": String(), + "platform": String(), + "copyright": String(), + "information": String(), + "unknown_props": String(), + } +) + +# Schema for Result struct +result_schema = SubRecord( + { + "result": SubRecord( + { + "failure": String(), + "version_major": Unsigned32BitInteger(), + "version_minor": Unsigned32BitInteger(), + "server_properties": known_server_properties, + "locales": ListOf(String()), + "auth_success": Boolean(), + "tune": connection_tune, + "tls": zgrab2.tls_log, + } + ) + }, + extends=zgrab2.base_scan_response, +) + +zschema.registry.register_schema("zgrab2-amqp091", result_schema) +zgrab2.register_scan_response_type("amqp091", result_schema) From 74377cf4ea903618fe7830abc6e0352eef3d6a8e Mon Sep 17 00:00:00 2001 From: phillip-stephens Date: Wed, 5 Jun 2024 17:02:24 -0700 Subject: [PATCH 2/2] fixed typo in cleanup script --- integration_tests/amqp091/cleanup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration_tests/amqp091/cleanup.sh b/integration_tests/amqp091/cleanup.sh index a80456c1..4b1ae12b 100755 --- a/integration_tests/amqp091/cleanup.sh +++ b/integration_tests/amqp091/cleanup.sh @@ -3,11 +3,11 @@ # Keep cleaning up even if something fails set +e -# Stop all MySQL containers. +# Stop all AMQP containers. VERSIONS="3.12.14 3.13.2" -for version in $MYSQL_VERSIONS; do +for version in $VERSIONS; do CONTAINER_NAME="zgrab_amqp091-$version" echo "amqp091/cleanup: Stopping $CONTAINER_NAME..." docker stop $CONTAINER_NAME