Blog
dark mode light mode Search Archivos descargables
Search

Cómo hackear toda una red EC2 durante una prueba de penetración

Hackear una red EC2

AWS (Amazon Web Services) es un servicio que ofrece un método sencillo para obtener acceso a servidores, almacenamiento, bases de datos y una amplia gama de servicios de aplicaciones a través de Internet.

AWS-EC2

Cada vez es más utilizado por pequeñas, medianas y grandes empresas para alojar aplicaciones, guardar imágenes, documentos o crear sus propias redes de una manera bastante sencilla, otorgando un gran nivel de escalabilidad para el usuario. La seguridad en las redes de AWS es crucial a la hora de desarrollar aplicaciones, ya que existen varias vulnerabilidades que podrían exponer información sensible que son esenciales para que un atacante pueda comprometer una red empresarial en la nube.

Este post no explicará en profundidad el uso de la herramienta AWS-CLI, no pretende servir de guía para la gestión de los diferentes servicios que componen AWS, sino que se encargará de detallar ciertos puntos de interés. La información adjunta (imágenes, comandos), corresponde a un caso real, que por motivos de privacidad será censurado para salvaguardar la identidad del cliente.

¿Qué necesito para empezar?

Existen diferentes formas por las que un atacante podría acceder a la infraestructura en la nube, pero todas ellas requieren obtener las credenciales del usuario IAM, que se compone de dos partes: la primera parte es la access_key que es un identificador del  usuario y la segunda parte es la secret_access_key que corresponde a la contraseña necesaria para autenticarse en  AWS.

Un atacante podría obtener las claves de sesión a través de la explotación de vulnerabilidades como SSRF (Server-Side Request Forgery), SQL Injection, Full Source Disclosure, RFI, etc. A continuación, explicaremos cómo fue posible obtener ambas claves a través de una de las vulnerabilidades mencionadas anteriormente.

Verificación rápida

Una de las muchas maneras de identificar si una aplicación está siendo alojada en AWS es hacer una resolución DNS inversa a la IP del servidor.

Resolucion-DNS

La dirección IP apunta al dominio de amazon AWS ec2-52-*-*-*.compute-1.amazonaws.com.

Durante las pruebas, se comprobó  la existencia de una vulnerabilidad de Blind SQL Injection en una de las funcionalidades de la aplicación y a través de ella, se obtuvo las claves de usuario IAM correspondientes al área de producción. Las claves estaban almacenadas en texto plano dentro de una tabla de la base de datos.

Más allá de obtener las claves

Normalmente en un Penetration Test, un auditor se conformaría con solo incluir las claves obtenidas dentro del informe, es información que puede ser demasiado valiosa para el cliente y que puede tener un efecto devastador si se explota la vulnerabilidad. Sin embargo, quisimos ir más allá y tomar control de una de las instancias EC2 donde corría la aplicación utilizando las credenciales filtradas.

Para ello, se realizaron los siguientes pasos para conseguir acceder por SSH al servidor de producción objetivo. En la siguiente imagen se puede ver un resumen de la metodología utilizada para ello.

AWS-RED-EC2

Haciendo uso de AWS-CLI

AWS-CLI es un cliente para consola escrito en python que permite al usuario interactuar con los diferentes servicios que ofrece AWS. Entre ellos, la posibilidad de operar sobre las instancias EC2, con AWS-CLI es posible crear imágenes AMI de una instancia concreta, arrancar y parar instancias, crear reglas de firewall, grupos de seguridad, entre otras cosas.

Así que lo primero para interactuar cómodamente con AWS es  instalar la herramienta.

Una vez completada la instalación, se configuran las credenciales que se obtuvieron previamente a través de la vulnerabilidad SQL Injection.

SQL-injection-EC2

Después de añadir las claves del usuario, se ejecutó el siguiente comando, para verificar que las credenciales eran válidas y no se trataba de datos que habían caducado hacía tiempo.

SQL-injection-EC2-2

Esto dio una lista de los servidores S3 que componían la empresa. En este punto, se ha tomado el control sobre toda la Red EC2 de la Empresa, y para probar los privilegios, se decidió utilizar estos accesos para acceder a la instancia EC2 de producción donde se ejecutaba el sistema principal.

Escalada de privilegios

Después de verificar que las credenciales obtenidas funcionaban correctamente, hay que enumerar los privilegios del usuario IAM. Para ello, se utilizó la herramienta nimbostratus.

Nimbostratus es una herramienta de fingerprinting y explotación en redes AWS que entre sus funcionalidades permite crear usuarios IAM, comprobar privilegios, extraer información de la instancia de metadatos, etc.

Lo primero, fue verificar cuáles eran los privilegios del usuario que estaba utilizando.

Privilegios-de-usuario-EC2

Como se ve en la imagen de salida, el usuario tenía permiso para ejecutar algunas acciones limitadas en el servicio EC2.

Después de esta acción, se  procedió a crear  un nuevo usuario con todos los privilegios, esto fue posible debido a que el usuario IAM “produccion”, tenía los permisos de iam:CreateUser.

Privilegios-de-usuario-EC2-2

Accediendo a EC2

En este punto, se había logrado crear un usuario con TODOS LOS PRIVILEGIOS en la red de AWS. Ahora, se podría autenticar y cómodamente empezar a manipular al servicio de EC2.

El siguiente paso fue identificar en qué instancia corría la aplicación, para ello tenía que listar todas las instancias que había en EC2.

Describir-instancias-EC2

Mediante el comando anterior, se pudo listar todas las instancias pertenecientes al cliente. Para identificar en qué instancia se ejecutaba la aplicación, sólo tenía que consultar el valor de la clave PublicIpAddress e identificar la que contenía la IP pública del objetivo, así de sencillo.

Una vez identificada la instancia, se obtuvo su InstanceId correspondiente. El siguiente comando devuelve la instancia de destino, haciendo un filtro sobre el InstanceId.

Instancias-EC2-Instanceld

Salida JSON del comando:

{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "VirtualizationType": "hvm",
                    "SecurityGroups": [
                        {
                            "GroupId": "sg-dee387a6",
                            "GroupName": "Client"
                        },
                        {
                            "GroupId": "sg-d05570a8",
                            "GroupName": "Frontend Web Servers SG"
                        },
                        {
                            "GroupId": "sg-4c4a6f34",
                            "GroupName": "RabbitMQ Management Access SG"
                        },
                        {
                            "GroupId": "sg-a3e7aadb",
                            "GroupName": "RDS PROD Access Group"
                        },
                        {
                            "GroupId": "sg-58cbee20",
                            "GroupName": "PROD Redis PHPSession Access SG"
                        }
                    ],
                    "Tags": [
                        {
                            "Value": "Application - PROD",
                            "Key": "Name"
                        },
                        {
                            "Value": "operacion",
                            "Key": "Grupo"
                        }
                    ],
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "BlockDeviceMappings": [
                        {
                            "Ebs": {
                                "DeleteOnTermination": true,
                                "AttachTime": "2017-09-28T20:09:44.000Z",
                                "VolumeId": "vol-03efb6d8259e693ae",
                                "Status": "attached"
                            },
                            "DeviceName": "/dev/sda1"
                        }
                    ],
                    "PrivateIpAddress": "10.0.0.57",
                    "ClientToken": "UDjHC1506629382681",
                    "Hypervisor": "xen",
                    "VpcId": "vpc-7d797f19",
                    "PublicIpAddress": "34.*.*.*",
                    "SubnetId": "subnet-cf3f8de5",
                    "PrivateDnsName": "ip-10-0-0-57.ec2.internal",
                    "ImageId": "ami-11790707",
                    "KeyName": "Frontend-PROD",
                    "StateReason": {
                        "Code": "",
                        "Message": ""
                    },
                    "AmiLaunchIndex": 0,
                    "SourceDestCheck": true,
                    "Architecture": "x86_64",
                    "PublicDnsName": "ec2-34-*-*-*.compute-1.amazonaws.com",
                    "ProductCodes": [],
                    "InstanceType": "t2.micro",
                    "Placement": {
                        "Tenancy": "default",
                        "GroupName": "",
                        "AvailabilityZone": "us-east-1b"
                    },
                    "RootDeviceType": "ebs",
                    "NetworkInterfaces": [
                        {
                            "Description": "Primary network interface",
                            "SourceDestCheck": true,
                            "Attachment": {
                                "AttachTime": "2017-09-28T20:09:43.000Z",
                                "AttachmentId": "eni-attach-3d0239c9",
                                "DeviceIndex": 0,
                                "Status": "attached",
                                "DeleteOnTermination": true
                            },
                            "OwnerId": "147200857443",
                            "Status": "in-use",
                            "Association": {
                                "PublicDnsName": "ec2-34-*-*-*.compute-1.amazonaws.com",
                                "PublicIp": "34.*.*.*",
                                "IpOwnerId": "147200857443"
                            },
                            "NetworkInterfaceId": "eni-2cc990a7",
                            "PrivateIpAddress": "10.0.0.57",
                            "MacAddress": "12:84:db:f6:96:cc",
                            "Groups": [
                                {
                                    "GroupId": "sg-dee387a6",
                                    "GroupName": "Client"
                                },
                                {
                                    "GroupId": "sg-d05570a8",
                                    "GroupName": "Frontend Web Servers SG"
                                },
                                {
                                    "GroupId": "sg-4c4a6f34",
                                    "GroupName": "RabbitMQ Management Access SG"
                                },
                                {
                                    "GroupId": "sg-a3e7aadb",
                                    "GroupName": "RDS PROD Access Group"
                                },
                                {
                                    "GroupId": "sg-58cbee20",
                                    "GroupName": "PROD Redis PHPSession Access SG"
                                }
                            ],
                            "PrivateIpAddresses": [
                                {
                                    "Association": {
                                        "PublicDnsName": "ec2-34-*-*-*.compute-1.amazonaws.com",
                                        "PublicIp": "34.*.*.*",
                                        "IpOwnerId": "147200857443"
                                    },
                                    "PrivateDnsName": "ip-10-0-0-57.ec2.internal",
                                    "Primary": true,
                                    "PrivateIpAddress": "10.0.0.57"
                                }
                            ],
                            "VpcId": "vpc-7d797f19",
                            "Ipv6Addresses": [],
                            "SubnetId": "subnet-cf3f8de5",
                            "PrivateDnsName": "ip-10-0-0-57.ec2.internal"
                        }
                    ],
                    "EbsOptimized": false,
                    "IamInstanceProfile": {
                        "Arn": "arn:aws:iam::147200857443:instance-profile/NGINX-PHPFPM-Role",
                        "Id": "AIPAIHNPLRX25Y7UN5WWW"
                    },
                    "RootDeviceName": "/dev/sda1",
                    "LaunchTime": "2017-09-28T20:09:43.000Z",
                    "InstanceId": "i-0b9c16863d2b0edef",
                    "State": {
                        "Code": 16,
                        "Name": "running"
                    },
                    "StateTransitionReason": ""
                }
            ],
            "ReservationId": "r-0d422c908382bac0b",
            "OwnerId": "147200857443"
        }
    ]
}

Hot-AMI

Hasta ahora se había identificado la instancia en la red y su correspondiente InstanceId necesario para realizar las siguientes acciones que permitirían tomar el control del servidor donde se ejecutaba la aplicación. El siguiente paso era crear una AMI de la instancia de destino.

Una imagen de máquina de Amazon (AMI) es un tipo especial de dispositivo virtual que se utiliza para crear una máquina virtual dentro de Amazon Elastic Compute Cloud (“EC2”). Sirve como unidad básica de despliegue para los servicios prestados mediante EC2.

En AWS es posible crear una AMI a partir de una instancia concreta, esto se puede hacer en caliente, es decir, sin necesidad de parar la instancia destino. Lo cual no es recomendable, pero no se podía permitir parar el ambiente de producción por unos instantes.

Crear-AMI-EC2

Output JSON del comando:

Output-Json-Comando-EC2

Recordando Agregar las Llaves Públicas

Listo. Ya se  tenía una imagen clonada de la instancia de destino, así que se podía proceder a crear una nueva instancia en la red, que sería idéntica a la original en el momento de hacer uso de la AMIcreada. Pero antes se necesitaba  añadir la clave pública al servicio EC2 para que una vez que la instancia estuviera funcionando Hackmetrix pudiera conectarse vía SSH.

Llave-publica-EC2

Ejecución de la instancia

Al crear una nueva instancia en AWS hay que especificar algunos atributos que debería haber obtenido de la instancia de destino, tales como:

Grupos de seguridad

 Los grupos de seguridad (SG) de AWS están asociados a instancias EC2 y proporcionan seguridad a nivel de protocolo y acceso a puertos. Cada grupo de seguridad, que funciona de forma muy similar a un cortafuegos, contiene un conjunto de reglas que filtran el tráfico que entra y sale de una instancia EC2.

Para que la instancia funcione sin problemas, hay que indicar los grupos de seguridad exactos, ya que las comunicaciones podrían realizarse a los servicios internos de la red necesarios para que las aplicaciones funcionaran correctamente.

Id de subred

Se indica  la misma subred en la que se ejecuta la instancia de destino.

Id-de-subred-EC2

Como se puede ver en el comando al ejecutar la instancia, específico el ImageId de la nueva AMI creada, los Security-Groups correspondientes, el SubnetId de la instancia original y el nombre de la llave pública importada. La salida del comando devuelve el InstanceId de la nueva instancia clonada.

Conexión por SSH

Para conectar por SSH se necesita saber la IP pública que se le concedió a la instancia clon, esto se descifra ejecutando el siguiente comando:

Conexion-por-SSH-EC2

Output de comando:

Output-de-comando-Conexion-por-SSH-EC2

Se puede ver el argumento –query que le permite analizar la respuesta JSON y consultar el valor de la clave PublicIpAddress.

Con la PublicIpAddress expuesta simplemente hay que conectarse  al servidor usando el comando ssh como se puede ver a continuación:

PublicIpAddress EC2

Mitigación

Siempre es recomendable evitar almacenar en texto plano, datos sensibles como contraseñas, claves, tokens, etc. Estos datos deben estar protegidos por algún tipo de encriptación como bcrypt.

Además, la API interna de AWS debe bloquearse mediante una regla de firewall para evitar que un atacante acceda a los datos almacenados en los metadatos a través de una vulnerabilidad SSRF.

Por último, es aconsejable utilizar un usuario IAM con los privilegios mínimos necesarios.

Referencias

En Hackmetrix, somos especialistas en Pruebas de penetración. Trabajamos con los mejores Hackers de la región para poner a prueba tus sistemas y poder encontrar las vulnerabilidades existentes. ¿Necesitas una prueba de penetración o pentest? Contáctanos ahora.

Hackmetrix newsletter ciberseguridad